-
Notifications
You must be signed in to change notification settings - Fork 2
/
rr.nim
29 lines (27 loc) · 1.26 KB
/
rr.nim
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
when not declared(stderr): import std/syncio
include cligen/unsafeAddr
import std/[strformat, posix], cligen, cligen/[dents, posixUt, statx]
proc rr*(roots: seq[string], xdev=false, eof0=false): int =
## Like rm -rf but a bit faster. Does nothing if no ``roots`` specified.
if roots.len == 0: return
var dfds: seq[cint]
for root in roots:
forPath(root, 0, false, false, xdev, eof0, stderr,
depth, path, nmAt, ino, dt, lst, dfd, dst, did):
if dt != DT_DIR:
if unlinkat(dfd, path[nmAt..^1].cstring, 0) != 0:
stderr.log &"rr({path}): {strerror(errno)}\n"
elif dfds.len > 0 and dfds[^1] == dfd: discard
else: dfds.add dfd
do: discard # Pre-recurse
do: # Post-recurse (dt == DT_DIR guaranteed)
if unlinkat(dfds.pop, path[nmAt..^1].cstring, AT_REMOVEDIR) != 0:
stderr.log &"rr({path}): {strerror(errno)}\n"
# Future dir-unlinks are doomed to fail ENOTEMPTY except if ENOENT here
# IF racing other unlinker(s). quit here forfeits any such races.
quit(1)
do: recFailDefault("rr", path) # Cannot recurse
return 0
when isMainModule:
include cligen/mergeCfgEnv
dispatch(rr, help = { "xdev" : "block recursion across device boundaries" })