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);}
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);
}