Commit | Line | Data |
---|---|---|
1b9a18bc | 1 | static char *sccsid = "@(#)dl.c 4.2\t%G%"; |
07e1a339 RC |
2 | |
3 | #include <stdio.h> | |
4 | #include <sys/param.h> | |
5 | #include <sys/stat.h> | |
6 | #include <sys/dir.h> | |
7 | #include <errno.h> | |
8 | #include <signal.h> | |
9 | ||
10 | #define DELIM '/' | |
11 | #define MODEBITS 07777 | |
12 | #define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR) | |
13 | #define ISLNK(st) (((st).st_mode&S_IFMT) == S_IFLNK) | |
14 | #define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG) | |
15 | #define ISDEV(st) \ | |
16 | (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) | |
17 | ||
18 | struct stat s1, s2, buf; | |
19 | extern unsigned errno; | |
20 | int errcode; | |
07e1a339 RC |
21 | char *path; |
22 | char *path2; | |
23 | char line[1024]; | |
24 | int cflag = 0; /* "copy" - same as cp */ | |
25 | int dflag = 0; /* "debug" - enable trace printf statements */ | |
26 | int fflag = 0; /* "force" option: override protection, no messages */ | |
27 | int mflag = 0; /* "move" - same as mv */ | |
28 | int cs = 0; /* flag used with cflag to prevent endless recursion */ | |
29 | int ms = 0; /* flag used with mflag to prevent endless recursion */ | |
30 | int tflag = 0; /* restore original time stamp */ | |
31 | ||
32 | main(argc, argv) /* dl.c - delete, undelete, move, copy */ | |
33 | char *argv[]; | |
34 | { | |
35 | register char *arg; | |
36 | char *s; | |
37 | int mode; | |
38 | int aflg = 0; /* "all" option: undelete all deleted files */ | |
39 | int iflg = 0; /* "interactive" option: send messages to user */ | |
40 | int rflg = 0; /* "recursive" opt., used only with n */ | |
41 | int sflg = 0; /* do not delete previous dlsave file */ | |
42 | int uflg = 0; /* undelete named files and/or directories */ | |
43 | int nflg = 0; /* do not provide back-up files */ | |
44 | ||
45 | if (isatty(0) == 0) /* if standard i/o is not a terminal, */ | |
46 | fflag++; /* turn on the f flag */ | |
47 | ||
48 | if (strcmp(*argv,"ud") == 0) | |
49 | uflg++; | |
50 | ||
51 | if (strcmp(*argv,"copy") == 0) | |
52 | cflag++; | |
53 | ||
54 | if (strcmp(*argv,"move") == 0) | |
55 | mflag++; | |
56 | ||
57 | while(argc>1 && argv[1][0]=='-') { | |
58 | arg = *++argv; | |
59 | argc--; | |
60 | ||
61 | /* | |
62 | * all arguments following a null option (- ) are | |
63 | * treated as file names, so that file names may | |
64 | * begin with a minus sign (-). | |
65 | */ | |
66 | if (*(arg+1) == '\0') break; | |
67 | ||
68 | while(*++arg != '\0') | |
69 | switch(*arg) { | |
70 | case 'a': /* "all" */ | |
71 | aflg++; | |
72 | break; | |
73 | case 'c': /* "copy" */ | |
74 | cflag++; | |
75 | break; | |
76 | case 'd': /* "debug" */ | |
77 | dflag++; | |
78 | break; | |
79 | case 'f': /* "force" */ | |
80 | fflag++; | |
81 | break; | |
82 | case 'i': /* "interactive" */ | |
83 | iflg++; | |
84 | break; | |
85 | case 'r': /* "recursive" */ | |
86 | rflg++; | |
87 | break; | |
88 | case 's': /* "save" */ | |
89 | sflg++; | |
90 | break; | |
91 | case 't': /* "time" stamp */ | |
92 | tflag++; | |
93 | break; | |
94 | case 'u': /* "undelete" */ | |
95 | uflg++; | |
96 | break; | |
97 | case 'm': /* "move" */ | |
98 | mflag++; | |
99 | break; | |
100 | case 'n': /* "not save" */ | |
101 | nflg++; | |
102 | break; | |
103 | default: | |
104 | printf("dl: unknown option %s\n", *argv); | |
105 | exit(1); | |
106 | } | |
107 | } | |
108 | if (cflag || mflag || nflg) sflg++; | |
109 | /* | |
110 | * set up home directory pathname | |
111 | */ | |
112 | setpath(); | |
113 | /* | |
114 | * process "undelete all" request | |
115 | */ | |
116 | if(aflg) { | |
117 | undelete_all(iflg); | |
118 | exit; | |
119 | } | |
120 | /* | |
121 | * remove previously saved files unless "save" option, | |
122 | * or ud or rm mode | |
123 | */ | |
124 | if(!sflg && !uflg) | |
125 | dldir(path,0); | |
126 | if(!nflg && lstat(path,&buf) != 0) { | |
127 | /* | |
128 | * set up .dlsave directory | |
129 | */ | |
130 | mode = 0777; | |
131 | if (mkdir(path,mode) != 0) { | |
132 | fprintf(stderr,"dl: cannot mkdir ~/.dlsave\n"); | |
133 | perror(s); | |
134 | exit(1); | |
135 | } | |
136 | } | |
137 | while(--argc > 0) { | |
138 | if(!strcmp(*++argv, "..")) { | |
139 | if(!fflag) | |
140 | fprintf(stderr, "dl: cannot remove `..'\n"); | |
141 | continue; | |
142 | } | |
143 | /* | |
144 | * process "undelete" request(s) | |
145 | */ | |
146 | if(uflg) { | |
147 | undelete(*argv,iflg); | |
148 | exit; | |
149 | } | |
150 | else { | |
151 | /* | |
152 | * process delete request(s) | |
153 | */ | |
154 | if (cflag) { | |
155 | copy(*argv,argv[argc-1],iflg,rflg); | |
156 | exit(errcode); | |
157 | } | |
158 | if (mflag) { | |
159 | move(*argv,argv[argc-1],iflg); | |
160 | exit(errcode); | |
161 | } | |
162 | if (nflg) | |
163 | rm(*argv, iflg, rflg); | |
164 | else | |
165 | dl(*argv, iflg); | |
166 | } | |
167 | } | |
168 | exit(errcode); | |
169 | } | |
170 | ||
171 | setpath() | |
172 | { | |
173 | char *home; | |
174 | char *suffix; | |
175 | char *getenv(); | |
176 | ||
177 | home = "HOME"; | |
178 | if ((path=getenv(home)) == NULL) { | |
179 | fprintf(stderr,"dl: getenv failed\n"); | |
180 | exit(1); | |
181 | } | |
182 | suffix = "/.dlsave"; | |
183 | strcat(path,suffix); | |
184 | return; | |
185 | } | |
186 | ||
187 | package(argu) | |
188 | char argu[]; | |
189 | { | |
190 | register int i, j, k; | |
191 | char *slash, *slashdot; | |
192 | char *place; | |
193 | char line2[512]; | |
194 | ||
195 | place = line2; | |
196 | strcpy(place,argu); | |
197 | path2 = line; | |
198 | strcpy(path2,path); | |
199 | slashdot = "/.#"; | |
200 | strcat(path2,slashdot); | |
201 | i = strlen(argu); | |
202 | slash = "/"; | |
203 | k = 0; | |
204 | for (j=0;j<i;j++) { | |
205 | if (place[j] == *slash) { | |
206 | k = j + 1; | |
207 | } | |
208 | } | |
209 | strcat(path2,argu+k); | |
210 | return; | |
211 | } | |
212 | ||
213 | undelete_all(iflg) | |
214 | { | |
215 | struct direct *dp; | |
216 | DIR *dirp; | |
217 | char *filename; | |
218 | int x; | |
219 | ||
220 | /* | |
221 | * undelete all saved files (a option) | |
222 | */ | |
223 | if((dirp = opendir(path)) == NULL) { | |
224 | if(!fflag) | |
225 | printf("uda: cannot read %s?\n", path); | |
226 | exit(1); | |
227 | } | |
228 | while((dp = readdir(dirp)) != NULL) { | |
229 | if(dp->d_ino != 0 && !dotname(dp->d_name)) { | |
230 | filename = (dp->d_name)+2; | |
231 | package(filename); | |
232 | if(iflg) { | |
233 | printf("uda: undelete %s?", filename); | |
234 | if (!yes()) | |
235 | goto no; | |
236 | } | |
237 | if(lstat(filename, &buf) == 0) { | |
238 | printf("uda: %s exists. Override?", filename); | |
239 | if(!yes()) | |
240 | goto no; | |
241 | } | |
242 | x = move(path2,filename,0); | |
243 | if(iflg) { | |
244 | if (x >= 0) | |
245 | printf("uda: %s undeleted.\n", filename); | |
246 | else | |
247 | printf("uda: unable to undelete %s\n", filename); | |
248 | } | |
249 | no: continue; | |
250 | } | |
251 | } | |
252 | closedir(dirp); | |
253 | return; | |
254 | } | |
255 | ||
256 | undelete(arg,iflg) | |
257 | char arg[]; | |
258 | { | |
259 | struct stat buf1, buf2; | |
260 | int x; | |
261 | ||
262 | /* | |
263 | * undelete a saved file (u option) | |
264 | */ | |
265 | package(arg); | |
266 | if(lstat(path2, &buf1)) { | |
267 | if (!fflag) | |
268 | printf("ud: %s nonexistent\n", path2); | |
269 | ++errcode; | |
270 | return; | |
271 | } | |
272 | if(iflg) { | |
273 | printf("ud: undelete %s?", arg); | |
274 | if(!yes()) | |
275 | return; | |
276 | } | |
277 | if(lstat(arg, &buf2) == 0) { | |
278 | printf("ud: %s exists: overwrite?", arg); | |
279 | if(!yes()) | |
280 | return; | |
281 | } | |
282 | x = move(path2,arg,0); | |
283 | if(iflg) { | |
284 | if (x >= 0) | |
285 | printf("ud: %s undeleted.\n", arg); | |
286 | else | |
287 | printf("ud: unable to undelete %s\n", arg); | |
288 | } | |
289 | return; | |
290 | } | |
291 | ||
292 | rm(arg, iflg, rflg) | |
293 | char arg[]; | |
294 | { | |
295 | if (dflag) printf("rm entered: arg=%s fflag=%d iflg=%d rflg=%d\n",arg,fflag,iflg,rflg); | |
296 | if(lstat(arg, &buf)) { | |
297 | if (!fflag) | |
298 | printf("rm: %s nonexistent\n", arg); | |
299 | ++errcode; | |
300 | return; | |
301 | } | |
302 | /* | |
303 | * unlink file named by arg | |
304 | */ | |
305 | if ((buf.st_mode&S_IFMT) == S_IFDIR || rflg) { | |
306 | if(iflg) { | |
307 | printf("rm: remove directory %s?", arg); | |
308 | if(!yes()) | |
309 | return; | |
310 | } | |
311 | dldir(arg, iflg); | |
312 | return; | |
313 | } | |
314 | if (!fflag && iflg) { | |
315 | printf("rm: remove %s?", arg); | |
316 | if (!yes()) | |
317 | return; | |
318 | } | |
319 | else if (!fflag) { | |
320 | if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, 02) < 0) { | |
321 | printf("rm: override protection %o for %s?\n",buf.st_mode&0777,arg); | |
322 | if (!yes()) | |
323 | return; | |
324 | } | |
325 | } | |
326 | if (unlink(arg) && !fflag) { | |
327 | printf ("rm: %s not removed.\n",arg); | |
328 | ++errcode; | |
329 | } | |
330 | else { | |
331 | if (!fflag && iflg) | |
332 | printf ("rm: %s removed.\n",arg); | |
333 | } | |
334 | return; | |
335 | } | |
336 | ||
337 | dl(arg, iflg) | |
338 | char arg[]; | |
339 | { | |
340 | /* | |
341 | * move the argument (file or directory) to | |
342 | * .dlsave directory in user's home directory | |
343 | */ | |
344 | if (dflag) printf("dl entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg); | |
345 | package(arg); | |
346 | move(arg,path2,iflg); | |
347 | return; | |
348 | } | |
349 | ||
350 | dldir(arg, iflg) | |
351 | char arg[]; | |
352 | { | |
353 | struct stat buf1, buf2; | |
354 | struct direct *dp; | |
355 | DIR *dirp; | |
356 | char name[BUFSIZ]; | |
357 | ||
358 | if (dflag) printf("dldir entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg); | |
359 | if(lstat(arg, &buf1)) { | |
360 | if (!fflag && iflg) | |
361 | printf("dldir: %s nonexistent\n", arg); | |
362 | ++errcode; | |
363 | return; | |
364 | } | |
365 | /* | |
366 | * if the argument is a directory, | |
367 | * recursively remove the directory's contents | |
368 | * and then the directory. | |
369 | */ | |
370 | if ((buf1.st_mode&S_IFMT) == S_IFDIR) { | |
371 | if (access(arg, 02) < 0) { | |
372 | if(!fflag) { | |
373 | printf("dldir: %s not accessable\n",arg); | |
374 | } | |
375 | errcode++; | |
376 | return; | |
377 | } | |
378 | if((dirp = opendir(arg)) == NULL) | |
379 | exit(1); | |
380 | while((dp = readdir(dirp)) != NULL) { | |
381 | if(dp->d_ino != 0 && !dotname(dp->d_name)) { | |
1b9a18bc | 382 | (void) sprintf(name, "%s/%s", arg, dp->d_name); |
07e1a339 RC |
383 | if (dflag) printf("dldir: name= %s\n",name); |
384 | if(lstat(name, &buf2)) { | |
385 | if (!fflag) | |
386 | printf("dldir: %s nonexistent\n", name); | |
387 | ++errcode; | |
388 | return; | |
389 | } | |
390 | if ((buf2.st_mode&S_IFMT) == S_IFDIR) { | |
391 | if(!fflag && iflg) { | |
392 | printf("dldir: delete directory %s?", name); | |
393 | if(!yes()) | |
394 | return; | |
395 | } | |
396 | dldir(name, iflg); | |
397 | } | |
398 | else { | |
399 | if(!fflag && iflg) { | |
400 | printf("dldir: delete file %s?", name); | |
401 | if(!yes()) | |
402 | return; | |
403 | } | |
404 | /* | |
405 | * permanently remove the file | |
406 | */ | |
407 | if (unlink(name)) { | |
408 | if (!fflag) | |
409 | printf("dldir: %s not removed\n", name); | |
410 | ++errcode; | |
411 | } | |
412 | else { | |
413 | if (!fflag && iflg) | |
414 | printf("dldir: %s removed.\n", name); | |
415 | } | |
416 | } | |
417 | } | |
418 | } | |
419 | closedir(dirp); | |
420 | if (dotname(arg)) | |
421 | return; | |
422 | if (rmdir(arg) < 0) { | |
423 | if(!fflag && iflg) { | |
424 | fprintf(stderr, "dldir: rmdir:"); | |
425 | perror(arg); | |
426 | } | |
427 | errcode++; | |
428 | } | |
429 | else { | |
430 | if(!fflag && iflg) | |
431 | printf("dldir: directory %s removed.\n",arg); | |
432 | } | |
433 | return; | |
434 | } | |
435 | } | |
436 | ||
437 | dotname(s) | |
438 | char *s; | |
439 | { | |
440 | if(s[0] == '.') | |
441 | if(s[1] == '.') | |
442 | if(s[2] == '\0') | |
443 | return(1); | |
444 | else | |
445 | return(0); | |
446 | else if(s[1] == '\0') | |
447 | return(1); | |
448 | return(0); | |
449 | } | |
450 | ||
451 | yes() | |
452 | { | |
453 | int i, b; | |
454 | ||
455 | i = b = getchar(); | |
456 | while(b != '\n' && b != EOF) | |
457 | b = getchar(); | |
458 | return(i == 'y'); | |
459 | } | |
460 | ||
461 | move(source, target, iflag) | |
462 | char *source, *target; | |
463 | { | |
464 | int targetexists; | |
465 | int sw = 0; | |
466 | ||
467 | if (dflag) printf("move entered: source=%s target=%s fflag=%d iflag=%d\n",source,target,fflag,iflag); | |
468 | if (lstat(source, &s1) < 0) { | |
469 | if (!fflag) | |
470 | error("cannot access %s", source); | |
471 | return (1); | |
472 | } | |
473 | if (dflag) printf("move: lstat(%s) successful\n",source); | |
474 | /* | |
475 | * First, try to rename source to target. | |
476 | */ | |
477 | targetexists = lstat(target, &s2) >= 0; | |
478 | if (targetexists) { | |
479 | if (dflag) printf("move: lstat(%s) successful\n",target); | |
480 | if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) { | |
481 | if (!fflag) | |
482 | error("%s and %s are identical", source, target); | |
483 | return (1); | |
484 | } | |
485 | if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) { | |
486 | if (query("override protection %o for %s? ", | |
487 | s2.st_mode & MODEBITS, target) == 0) | |
488 | return (1); | |
489 | sw++; | |
490 | } | |
491 | if (mflag && ms == 0) { | |
492 | if (ISREG(s2)) { | |
493 | if (!fflag && sw == 0) { | |
494 | printf("overwrite file %s?", target); | |
495 | if(!yes()) | |
496 | return; | |
497 | } | |
498 | ms = 1; | |
499 | dl (target, 0); | |
500 | } | |
501 | else | |
502 | if (s1.st_dev != s2.st_dev && ISDIR(s2)) | |
503 | goto copyit; | |
504 | } | |
505 | } | |
506 | if (!fflag && iflag && !mflag) { | |
507 | if (ISDIR(s1)) | |
508 | printf("dl: delete directory %s?", source); | |
509 | else | |
510 | printf("dl: delete file %s?", source); | |
511 | if(!yes()) | |
512 | return; | |
513 | } | |
514 | if(dflag) printf("move(1)rename: source=%s, target=%s\n",source, target); | |
515 | if (rename(source, target) >= 0) { | |
516 | if (!fflag && iflag && !mflag) | |
517 | printf("dl: %s deleted. \n",source); | |
518 | if (dflag) printf("move: %s renamed %s.\n",source,target); | |
519 | return (0); | |
520 | } | |
521 | if (dflag) printf("move/rename: errno=%d\n",errno); | |
522 | if (errno != EXDEV) { | |
523 | if (!fflag && iflag) { | |
524 | Perror2(source, "rename"); | |
525 | } | |
526 | goto copyit; | |
527 | } | |
528 | if (targetexists && unlink(target) < 0) { | |
529 | if(!fflag) | |
530 | error("cannot unlink %s", target); | |
531 | return (1); | |
532 | } | |
533 | if (dflag) printf("move: target unlinked\n"); | |
534 | ||
535 | /* | |
536 | * If file or directory cannot be renamed: | |
537 | * If directory, copy it with r option | |
538 | * and delete the source | |
539 | */ | |
540 | copyit: if (ISDIR(s1)) { | |
541 | if (dflag) printf("move: directory copy %s to %s\n",source,target); | |
542 | copy (source, target, iflag, 1); | |
543 | dldir (source, iflag); | |
544 | return(0); | |
545 | } | |
546 | ||
547 | /* | |
548 | * If link, recreate symbolic link | |
549 | */ | |
550 | if (ISLNK(s1)) { | |
551 | register m; | |
552 | char symln[MAXPATHLEN]; | |
553 | ||
554 | if (readlink(source, symln, sizeof (symln)) < 0) { | |
555 | if (!fflag) | |
556 | Perror(source); | |
557 | return (1); | |
558 | } | |
559 | m = umask(~(s1.st_mode & MODEBITS)); | |
560 | if (symlink(symln, target) < 0) { | |
561 | if (!fflag) | |
562 | Perror(target); | |
563 | return (1); | |
564 | } | |
565 | if (dflag) printf("move: symlink to target successful\n"); | |
566 | (void) umask(m); | |
567 | goto cleanup; | |
568 | } | |
569 | ||
570 | /* | |
571 | * If device | |
572 | */ | |
573 | if (ISDEV(s1)) { | |
574 | if (mknod(target, s1.st_mode, s1.st_rdev) < 0) { | |
575 | if (!fflag) | |
576 | Perror(target); | |
577 | return (1); | |
578 | } | |
579 | if (dflag) printf("move: mknod for target successful\n"); | |
580 | goto cleanup; | |
581 | } | |
582 | ||
583 | /* | |
584 | * If regular file, copy it | |
585 | */ | |
586 | if (ISREG(s1)) { | |
587 | if(dflag) printf("move: file copy %s to %s\n",source,target); | |
588 | copy(source, target, iflag, 0); | |
589 | goto cleanup; | |
590 | } | |
591 | ||
592 | if (!fflag) | |
593 | error("%s: unknown file type %o", source, s1.st_mode); | |
594 | return (1); | |
595 | ||
596 | /* | |
597 | * If a move has been successful, erase the source | |
598 | */ | |
599 | cleanup: | |
600 | if (dflag) printf("move: cleanup\n"); | |
601 | if (unlink(source) < 0) { | |
602 | if (!fflag) | |
603 | error("cannot unlink %s", source); | |
604 | return (1); | |
605 | } | |
606 | if (dflag) printf("move: %s unlinked.\n",source); | |
607 | if (!fflag && iflag && !mflag) | |
608 | printf("dl: %s deleted.\n",source); | |
609 | return (0); | |
610 | } | |
611 | ||
612 | /*VARARGS*/ | |
613 | query(prompt, a1, a2) | |
614 | char *a1; | |
615 | { | |
616 | register char i, c; | |
617 | ||
618 | fprintf(stderr, prompt, a1, a2); | |
619 | i = c = getchar(); | |
620 | while (c != '\n' && c != EOF) | |
621 | c = getchar(); | |
622 | return (i == 'y'); | |
623 | } | |
624 | ||
625 | error(fmt, a1, a2) | |
626 | char *fmt; | |
627 | { | |
628 | fprintf(stderr, "dl: "); | |
629 | fprintf(stderr, fmt, a1, a2); | |
630 | fprintf(stderr, "\n"); | |
631 | } | |
632 | ||
633 | Perror(s) | |
634 | char *s; | |
635 | { | |
636 | char buf[MAXPATHLEN + 10]; | |
1b9a18bc KB |
637 | |
638 | (void) sprintf(buf, "move: %s", s); | |
07e1a339 RC |
639 | perror(buf); |
640 | } | |
641 | ||
642 | Perror2(s1, s2) | |
643 | char *s1, *s2; | |
644 | { | |
645 | char buf[MAXPATHLEN + 20]; | |
646 | ||
1b9a18bc | 647 | (void) sprintf(buf, "dl: %s: %s", s1, s2); |
07e1a339 RC |
648 | perror(buf); |
649 | } | |
650 | ||
651 | #define BSIZE 8192 | |
652 | ||
653 | char *rindex(); | |
654 | ||
655 | copy(from, to, iflag, rflag) | |
656 | char *from, *to; | |
657 | { | |
658 | int fold, fnew, n; | |
659 | char *last, destname[BSIZE], buf[BSIZE]; | |
660 | struct stat stfrom, stto; | |
661 | time_t tv[2]; | |
662 | ||
663 | if (dflag) printf("copy entered: from=%s to=%s iflag=%d rflag=%d\n",from,to,iflag,rflag); | |
664 | fold = open(from, 0); | |
665 | if (fold < 0) { | |
666 | Cerror(from,fflag); | |
667 | return (1); | |
668 | } | |
669 | if (fstat(fold, &stfrom) < 0) { | |
670 | Cerror(from,fflag); | |
671 | (void) close(fold); | |
672 | return (1); | |
673 | } | |
674 | if (dflag) printf("copy: fstat(%s) OK.\n",from); | |
675 | if (stat(to, &stto) >= 0 && | |
676 | (stto.st_mode&S_IFMT) == S_IFDIR) { | |
677 | last = rindex(from, '/'); | |
678 | if (last) last++; else last = from; | |
679 | if (strlen(to) + strlen(last) >= BSIZE - 1) { | |
680 | fprintf(stderr, "cp: %s/%s: Name too long", to, last); | |
681 | (void) close(fold); | |
682 | return(1); | |
683 | } | |
684 | (void) sprintf(destname, "%s/%s", to, last); | |
685 | if (dflag) printf("copy: stat %s & %s is dir., to=%s.\n",to,to,destname); | |
686 | to = destname; | |
687 | } | |
688 | if (!rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { | |
689 | fprintf(stderr, "cp: %s is a directory, and option -r not chosen. Job aborted.\n", from); | |
690 | return(1); | |
691 | } | |
692 | if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { | |
693 | (void) close(fold); | |
694 | if (dflag) printf("copy: rflag & from is dir., %s closed.\n",from); | |
695 | if (stat(to, &stto) < 0) { | |
696 | if (mkdir(to, (int)stfrom.st_mode) < 0) { | |
697 | Cerror(to,fflag); | |
698 | return (1); | |
699 | } | |
700 | if (dflag) printf("copy: stat(%s) failed & mkdir % successful.\n",to,to); | |
701 | } | |
702 | else { | |
703 | if (!fflag) { | |
704 | if ((stto.st_mode&S_IFMT) == S_IFDIR) { | |
705 | dl(to, iflag); | |
706 | } | |
707 | else { | |
708 | fprintf(stderr, "cp: %s: Not a directory.\n", to); | |
709 | return (1); | |
710 | } | |
711 | } | |
712 | } | |
713 | if (dflag) printf("copy: return with rcopy(%s,%s,%d,%d)\n",from,to,iflag,rflag); | |
714 | return (rcopy(from, to, iflag, rflag)); | |
715 | } | |
716 | if (stat(to, &stto) >= 0) { | |
717 | if (dflag) printf("cp:stat(%s) o.k.\n",to); | |
718 | if (stfrom.st_dev == stto.st_dev && | |
719 | stfrom.st_ino == stto.st_ino) { | |
720 | fprintf(stderr, "cp: Cannot copy file to itself.\n"); | |
721 | (void) close(fold); | |
722 | return (1); | |
723 | } | |
724 | if (cflag && cs == 0) { | |
725 | if (!fflag) | |
726 | fprintf (stderr, "cp: %s exists: overwrite? ", to); | |
727 | if (!yes()) { | |
728 | (void) close(fold); | |
729 | return(1); | |
730 | } | |
731 | dl(to, 0); | |
732 | cs = 1; | |
733 | } | |
734 | } | |
735 | fnew = creat(to, (int)stfrom.st_mode); | |
736 | if (fnew < 0) { | |
737 | Cerror(to,fflag); | |
738 | (void) close(fold); return(1); | |
739 | } | |
740 | if (dflag) printf("copy: creat(%s,%d) successful.\n",to,stfrom.st_mode); | |
741 | for (;;) { | |
742 | n = read(fold, buf, BSIZE); | |
743 | if (n == 0) | |
744 | break; | |
745 | if (n < 0) { | |
746 | Cerror(from,fflag); | |
747 | (void) close(fold); (void) close(fnew); return (1); | |
748 | } | |
749 | if (write(fnew, buf, n) != n) { | |
750 | Cerror(to,fflag); | |
751 | (void) close(fold); (void) close(fnew); return (1); | |
752 | } | |
753 | } | |
754 | if (dflag) printf("copy: %s copied to %s.\n",from,to); | |
755 | if (!tflag) { | |
756 | /* restore original time-stamp */ | |
757 | tv[0] = stfrom.st_atime; | |
758 | tv[1] = stfrom.st_mtime; | |
759 | (void) utime(to, tv); | |
760 | if (dflag) printf("copy: tflag on, tv[0]=%d, tv[1]=%d.\n",tv[0], tv[1]); | |
761 | } | |
762 | if (dflag) printf("copy: returning from copy, from=%s, to=%s.\n",from,to); | |
763 | (void) close(fold); (void) close(fnew); return (0); | |
764 | } | |
765 | ||
766 | rcopy(from, to, iflag, rflag) | |
767 | char *from, *to; | |
768 | { | |
769 | DIR *fold = opendir(from); | |
770 | struct direct *dp; | |
771 | int errs = 0; | |
772 | char fromname[BUFSIZ]; | |
773 | ||
774 | if (dflag) printf("rcopy: entered: from=%s, to=%s.\n",from,to); | |
775 | if (fold == 0) { | |
776 | Cerror(from,fflag); | |
777 | return (1); | |
778 | } | |
779 | for (;;) { | |
780 | dp = readdir(fold); | |
781 | if (dp == 0) { | |
782 | closedir(fold); | |
783 | return (errs); | |
784 | } | |
785 | if (dp->d_ino == 0) | |
786 | continue; | |
787 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
788 | continue; | |
789 | if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { | |
790 | if (!fflag) { | |
791 | fprintf(stderr, "cp: %s/%s: Name too long.\n", | |
792 | from, dp->d_name); | |
793 | } | |
794 | errs++; | |
795 | continue; | |
796 | } | |
797 | (void) sprintf(fromname, "%s/%s", from, dp->d_name); | |
798 | if (dflag) printf("rcopy: copy(%s,%s,%d,%d)\n",fromname,to,iflag,rflag); | |
799 | errs += copy(fromname, to, iflag, rflag); | |
800 | } | |
801 | } | |
802 | ||
803 | Cerror(s) | |
804 | char *s; | |
805 | { | |
806 | if (!fflag) { | |
807 | fprintf(stderr, "cp: "); | |
808 | perror(s); | |
809 | } | |
810 | } |