diff options
Diffstat (limited to 'appl/wm/ftree/cptree.b')
| -rw-r--r-- | appl/wm/ftree/cptree.b | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/appl/wm/ftree/cptree.b b/appl/wm/ftree/cptree.b new file mode 100644 index 00000000..5af59fff --- /dev/null +++ b/appl/wm/ftree/cptree.b @@ -0,0 +1,136 @@ +implement Cptree; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "readdir.m"; + readdir: Readdir; +include "cptree.m"; + +init() +{ + sys = load Sys Sys->PATH; + readdir = load Readdir Readdir->PATH; +} + +Context: adt { + progressch: chan of string; + warningch: chan of (string, chan of int); + finishedch: chan of string; +}; + +# recursively copy file/directory f into directory d; +# the name remains the same. +copyproc(f, d: string, progressch: chan of string, + warningch: chan of (string, chan of int), + finishedch: chan of string) +{ + ctxt := ref Context(progressch, warningch, finishedch); + (fok, fstat) := sys->stat(f); + if (fok == -1) + error(ctxt, sys->sprint("cannot stat '%s': %r", f)); + (dok, dstat) := sys->stat(d); + if (dok == -1) + error(ctxt, sys->sprint("cannot stat '%s': %r", d)); + if ((dstat.mode & Sys->DMDIR) == 0) + error(ctxt, sys->sprint("'%s' is not a directory", d)); + if (fstat.qid.path == dstat.qid.path) + error(ctxt, sys->sprint("'%s' and '%s' are identical", f, d)); + + c := d + "/" + fname(f); + (cok, cstat) := sys->stat(c); + if (cok == 0) + error(ctxt, sys->sprint("'%s' already exists", c)); + rcopy(ctxt, f, ref fstat, c); + finishedch <-= nil; +} + +rcopy(ctxt: ref Context, src: string, srcstat: ref Sys->Dir, dst: string) +{ + omode := Sys->OWRITE; + perm := srcstat.mode; + if (perm & Sys->DMDIR) { + omode = Sys->OREAD; + perm |= 8r300; + } + + dstfd := sys->create(dst, omode, perm); + if (dstfd == nil) { + warning(ctxt, sys->sprint("cannot create '%s': %r", dst)); + return; + } + if (srcstat.mode & Sys->DMDIR) { + (entries, n) := readdir->init(src, Readdir->NAME | Readdir->COMPACT); + if (n == -1) + warning(ctxt, sys->sprint("cannot read dir '%s': %r", src)); + for (i := 0; i < len entries; i++) { + e := entries[i]; + rcopy(ctxt, src + "/" + e.name, e, dst + "/" + e.name); + } + if (perm != srcstat.mode) { + (ok, nil) := sys->fstat(dstfd); + if (ok != -1) { + dststat := sys->nulldir; + dststat.mode = srcstat.mode; + sys->fwstat(dstfd, dststat); + } + } + } else { + srcfd := sys->open(src, Sys->OREAD); + if (srcfd == nil) { + sys->remove(dst); + warning(ctxt, sys->sprint("cannot open '%s': %r", src)); + return; + } + ctxt.progressch <-= "copying " + src; + buf := array[Sys->ATOMICIO] of byte; + while ((n := sys->read(srcfd, buf, len buf)) > 0) { + if (sys->write(dstfd, buf, n) != n) { + sys->remove(dst); + warning(ctxt, sys->sprint("error writing '%s': %r", dst)); + return; + } + } + if (n == -1) { + sys->remove(dst); + warning(ctxt, sys->sprint("error reading '%s': %r", src)); + return; + } + } +} + +warning(ctxt: ref Context, msg: string) +{ + r := chan of int; + ctxt.warningch <-= (msg, r); + if (!<-r) + exit; +} + +error(ctxt: ref Context, msg: string) +{ + ctxt.finishedch <-= msg; + exit; +} + +fname(f: string): string +{ + f = cleanname(f); + for (i := len f - 1; i >= 0; i--) + if (f[i] == '/') + break; + return f[i+1:]; +} + +cleanname(s: string): string +{ + t := ""; + i := 0; + while (i < len s) + if ((t[len t] = s[i++]) == '/') + while (i < len s && s[i] == '/') + i++; + if (len t > 1 && t[len t - 1] == '/') + t = t[0:len t - 1]; + return t; +} |
