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