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