ref: ec35f468e0eba87c9f09cbbe5fa8af2591e6f914
dir: /appl/cmd/mv.b/
implement Mv; include "sys.m"; sys: Sys; stderr: ref Sys->FD; include "draw.m"; draw: Draw; include "string.m"; str: String; Mv: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; stderr = sys->fildes(2); str = load String String->PATH; if(str == nil) { sys->fprint(stderr, "mv: can't load %s: %r\n", String->PATH); raise "fail:load"; } dirto, dirfrom: Sys->Dir; todir, toelem: string; if(len argv<3) { sys->fprint(stderr, "usage: mv fromfile tofile\n"); sys->fprint(stderr, " mv fromfile ... todir\n"); raise "fail:usage"; } argv = tl argv; arr := array[len argv] of string; for (i:=0; argv!=nil;i++){ arr[i]= hd argv; argv = tl argv; } (i,dirto)=sys->stat(arr[len arr-1]); if(i >= 0 && (dirto.mode&Sys->DMDIR)){ (i,dirfrom)=sys->stat(arr[0]); if(len arr == 2 && i >= 0 && (dirfrom.mode&Sys->DMDIR)) (todir,toelem)=split(arr[len arr-1]); else{ todir = arr[len arr -1]; toelem = ""; # toelem will be fromelem } }else (todir,toelem)=split(arr[len arr-1]); if(len arr > 2 && toelem != nil) { sys->fprint(stderr, "mv: %s not a directory\n", arr[len arr-1]); raise "fail:error"; } failed := 0; for(i=0; i < len arr-1; i++) if (mv(arr[i], todir, toelem) < 0) failed++; if(failed) raise "fail:error"; } mv(from,todir,toelem : string): int { (i,dirb):=sys->stat(from); if(i != 0) { sys->fprint(stderr, "mv: can't stat %s: %r\n", from); return -1; } (fromdir,fromelem):=split(from); fromname:= fromdir+fromelem; if(toelem == nil){ if (todir[len todir-1]!='/') todir[len todir]='/'; toelem = fromelem; } i = len toelem; if(i==0){ sys->fprint(stderr, "mv: null last name element moving %s\n", fromname); return -1; } toname:=todir+toelem; if(samefile(fromdir, todir)){ if(samefile(fromname, toname)){ sys->fprint(stderr, "mv: %s and %s are the same\n", fromname, toname); return -1; } (j,dirt):=sys->stat(toname); if( (j == 0) && (dirb.mode&Sys->DMDIR) ){ sys->fprint(stderr, "mv: can't rename a directory to an existing name\n"); return -1; } if(j == 0) hardremove(toname); dirt = sys->nulldir; dirt.name=toelem; if(sys->wstat(fromname,dirt) >= 0) return 0; if(dirb.mode&Sys->DMDIR){ sys->fprint(stderr, "mv: can't rename directory %s: %r\n", fromname); return -1; } } # Renaming won't work --- have to copy if(dirb.mode&Sys->DMDIR){ sys->fprint(stderr, "mv: %s is a directory, not copied to %s\n", fromname, toname); return -1; } fdf := sys->open(fromname, Sys->OREAD); if(fdf==nil){ sys->fprint(stderr, "mv: can't open %s: %r\n", fromname); return -1; } fdt := sys->create(toname, Sys->OWRITE, dirb.mode); if(fdt == nil){ sys->fprint(stderr, "mv: can't create %s: %r\n", toname); return -1; } if ((stat := copy1(fdf, fdt, fromname, toname)) != -1) fdf = nil; # temp bug: sometimes can't remove open file if (sys->remove(fromname) < 0) { sys->fprint(stderr, "mv: can't remove %s: %r\n", fromname); return -1; } return stat; } copy1(fdf, fdt : ref Sys->FD,from, fto : string): int { n : int; buf:=array[Sys->ATOMICIO] of byte; for(;;) { n = sys->read(fdf, buf, len buf); if (n<=0) break; n1 := sys->write(fdt, buf, n); if(n1 != n) { sys->fprint(stderr, "mv: error writing %s: %r\n", fto); return -1; } } if(n < 0) { sys->fprint(stderr, "mv: error reading %s: %r\n", from); return -1; } return 0; } split(name : string): (string,string) { (d,t) := str->splitr(name, "/"); if(d!=nil) return(d,t); else if(name=="..") return("../","."); else return("./",name); } samefile(a,b : string): int { if(a==b) return 1; (i,da):=sys->stat(a); (j,db):=sys->stat(b); if(i < 0 || j < 0) return 0; i= (da.qid.path==db.qid.path && da.qid.vers==db.qid.vers && da.dev==db.dev && da.dtype==db.dtype); return i; } hardremove(a: string) { if(sys->remove(a) == -1){ sys->fprint(stderr, "mv: can't remove %s: %r\n", a); raise "fail:mv"; } do; while(sys->remove(a) != -1); }