summaryrefslogtreecommitdiff
path: root/lib/fileutil
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fileutil')
-rw-r--r--lib/fileutil/bld.sub4
-rw-r--r--lib/fileutil/loopcheck+plan9.myr21
-rw-r--r--lib/fileutil/loopcheck+posixy.myr65
-rw-r--r--lib/fileutil/tmpdir.myr12
-rw-r--r--lib/fileutil/walk.myr55
5 files changed, 139 insertions, 18 deletions
diff --git a/lib/fileutil/bld.sub b/lib/fileutil/bld.sub
index 8971630..e54f88d 100644
--- a/lib/fileutil/bld.sub
+++ b/lib/fileutil/bld.sub
@@ -1,6 +1,10 @@
lib fileutil =
walk.myr
homedir.myr
+ tmpdir.myr
+
+ loopcheck+posixy.myr
+ loopcheck+plan9.myr
lib ../sys:sys
lib ../std:std
diff --git a/lib/fileutil/loopcheck+plan9.myr b/lib/fileutil/loopcheck+plan9.myr
new file mode 100644
index 0000000..9b5584b
--- /dev/null
+++ b/lib/fileutil/loopcheck+plan9.myr
@@ -0,0 +1,21 @@
+use std
+
+/* plan 9 can't have directory loops, by construction, so this is nops */
+pkg fileutil =
+ type loopcheck = void
+
+ const mkloopcheck : (cwd : byte[:] -> loopcheck)
+ const freeloopcheck : (l : loopcheck -> void)
+ const looped : (l : loopcheck, p : byte[:] -> bool)
+;;
+
+const mkloopcheck = {cwd
+ -> (void : loopcheck)
+}
+
+const freeloopcheck = {l
+}
+
+const looped = {l, p
+ -> false
+}
diff --git a/lib/fileutil/loopcheck+posixy.myr b/lib/fileutil/loopcheck+posixy.myr
new file mode 100644
index 0000000..784fe3f
--- /dev/null
+++ b/lib/fileutil/loopcheck+posixy.myr
@@ -0,0 +1,65 @@
+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(fidhash, fideq)
+ 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))
+ ;;
+}
+
+const fidhash = {fid
+ var dev, ino
+
+ (dev, ino) = fid
+ -> std.inthash(dev) ^ std.inthash(ino)
+}
+
+const fideq = {a, b
+ var adev, aino
+ var bdev, bino
+
+ (adev, aino) = a
+ (bdev, bino) = b
+ -> adev == bdev && aino == bino
+}
diff --git a/lib/fileutil/tmpdir.myr b/lib/fileutil/tmpdir.myr
new file mode 100644
index 0000000..786a151
--- /dev/null
+++ b/lib/fileutil/tmpdir.myr
@@ -0,0 +1,12 @@
+use std
+
+pkg fileutil =
+ const tmpdir : (-> byte[:])
+;;
+
+const tmpdir = {
+ match std.getenv("TMPDIR")
+ | `std.Some d: -> d
+ | `std.None: -> "/tmp"
+ ;;
+}
diff --git a/lib/fileutil/walk.myr b/lib/fileutil/walk.myr
index 75ed5e2..dbdfb5f 100644
--- a/lib/fileutil/walk.myr
+++ b/lib/fileutil/walk.myr
@@ -1,18 +1,33 @@
use std
+use "loopcheck"
+
pkg fileutil =
type walkiter = struct
dirstk : std.dir#[:]
curdir : byte[:][:]
- iterdir : bool
+ loopck : loopcheck
;;
impl iterable walkiter -> byte[:]
- const bywalk : (dir : std.dir# -> walkiter)
+ const bywalk : (dir : byte[:] -> walkiter)
;;
-const bywalk = {d
- -> [.dirstk = std.sldup([d][:]), .curdir = std.sldup([""][:])]
+const bywalk = {p
+ match std.diropen(p)
+ | `std.Ok d:
+ -> [
+ .dirstk = std.sldup([d][:]),
+ .curdir = std.sldup([std.sldup(p)][:]),
+ .loopck = mkloopcheck(p),
+ ]
+ | `std.Err e:
+ -> [
+ .dirstk = [][:],
+ .curdir = [][:],
+ .loopck = mkloopcheck(p),
+ ]
+ ;;
}
impl iterable walkiter -> byte[:] =
@@ -20,34 +35,38 @@ impl iterable walkiter -> byte[:] =
var cur, p
:nextfile
+ if itp.dirstk.len < 1
+ freeloopcheck(itp.loopck)
+ -> false
+ ;;
cur = itp.dirstk[itp.dirstk.len - 1]
match std.dirread(cur)
| `std.Some ".": goto nextfile
| `std.Some "..": goto nextfile
| `std.Some ent:
p = std.pathcat(itp.curdir[itp.curdir.len - 1], ent)
+ if looped(itp.loopck, p)
+ std.slfree(p)
+ goto nextfile
+ ;;
if std.fisdir(p)
match std.diropen(p)
- | `std.Ok d: std.slpush(&itp.dirstk, d)
+ | `std.Ok d:
+ std.slpush(&itp.dirstk, d)
+ std.slpush(&itp.curdir, p)
| `std.Err e: /* ? */
+ std.slfree(p)
;;
- std.slpush(&itp.curdir, p)
goto nextfile
- else
- valp# = p
;;
+ valp# = p
-> true
| `std.None:
- /* don't close the directory given to us by the user */
- if itp.dirstk.len > 1
- std.dirclose(itp.dirstk[itp.dirstk.len - 1])
- std.slfree(itp.curdir[itp.curdir.len - 1])
- std.slpop(&itp.curdir)
- std.slpop(&itp.dirstk)
- goto nextfile
- else
- -> false
- ;;
+ std.dirclose(cur)
+ std.slfree(itp.curdir[itp.curdir.len - 1])
+ std.slpop(&itp.curdir)
+ std.slpop(&itp.dirstk)
+ goto nextfile
;;
}