4 int copy1(int fdf, int fdt, char *from, char *to);
5 void hardremove(char *);
6 int mv(char *from, char *todir, char *toelem);
7 int mv1(char *from, Dir *dirb, char *todir, char *toelem);
8 int samefile(char *, char *);
9 void split(char *, char **, char **);
12 main(int argc, char *argv[])
19 fprint(2, "usage: mv fromfile tofile\n");
20 fprint(2, " mv fromfile ... todir\n");
25 if(argv[1][0] == '-' && argv[1][1] == 'f' && argv[1][2] == 0) {
26 for(i=2; i<argc; i++) {
32 /* prepass to canonicalise names before splitting, etc. */
33 for(i=1; i < argc; i++)
36 if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){
39 && (dirfrom = dirstat(argv[1])) != nil
40 && (dirfrom->mode & DMDIR))
41 split(argv[argc-1], &todir, &toelem); /* mv dir1 dir2 */
42 else{ /* mv file... dir */
44 toelem = nil; /* toelem will be fromelem */
48 split(argv[argc-1], &todir, &toelem); /* mv file1 file2 */
50 if(argc>3 && toelem != nil){
51 fprint(2, "mv: %s not a directory\n", argv[argc-1]);
56 for(i=1; i < argc-1; i++)
57 if(mv(argv[i], todir, toelem) < 0)
65 mv(char *from, char *todir, char *toelem)
72 fprint(2, "mv: can't stat %s: %r\n", from);
75 stat = mv1(from, dirb, todir, toelem);
81 mv1(char *from, Dir *dirb, char *todir, char *toelem)
83 int fdf, fdt, i, j, stat;
84 char toname[4096], fromname[4096];
85 char *fromdir, *fromelem;
88 strncpy(fromname, from, sizeof fromname);
89 split(from, &fromdir, &fromelem);
94 fprint(2, "mv: null last name element moving %s\n", fromname);
98 if(i + j + 2 > sizeof toname){
99 fprint(2, "mv: path too big (max %d): %s/%s\n",
100 sizeof toname, todir, toelem);
103 memmove(toname, todir, j);
105 memmove(toname+j+1, toelem, i);
108 if(samefile(fromdir, todir)){
109 if(samefile(fromname, toname)){
110 fprint(2, "mv: %s and %s are the same\n",
115 /* remove target if present */
116 dirt = dirstat(toname);
125 if(dirwstat(fromname, &null) >= 0)
127 if(dirb->mode & DMDIR){
128 fprint(2, "mv: can't rename directory %s: %r\n",
134 * Renaming won't work --- must copy
136 if(dirb->mode & DMDIR){
137 fprint(2, "mv: %s is a directory, not copied to %s\n",
141 fdf = open(fromname, OREAD);
143 fprint(2, "mv: can't open %s: %r\n", fromname);
147 dirt = dirstat(toname);
148 if(dirt != nil && (dirt->mode & DMAPPEND))
149 hardremove(toname); /* because create() won't truncate file */
152 fdt = create(toname, OWRITE, dirb->mode);
154 fprint(2, "mv: can't create %s: %r\n", toname);
158 stat = copy1(fdf, fdt, fromname, toname);
163 null.mtime = dirb->mtime;
164 null.mode = dirb->mode;
165 dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */
166 if(remove(fromname) < 0){
167 fprint(2, "mv: can't remove %s: %r\n", fromname);
176 copy1(int fdf, int fdt, char *from, char *to)
181 while ((n = read(fdf, buf, sizeof buf)) > 0) {
182 n1 = write(fdt, buf, n);
184 fprint(2, "mv: error writing %s: %r\n", to);
189 fprint(2, "mv: error reading %s: %r\n", from);
196 split(char *name, char **pdir, char **pelem)
200 s = utfrrune(name, '/');
205 }else if(strcmp(name, "..") == 0){
215 samefile(char *a, char *b)
220 if(strcmp(a, b) == 0)
224 ret = (da != nil && db != nil &&
225 da->qid.type==db->qid.type &&
226 da->qid.path==db->qid.path &&
227 da->qid.vers==db->qid.vers &&
239 fprint(2, "mv: can't remove %s: %r\n", a);
242 while(remove(a) != -1)