]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cp.c
[9front] walk: properly format permissions
[plan9front.git] / sys / src / cmd / cp.c
1 #include <u.h>
2 #include <libc.h>
3
4 #define DEFB    (8*1024)
5
6 int     buflen;
7 int     failed;
8 int     gflag;
9 int     uflag;
10 int     xflag;
11 void    copy(char *from, char *to, int todir);
12 int     copy1(int fdf, int fdt, char *from, char *to);
13
14 void
15 main(int argc, char *argv[])
16 {
17         Dir *dirb;
18         int todir, i;
19
20         ARGBEGIN {
21         case 'g':
22                 gflag++;
23                 break;
24         case 'u':
25                 uflag++;
26                 gflag++;
27                 break;
28         case 'x':
29                 xflag++;
30                 break;
31         default:
32                 goto usage;
33         } ARGEND
34
35         todir=0;
36         if(argc < 2)
37                 goto usage;
38         dirb = dirstat(argv[argc-1]);
39         if(dirb!=nil && (dirb->mode&DMDIR))
40                 todir=1;
41         if(argc>2 && !todir){
42                 fprint(2, "cp: %s not a directory\n", argv[argc-1]);
43                 exits("bad usage");
44         }
45         for(i=0; i<argc-1; i++)
46                 copy(argv[i], argv[argc-1], todir);
47         if(failed)
48                 exits("errors");
49         exits(0);
50
51 usage:
52         fprint(2, "usage:\tcp [-gux] fromfile tofile\n");
53         fprint(2, "\tcp [-x] fromfile ... todir\n");
54         exits("usage");
55 }
56
57 int
58 samefile(Dir *a, char *an, char *bn)
59 {
60         Dir *b;
61         int ret;
62
63         ret = 0;
64         b=dirstat(bn);
65         if(b != nil)
66         if(b->qid.type==a->qid.type)
67         if(b->qid.path==a->qid.path)
68         if(b->qid.vers==a->qid.vers)
69         if(b->dev==a->dev)
70         if(b->type==a->type){
71                 fprint(2, "cp: %s and %s are the same file\n", an, bn);
72                 ret = 1;
73         }
74         free(b);
75         return ret;
76 }
77
78 void
79 copy(char *from, char *to, int todir)
80 {
81         Dir *dirb, dirt;
82         char *name;
83         int fdf, fdt, fds, mode;
84
85         name = nil;
86         if(todir){
87                 char *s, *elem;
88                 elem=s=from;
89                 while(*s++)
90                         if(s[-1]=='/')
91                                 elem=s;
92                 name = smprint("%s/%s", to, elem);
93                 to = name;
94         }
95
96         fdf = fdt = fds = -1;
97         if((dirb=dirstat(from))==nil){
98                 fprint(2,"cp: can't stat %s: %r\n", from);
99                 failed = 1;
100                 goto out;
101         }
102         mode = dirb->mode;
103         if(mode&DMDIR){
104                 fprint(2, "cp: %s is a directory\n", from);
105                 failed = 1;
106                 goto out;
107         }
108         if(samefile(dirb, from, to)){
109                 failed = 1;
110                 goto out;
111         }
112         mode &= 0777;
113         fdf=open(from, OREAD);
114         if(fdf<0){
115                 fprint(2, "cp: can't open %s: %r\n", from);
116                 failed = 1;
117                 goto out;
118         }
119         fdt=create(to, OWRITE, mode);
120         if(fdt<0){
121                 fprint(2, "cp: can't create %s: %r\n", to);
122                 failed = 1;
123                 goto out;
124         }
125
126         buflen = iounit(fdf);
127         if(buflen <= 0)
128                 buflen = DEFB;
129
130         if(copy1(fdf, fds < 0 ? fdt : fds, from, to)==0){
131                 if(fds >= 0 && write(fds, "", 0) < 0){
132                         fprint(2, "cp: error writing %s: %r\n", to);
133                         failed = 1;
134                         goto out;
135                 }
136                 if(xflag || gflag || uflag){
137                         nulldir(&dirt);
138                         if(xflag){
139                                 dirt.mtime = dirb->mtime;
140                                 dirt.mode = dirb->mode;
141                         }
142                         if(uflag)
143                                 dirt.uid = dirb->uid;
144                         if(gflag)
145                                 dirt.gid = dirb->gid;
146                         if(dirfwstat(fdt, &dirt) < 0)
147                                 fprint(2, "cp: warning: can't wstat %s: %r\n", to);
148                 }
149         }
150 out:
151         if(fdf >= 0)
152                 close(fdf);
153         if(fdt >= 0)
154                 close(fdt);
155         if(fds >= 0)
156                 close(fds);
157         free(dirb);
158         free(name);
159 }
160
161 int
162 copy1(int fdf, int fdt, char *from, char *to)
163 {
164         char *buf;
165         long n, n1, rcount;
166         int rv;
167         char err[ERRMAX];
168
169         buf = malloc(buflen);
170         if(buf == nil){
171                 fprint(2, "cp: out of memory\n");
172                 return -1;
173         }
174
175         /* clear any residual error */
176         err[0] = '\0';
177         errstr(err, ERRMAX);
178         rv = 0;
179         for(rcount=0;; rcount++) {
180                 n = read(fdf, buf, buflen);
181                 if(n <= 0)
182                         break;
183                 n1 = write(fdt, buf, n);
184                 if(n1 != n) {
185                         fprint(2, "cp: error writing %s: %r\n", to);
186                         failed = 1;
187                         rv = -1;
188                         break;
189                 }
190         }
191         if(n < 0) {
192                 fprint(2, "cp: error reading %s: %r\n", from);
193                 failed = 1;
194                 rv = -1;
195         }
196         free(buf);
197         return rv;
198 }