summaryrefslogtreecommitdiff
path: root/lib/fileutil/loopcheck+posixy.myr
blob: 0a311bfdf685af914ada04714d0f43ff40d63b4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std
use sys

/* plan 9 can't have directory loops, by construction, so this is nops */
pkg fileutil =
	type loopcheck = std.htab((int64, int64), void)#

	const mkloopcheck	: (cwd : byte[:] -> loopcheck)
	const freeloopcheck	: (l : loopcheck -> void)
	const looped	: (l : loopcheck, p : byte[:] -> bool)
;;

const mkloopcheck = {cwd
	var ht : std.htab((int64, int64), void)#
	var l

	ht = std.mkht()
	l = (ht : loopcheck)
	looped(l, cwd)
	-> l
}

const freeloopcheck = {l
	std.htfree((l : std.htab((int64, int64), void)#))
}

const looped = {l, p
	var ht, has

	ht = (l : std.htab((int64, int64), void)#)
	match fid(p)
	| `std.Err e:
		-> false
	| `std.Ok id:
		has = std.hthas(ht, id)
		std.htput(ht, id, void)
		-> has
	;;
}

const fid = {p
	var sb

	if sys.stat(p, &sb) != 0
		-> `std.Err void
	else
		-> `std.Ok ((sb.dev : int64), (sb.ino : int64))
	;;
}

impl std.hashable (int64, int64) =
	hash = {fid
		var dev, ino

		(dev, ino) = fid
		-> std.hash(dev) ^ std.hash(ino)
	}
;;

impl std.comparable (int64, int64) =
	cmp = {a, b
		var adev, aino
		var bdev, bino

		(adev, aino) = a
		(bdev, bino) = b
		-> adev == bdev && aino == bino
	}
;;