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