]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cp.c
usbd: intoruce /env/usbbusy
[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(dirb->length/2 > buflen){
131                 char nam[32];
132
133                 snprint(nam, sizeof nam, "/fd/%dstream", fdf);
134                 fds = open(nam, OREAD);
135                 if(fds >= 0){
136                         close(fdf);
137                         fdf = fds;
138                 }
139                 snprint(nam, sizeof nam, "/fd/%dstream", fdt);
140                 fds = open(nam, OWRITE);
141         }
142
143         if(copy1(fdf, fds < 0 ? fdt : fds, from, to)==0){
144                 if(fds >= 0 && write(fds, "", 0) < 0){
145                         fprint(2, "cp: error writing %s: %r\n", to);
146                         failed = 1;
147                         goto out;
148                 }
149                 if(xflag || gflag || uflag){
150                         nulldir(&dirt);
151                         if(xflag){
152                                 dirt.mtime = dirb->mtime;
153                                 dirt.mode = dirb->mode;
154                         }
155                         if(uflag)
156                                 dirt.uid = dirb->uid;
157                         if(gflag)
158                                 dirt.gid = dirb->gid;
159                         if(dirfwstat(fdt, &dirt) < 0)
160                                 fprint(2, "cp: warning: can't wstat %s: %r\n", to);
161                 }
162         }
163 out:
164         if(fdf >= 0)
165                 close(fdf);
166         if(fdt >= 0)
167                 close(fdt);
168         if(fds >= 0)
169                 close(fds);
170         free(dirb);
171         free(name);
172 }
173
174 int
175 copy1(int fdf, int fdt, char *from, char *to)
176 {
177         char *buf;
178         long n, n1, rcount;
179         int rv;
180         char err[ERRMAX];
181
182         buf = malloc(buflen);
183         if(buf == nil){
184                 fprint(2, "cp: out of memory\n");
185                 return -1;
186         }
187
188         /* clear any residual error */
189         err[0] = '\0';
190         errstr(err, ERRMAX);
191         rv = 0;
192         for(rcount=0;; rcount++) {
193                 n = read(fdf, buf, buflen);
194                 if(n <= 0)
195                         break;
196                 n1 = write(fdt, buf, n);
197                 if(n1 != n) {
198                         fprint(2, "cp: error writing %s: %r\n", to);
199                         failed = 1;
200                         rv = -1;
201                         break;
202                 }
203         }
204         if(n < 0) {
205                 fprint(2, "cp: error reading %s: %r\n", from);
206                 failed = 1;
207                 rv = -1;
208         }
209         free(buf);
210         return rv;
211 }