]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/upas/fs/rename.c
merge
[plan9front.git] / sys / src / cmd / upas / fs / rename.c
1 #include "common.h"
2 #include "dat.h"
3
4 #define deprint(...)    /* eprint(__VA_ARGS__) */
5
6 static int
7 delivery(char *s)
8 {
9         if(strncmp(s, "/mail/fs/", 9) == 0)
10         if((s = strrchr(s, '/')) && strcmp(s + 1, "mbox") == 0)
11                 return 1;
12         return 0;
13 }
14
15 static int
16 isdir(char *s)
17 {
18         int isdir;
19         Dir *d;
20
21         d = dirstat(s);
22         isdir = d && d->mode & DMDIR;
23         free(d);
24         return isdir;
25 }
26
27 static int
28 docreate(char *file, int perm)
29 {
30         int fd;
31         Dir ndir;
32         Dir *d;
33
34         fd = create(file, OREAD, perm);
35         if(fd < 0)
36                 return -1;
37         d = dirfstat(fd);
38         if(d == nil)
39                 return -1;
40         nulldir(&ndir);
41         ndir.mode = perm;
42         ndir.gid = d->uid;
43         dirfwstat(fd, &ndir);
44         close(fd);
45         return 0;
46 }
47
48 static int
49 rollup(char *s)
50 {
51         char *p;
52         int mode;
53
54         if(access(s, 0) == 0)
55                 return -1;
56
57         /*
58          * if we can deliver to this mbox, it needs
59          * to be read/execable all the way down
60          */
61         mode = 0711;
62         if(delivery(s))
63                 mode = 0755;
64
65         for(p = s; p; p++) {
66                 if(*p == '/')
67                         continue;
68                 p = strchr(p, '/');
69                 if(p == 0)
70                         break;
71                 *p = 0;
72                 if(access(s, 0) != 0)
73                 if(docreate(s, DMDIR|mode) < 0)
74                         return -1;
75                 *p = '/';
76         }
77         return 0;
78 }
79
80 static int
81 copyfile(char *a, char *b, int flags)
82 {
83         char *s;
84         int fd, fd1, mode, i, m, n, r;
85         Dir *d;
86
87         mode = 0600;
88         if(delivery(b))
89                 mode = 0622;
90         fd = open(a, OREAD);
91         fd1 = create(b, OWRITE|OEXCL, DMEXCL|mode);
92         if(fd == -1 || fd1 == -1){
93                 close(fd);
94                 close(fd1);
95                 return -1;
96         }
97         s = malloc(64*1024);
98         i = m = 0;
99         while((n = read(fd, s, sizeof s)) > 0)
100                 for(i = 0; i != n; i += m)
101                         if((m = write(fd1, s + i, n - i)) == -1)
102                                 goto lose;
103 lose:
104         free(s);
105         close(fd);
106         close(fd1);
107         if(i != m || n != 0)
108                 return -1;
109
110         if((flags & Rtrunc) == 0)
111                 return vremove(a);
112
113         fd = open(a, ORDWR);
114         if(fd == -1)
115                 return -1;
116         r = -1;
117         if(d = dirfstat(fd)){
118                 d->length = 0;
119                 r = dirfwstat(fd, d);
120                 free(d);
121         }
122         return r;
123 }
124
125 static int
126 copydir(char *a, char *b, int flags)
127 {
128         char *p, buf[Pathlen], ns[Pathlen], owd[Pathlen];
129         int fd, fd1, len, i, n, r;
130         Dir *d;
131
132         fd = open(a, OREAD);
133         fd1 = create(b, OWRITE|OEXCL, DMEXCL|0777);
134         close(fd1);
135         if(fd == -1 || fd1 == -1){
136                 close(fd);
137                 return -1;
138         }
139
140         /* fixup mode */
141         if(delivery(b))
142         if(d = dirfstat(fd)){
143                 d->mode |= 0777;
144                 dirfwstat(fd, d);
145                 free(d);
146         }
147
148         getwd(owd, sizeof owd);
149         if(chdir(a) == -1)
150                 return -1;
151
152         p = seprint(buf, buf + sizeof buf, "%s/", b);
153         len = buf + sizeof buf - p;
154         n = dirreadall(fd, &d);
155         r = 0;
156         for(i = 0; i < n; i++){
157                 snprint(p, len, "%s", d[i].name);
158                 if(d->mode & DMDIR){
159                         snprint(ns, sizeof ns, "%s/%s", a, d[i].name);
160                         r |= copydir(ns, buf, 0);
161                         chdir(a);
162                 }else
163                         r |= copyfile(d[i].name, buf, 0);
164                 if(r)
165                         break;
166         }
167         free(d);
168
169         if((flags & Rtrunc) == 0)
170                 r |= vremove(a);
171
172         chdir(owd);
173         return r;
174 }
175
176 int
177 rename(char *a, char *b, int flags)
178 {
179         char *e0, *e1;
180         int fd, r;
181         Dir *d;
182
183         e0 = strrchr(a, '/');
184         e1 = strrchr(b, '/');
185         if(!e0 || !e1 || !e1[1])
186                 return -1;
187
188         if(e0 - a == e1 - b)
189         if(strncmp(a, b, e0 - a) == 0)
190         if(!delivery(a) || isdir(a)){
191                 fd = open(a, OREAD);
192                 if(!(d = dirfstat(fd))){
193                         close(fd);
194                         return -1;
195                 }
196                 d->name = e1 + 1;
197                 r = dirfwstat(fd, d);
198                 deprint("rename %s %s -> %d\n", a, b, r);
199                 if(r != -1 && flags & Rtrunc)
200                         close(create(a, OWRITE, d->mode));
201                 free(d);
202                 close(fd);
203                 return r;
204         }
205
206         if(rollup(b) == -1)
207                 return -1;
208         if(isdir(a))
209                 return copydir(a, b, flags);
210         return copyfile(a, b, flags);
211 }
212
213 char*
214 localrename(Mailbox *mb, char *p2, int flags)
215 {
216         char *path, *msg;
217         int r;
218         static char err[2*Pathlen];
219
220         path = mb->path;
221         msg = "rename";
222         if(flags & Rtrunc)
223                 msg = "move";
224         deprint("localrename %s: %s %s\n", msg, path, p2);
225
226         r = rename(path, p2, flags);
227         if(r == -1){
228                 snprint(err, sizeof err, "%s: can't %s\n", path, msg);
229                 deprint("localrename %s\n", err);
230                 return err;
231         }
232         close(r);
233         return 0;
234 }