1 #include <u.h> 2 #include <libc.h> 3 4 void split(char *, char **, char **); 5 int samefile(char *, char *); 6 int mv(char *from, char *todir, char *toelem); 7 int copy1(int fdf, int fdt, char *from, char *to); 8 void hardremove(char *); 9 10 void 11 main(int argc, char *argv[]) 12 { 13 int i; 14 int failed; 15 Dir *dirto, *dirfrom; 16 char *todir, *toelem; 17 18 if(argc<3){ 19 fprint(2, "usage: mv fromfile tofile\n"); 20 fprint(2, " mv fromfile ... todir\n"); 21 exits("bad usage"); 22 } 23 if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){ 24 if(argc == 3 25 && (dirfrom = dirstat(argv[1])) !=nil 26 && (dirfrom->mode & DMDIR)) 27 split(argv[argc-1], &todir, &toelem); 28 else{ 29 todir = argv[argc-1]; 30 toelem = 0; /* toelem will be fromelem */ 31 } 32 }else 33 split(argv[argc-1], &todir, &toelem); 34 if(argc>3 && toelem != 0){ 35 fprint(2, "mv: %s not a directory\n", argv[argc-1]); 36 exits("bad usage"); 37 } 38 failed = 0; 39 for(i=1; i < argc-1; i++) 40 if(mv(argv[i], todir, toelem) < 0) 41 failed++; 42 if(failed) 43 exits("failure"); 44 exits(0); 45 } 46 47 int 48 mv(char *from, char *todir, char *toelem) 49 { 50 Dir *dirb, *dirt, null; 51 char toname[4096], fromname[4096]; 52 int fdf, fdt, i, j; 53 int stat; 54 char *fromdir, *fromelem; 55 56 dirb = dirstat(from); 57 if(dirb == nil){ 58 fprint(2, "mv: can't stat %s: %r\n", from); 59 return -1; 60 } 61 strncpy(fromname, from, sizeof fromname); 62 split(from, &fromdir, &fromelem); 63 if(toelem == 0) 64 toelem = fromelem; 65 i = strlen(toelem); 66 if(i==0){ 67 fprint(2, "mv: null last name element moving %s\n", fromname); 68 return -1; 69 } 70 j = strlen(todir); 71 if(i + j + 2 > sizeof toname){ 72 fprint(2, "mv: path too big (max %d): %s/%s\n", sizeof toname, todir, toelem); 73 return -1; 74 } 75 memmove(toname, todir, j); 76 toname[j] = '/'; 77 memmove(toname+j+1, toelem, i); 78 toname[i+j+1] = 0; 79 if(samefile(fromdir, todir)){ 80 if(samefile(fromname, toname)){ 81 fprint(2, "mv: %s and %s are the same\n", fromname, toname); 82 return -1; 83 } 84 dirt = dirstat(toname); 85 if(dirt != nil){ 86 free(dirt); 87 hardremove(toname); 88 } 89 nulldir(&null); 90 null.name = toelem; 91 if(dirwstat(fromname, &null) >= 0) 92 return 0; 93 if(dirb->mode & DMDIR){ 94 fprint(2, "mv: can't rename directory %s: %r\n", fromname); 95 return -1; 96 } 97 } 98 /* 99 * Renaming won't work --- must copy 100 */ 101 if(dirb->mode & DMDIR){ 102 fprint(2, "mv: %s is a directory, not copied to %s\n", fromname, toname); 103 return -1; 104 } 105 fdf = open(fromname, OREAD); 106 if(fdf < 0){ 107 fprint(2, "mv: can't open %s: %r\n", fromname); 108 return -1; 109 } 110 dirt = dirstat(toname); 111 if(dirt != nil && (dirt->mode & DMAPPEND)) 112 hardremove(toname); /* because create() won't truncate file */ 113 free(dirt); 114 fdt = create(toname, OWRITE, dirb->mode); 115 if(fdt < 0){ 116 fprint(2, "mv: can't create %s: %r\n", toname); 117 close(fdf); 118 return -1; 119 } 120 stat = copy1(fdf, fdt, fromname, toname); 121 close(fdf); 122 if(stat >= 0){ 123 nulldir(&null); 124 null.mtime = dirb->mtime; 125 null.mode = dirb->mode; 126 dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */ 127 if(remove(fromname) < 0){ 128 fprint(2, "mv: can't remove %s: %r\n", fromname); 129 stat = -1; 130 } 131 } 132 close(fdt); 133 return stat; 134 } 135 136 int 137 copy1(int fdf, int fdt, char *from, char *to) 138 { 139 char buf[8192]; 140 long n, n1; 141 142 for(;;){ 143 n = read(fdf, buf, sizeof buf); 144 if(n >= 0){ 145 if(n == 0) 146 break; 147 n1 = write(fdt, buf, n); 148 if(n1 != n){ 149 fprint(2, "mv: error writing %s: %r\n", to); 150 return -1; 151 } 152 } 153 } 154 if(n < 0){ 155 fprint(2, "mv: error reading %s: %r\n", from); 156 return -1; 157 } 158 return 0; 159 } 160 161 void 162 split(char *name, char **pdir, char **pelem) 163 { 164 char *s; 165 166 s = utfrrune(name, '/'); 167 if(s){ 168 *s = 0; 169 *pelem = s+1; 170 *pdir = name; 171 }else if(strcmp(name, "..") == 0){ 172 *pdir = ".."; 173 *pelem = "."; 174 }else{ 175 *pdir = "."; 176 *pelem = name; 177 } 178 } 179 180 int 181 samefile(char *a, char *b) 182 { 183 Dir *da, *db; 184 int ret; 185 186 if(strcmp(a, b) == 0) 187 return 1; 188 da = dirstat(a); 189 db = dirstat(b); 190 ret = (da !=nil ) && 191 (db != nil) && 192 (da->qid.type==db->qid.type) && 193 (da->qid.path==db->qid.path) && 194 (da->qid.vers==db->qid.vers) && 195 (da->dev==db->dev) && 196 da->type==db->type; 197 free(da); 198 free(db); 199 return ret; 200 } 201 202 void 203 hardremove(char *a) 204 { 205 if(remove(a) == -1){ 206 fprint(2, "mv: can't remove %s: %r\n", a); 207 exits("mv"); 208 } 209 do; while(remove(a) != -1); 210 } 211