1implement Mv; 2 3include "sys.m"; 4 sys: Sys; 5 stderr: ref Sys->FD; 6 7include "draw.m"; 8 draw: Draw; 9 10include "string.m"; 11 str: String; 12 13 14Mv: module 15{ 16 init: fn(ctxt: ref Draw->Context, argv: list of string); 17}; 18 19init(nil: ref Draw->Context, argv: list of string) 20{ 21 sys = load Sys Sys->PATH; 22 stderr = sys->fildes(2); 23 str = load String String->PATH; 24 if(str == nil) { 25 sys->fprint(stderr, "mv: can't load %s: %r\n", String->PATH); 26 raise "fail:load"; 27 } 28 29 dirto, dirfrom: Sys->Dir; 30 todir, toelem: string; 31 if(len argv<3) { 32 sys->fprint(stderr, "usage: mv fromfile tofile\n"); 33 sys->fprint(stderr, " mv fromfile ... todir\n"); 34 raise "fail:usage"; 35 } 36 argv = tl argv; 37 arr := array[len argv] of string; 38 for (i:=0; argv!=nil;i++){ 39 arr[i]= hd argv; 40 argv = tl argv; 41 } 42 (i,dirto)=sys->stat(arr[len arr-1]); 43 if(i >= 0 && (dirto.mode&Sys->DMDIR)){ 44 (i,dirfrom)=sys->stat(arr[0]); 45 if(len arr == 2 && i >= 0 && (dirfrom.mode&Sys->DMDIR)) 46 (todir,toelem)=split(arr[len arr-1]); 47 else{ 48 todir = arr[len arr -1]; 49 toelem = ""; # toelem will be fromelem 50 } 51 }else 52 (todir,toelem)=split(arr[len arr-1]); 53 if(len arr > 2 && toelem != nil) { 54 sys->fprint(stderr, "mv: %s not a directory\n", arr[len arr-1]); 55 raise "fail:error"; 56 } 57 failed := 0; 58 for(i=0; i < len arr-1; i++) 59 if (mv(arr[i], todir, toelem) < 0) 60 failed++; 61 if(failed) 62 raise "fail:error"; 63} 64 65mv(from,todir,toelem : string): int 66{ 67 (i,dirb):=sys->stat(from); 68 if(i != 0) { 69 sys->fprint(stderr, "mv: can't stat %s: %r\n", from); 70 return -1; 71 } 72 (fromdir,fromelem):=split(from); 73 fromname:= fromdir+fromelem; 74 if(toelem == nil){ 75 if (todir[len todir-1]!='/') 76 todir[len todir]='/'; 77 toelem = fromelem; 78 } 79 i = len toelem; 80 if(i==0){ 81 sys->fprint(stderr, "mv: null last name element moving %s\n", fromname); 82 return -1; 83 } 84 toname:=todir+toelem; 85 if(samefile(fromdir, todir)){ 86 if(samefile(fromname, toname)){ 87 sys->fprint(stderr, "mv: %s and %s are the same\n", fromname, toname); 88 return -1; 89 } 90 (j,dirt):=sys->stat(toname); 91 if( (j == 0) && (dirb.mode&Sys->DMDIR) ){ 92 sys->fprint(stderr, "mv: can't rename a directory to an existing name\n"); 93 return -1; 94 } 95 if(j == 0) 96 hardremove(toname); 97 dirt = sys->nulldir; 98 dirt.name=toelem; 99 if(sys->wstat(fromname,dirt) >= 0) 100 return 0; 101 if(dirb.mode&Sys->DMDIR){ 102 sys->fprint(stderr, "mv: can't rename directory %s: %r\n", fromname); 103 return -1; 104 } 105 } 106 # Renaming won't work --- have to copy 107 if(dirb.mode&Sys->DMDIR){ 108 sys->fprint(stderr, "mv: %s is a directory, not copied to %s\n", fromname, toname); 109 return -1; 110 } 111 fdf := sys->open(fromname, Sys->OREAD); 112 if(fdf==nil){ 113 sys->fprint(stderr, "mv: can't open %s: %r\n", fromname); 114 return -1; 115 } 116 fdt := sys->create(toname, Sys->OWRITE, dirb.mode); 117 if(fdt == nil){ 118 sys->fprint(stderr, "mv: can't create %s: %r\n", toname); 119 return -1; 120 } 121 if ((stat := copy1(fdf, fdt, fromname, toname)) != -1) 122 fdf = nil; # temp bug: sometimes can't remove open file 123 if (sys->remove(fromname) < 0) { 124 sys->fprint(stderr, "mv: can't remove %s: %r\n", fromname); 125 return -1; 126 } 127 return stat; 128} 129 130 131copy1(fdf, fdt : ref Sys->FD,from, fto : string): int 132{ 133 n : int; 134 buf:=array[Sys->ATOMICIO] of byte; 135 for(;;) { 136 n = sys->read(fdf, buf, len buf); 137 if (n<=0) 138 break; 139 n1 := sys->write(fdt, buf, n); 140 if(n1 != n) { 141 sys->fprint(stderr, "mv: error writing %s: %r\n", fto); 142 return -1; 143 } 144 } 145 if(n < 0) { 146 sys->fprint(stderr, "mv: error reading %s: %r\n", from); 147 return -1; 148 } 149 return 0; 150} 151 152split(name : string): (string,string) 153{ 154 (d,t) := str->splitr(name, "/"); 155 if(d!=nil) 156 return(d,t); 157 else if(name=="..") 158 return("../","."); 159 else 160 return("./",name); 161} 162 163samefile(a,b : string): int 164{ 165 if(a==b) 166 return 1; 167 (i,da):=sys->stat(a); 168 (j,db):=sys->stat(b); 169 if(i < 0 || j < 0) 170 return 0; 171 i= (da.qid.path==db.qid.path && da.qid.vers==db.qid.vers && 172 da.dev==db.dev && da.dtype==db.dtype); 173 return i; 174} 175 176hardremove(a: string) 177{ 178 if(sys->remove(a) == -1){ 179 sys->fprint(stderr, "mv: can't remove %s: %r\n", a); 180 raise "fail:mv"; 181 } 182 do; while(sys->remove(a) != -1); 183} 184