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