summaryrefslogtreecommitdiff
path: root/lib/std/dir+plan9.myr
blob: e36366235b7c6a0454263634bab0ade107971ae2 (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 sys

use "alloc"
use "die"
use "option"
use "result"
use "slcp"
use "sldup"
use "syswrap"
use "types"

pkg std =
	type dir = struct
		fd	: fd
		buf	: byte[65536]	/* a big big, but at least it will always hold a directory entry... */
		len	: int64
		off	: int64
	;;

	const diropen	: (p : byte[:] -> std.result(dir#, byte[:]))
	const dirread	: (d : dir# -> std.option(byte[:]))
	const dirclose	: (d : dir# -> void)
;;

const diropen = {p
	var fd
	var dir

	match open(p, Ordonly)
	| `Ok f:	fd = f
	| `Err e:	-> `Err "couldn't open directory"
	;;

	dir = zalloc()
	dir.fd = fd
	-> `Ok dir
}
	

const dirread = {d
	var name, base, namelen, dirlen

	/* NB: On Plan 9, read(2) will always return whole directory entries */
	if d.off >= d.len
		match read(d.fd, d.buf[:])
		| `Ok 0:
			-> `None
		| `Err e:
			-> `None
		| `Ok len:
			d.len = (len : int64)
			d.off = 0
		;;
	;;

	namelen = (d.buf[d.off + Stringsoff] : int64) | \
		((d.buf[d.off + Stringsoff + 1] : int64) << 8)
	base = d.off + Stringsoff + 2
	dirlen = (d.buf[d.off] : int64) | \
		((d.buf[d.off + 1] : int64) << 8)
	name = d.buf[base:base + namelen]
	d.off += dirlen + 2
	-> `Some std.sldup(name)
}

const dirclose = {d
	close(d.fd)
	free(d)
}