1 static char *sccsid = "@(#)dl.c 4.2\t12/20/87"; 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; 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)) { 382 (void) sprintf(name, "%s/%s", arg, dp->d_name); 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]; 637 638 (void) sprintf(buf, "move: %s", s); 639 perror(buf); 640 } 641 642 Perror2(s1, s2) 643 char *s1, *s2; 644 { 645 char buf[MAXPATHLEN + 20]; 646 647 (void) sprintf(buf, "dl: %s: %s", s1, s2); 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 } 811