diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/fs/mergewrite.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/cmd/fs/mergewrite.b')
| -rw-r--r-- | appl/cmd/fs/mergewrite.b | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/appl/cmd/fs/mergewrite.b b/appl/cmd/fs/mergewrite.b new file mode 100644 index 00000000..3ff1b1f1 --- /dev/null +++ b/appl/cmd/fs/mergewrite.b @@ -0,0 +1,186 @@ +implement Fsmodule; +include "sys.m"; + sys: Sys; +include "draw.m"; +include "sh.m"; +include "readdir.m"; + readdir: Readdir; +include "fslib.m"; + fslib: Fslib; + Report, Value, quit, report: import fslib; + Fschan, Fsdata, Entrychan, Entry, + Cmpchan, Option, + Next, Down, Skip, Quit: import Fslib; + +types(): string +{ + return "vmsx"; # XXX bad argument ordering... +} + +init() +{ + sys = load Sys Sys->PATH; + readdir = load Readdir Readdir->PATH; + if(readdir == nil){ + sys->fprint(sys->fildes(2), "fs: mergewrite: cannot load %s: %r\n", Readdir->PATH); + raise "fail:bad module"; + } + readdir->init(nil, 0); + + fslib = load Fslib Fslib->PATH; + if(fslib == nil){ + sys->fprint(sys->fildes(2), "fs: mergewrite: cannot load %s: %r\n", Fslib->PATH); + raise "fail:bad module"; + } +} + +run(nil: ref Draw->Context, report: ref Report, + nil: list of Option, args: list of ref Value): ref Value +{ + sync := chan of int; + spawn fswriteproc(sync, (hd args).m().i, (hd tl args).s().i, (hd tl tl args).x().i, report.start("mergewrite")); + <-sync; + return ref Value.V(sync); +} + +fswriteproc(sync: chan of int, cmp: Cmpchan, root: string, c: Fschan, errorc: chan of string) +{ + sys->pctl(Sys->FORKNS, nil); + sync <-= 1; + if(<-sync == 0){ + (<-c).t1 <-= Quit; + quit(errorc); + } + + ((d, nil), reply) := <-c; + if(root != nil){ + d = ref *d; + d.name = root; + } + fswritedir(d.name, cmp, d, reply, c, errorc); + quit(errorc); +} + +fswritedir(path: string, cmp: Cmpchan, dir: ref Sys->Dir, dreply: chan of int, c: Fschan, errorc: chan of string) +{ + fd: ref Sys->FD; + if(dir.mode & Sys->DMDIR){ + fd = sys->create(dir.name, Sys->OREAD, dir.mode|8r300); + made := fd != nil; + if(fd == nil && (fd = sys->open(dir.name, Sys->OREAD)) == nil){ + dreply <-= Next; + report(errorc, sys->sprint("cannot create %q, mode %uo: %r", path, dir.mode|8r300)); + return; + } + # XXX if we haven't just made it, we should chmod the old entry u+w to enable writing. + if(sys->chdir(dir.name) == -1){ # XXX beware of names starting with '#' + dreply <-= Next; + report(errorc, sys->sprint("cannot cd to %q: %r", path)); + fd = nil; + sys->remove(dir.name); + return; + } + dreply <-= Down; + entries: array of ref Sys->Dir; + if(made == 0) + entries = readdir->readall(fd, Readdir->NAME|Readdir->COMPACT).t0; + i := 0; + eod := 0; + d0, d1: ref Sys->Dir; + reply: chan of int; + path[len path] = '/'; + for(;;){ + if(!eod && d0 == nil){ + ((d0, nil), reply) = <-c; + if(d0 == nil){ + reply <-= Next; + eod = 1; + } + } + if(d1 == nil && i < len entries) + d1 = entries[i++]; + if(d0 == nil && d1 == nil) + break; + + (wd0, wd1) := (d0, d1); + if(d0 != nil && d1 != nil && d0.name != d1.name){ + if(d0.name < d1.name) + wd1 = nil; + else + wd0 = nil; + } + r := compare(cmp, wd0, wd1); + if(wd1 != nil && (r & 2r10) == 0){ + if(wd1.mode & Sys->DMDIR) + rmdir(wd1.name); + else + remove(wd1.name); + d1 = nil; + } + if(wd0 != nil){ + if((r & 2r01) == 0) + reply <-= Next; + else + fswritedir(path + wd0.name, cmp, d0, reply, c, errorc); + d0 = nil; + } + } + sys->chdir(".."); + if((dir.mode & 8r300) != 8r300){ + ws := Sys->nulldir; + ws.mode = dir.mode; + if(sys->fwstat(fd, ws) == -1) + report(errorc, sys->sprint("cannot wstat %q: %r", path)); + } + }else{ + fd = sys->create(dir.name, Sys->OWRITE, dir.mode); + if(fd == nil){ + dreply <-= Next; + report(errorc, sys->sprint("cannot create %q, mode %uo: %r", path, dir.mode|8r300)); + return; + } + dreply <-= Down; + while((((nil, buf), reply) := <-c).t0.data != nil){ + nw := sys->write(fd, buf, len buf); + if(nw < len buf){ + if(nw == -1) + errorc <-= sys->sprint("error writing %q: %r", path); + else + errorc <-= sys->sprint("short write"); + reply <-= Skip; + break; + } + reply <-= Next; + } + reply <-= Next; + } +} + +rmdir(name: string) +{ + (d, n) := readdir->init(name, Readdir->NONE|Readdir->COMPACT); + for(i := 0; i < n; i++){ + path := name+"/"+d[i].name; + if(d[i].mode & Sys->DMDIR) + rmdir(path); + else + remove(path); + } + remove(name); +} + +remove(name: string) +{ + if(sys->remove(name) < 0) + sys->fprint(sys->fildes(2), "mergewrite: cannot remove %q: %r\n", name); +} + +compare(cmp: Cmpchan, d0, d1: ref Sys->Dir): int +{ + mask := (d0 != nil) | (d1 != nil) << 1; + if(cmp == nil) + return mask; + reply := chan of int; + cmp <-= (d0, d1, reply); + return <-reply & mask; +} |
