home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / undel / part03 / delete.c next >
Encoding:
C/C++ Source or Header  |  1989-05-06  |  9.6 KB  |  422 lines

  1. /*
  2.  * $Source: /mit/jik/src/delete/RCS/delete.c,v $
  3.  * $Author: jik $
  4.  *
  5.  * This program is a replacement for rm.  Instead of actually deleting
  6.  * files, it marks them for deletion by prefixing them with a ".#"
  7.  * prefix.
  8.  *
  9.  * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  10.  * For copying and distribution information, see the file "mit-copyright.h."
  11.  */
  12.  
  13. #if (!defined(lint) && !defined(SABER))
  14.      static char rcsid_delete_c[] = "$Header: delete.c,v 1.17 89/03/27 12:05:58 jik Exp $";
  15. #endif
  16.  
  17. #include <sys/types.h>
  18. #include <stdio.h>
  19. #include <sys/stat.h>
  20. #include <sys/dir.h>
  21. #include <strings.h>
  22. #include <sys/param.h>
  23. #include <sys/file.h>
  24. #include "util.h"
  25. #include "delete.h"
  26. #include "mit-copyright.h"
  27.  
  28.  
  29.  
  30.  
  31. /*
  32.  * ALGORITHM:
  33.  *
  34.  * 1. Parse command-line arguments and set flags.
  35.  * 2. Call the function delete() for each filename command-line argument.
  36.  *
  37.  * delete():
  38.  *
  39.  * 1. Can the file be lstat'd?
  40.  *    no -- abort
  41.  *    yes -- continue
  42.  * 2. Is the file a directory?
  43.  *    yes -- is it a dotfile?
  44.  *           yes -- abort
  45.  *           no -- continue
  46.  *        -- is the filesonly option set?
  47.  *           yes -- is the recursive option specified?
  48.  *                  yes -- continue
  49.  *                  no -- abort
  50.  *           no -- is the directory empty?
  51.  *                  yes -- remove it
  52.  *                  no -- is the directoriesonly option set?
  53.  *               yes -- abort
  54.  *               no -- continue
  55.  *                -- is the recursive option specified?
  56.  *               yes -- continue
  57.  *               no -- abort
  58.  *    no -- is the directoriesonly option set?
  59.  *         yes -- abort
  60.  *         no -- continue
  61.  * 3. If the file is a file, remove it.
  62.  * 4. If the file is a directory, open it and pass each of its members
  63.  *    (excluding . files) to delete().
  64.  */
  65.  
  66.  
  67. int force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
  68. char *whoami;
  69. char *malloc();
  70.  
  71. main(argc, argv)
  72. int argc;
  73. char *argv[];
  74. {
  75.      extern char *optarg;
  76.      extern int optind;
  77.      int arg;
  78.      int status = 0;
  79.      
  80.      whoami = lastpart(argv[0]);
  81.  
  82.      force = interactive = recursive = noop = verbose = filesonly =
  83.       directoriesonly = 0;
  84.      while ((arg = getopt(argc, argv, "firnvFD")) != -1) {
  85.       switch (arg) {
  86.       case 'r':
  87.            recursive++;
  88.            if (directoriesonly) {
  89.             fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  90.                 whoami);
  91.             usage();
  92.             exit(! force);
  93.            }
  94.            break;
  95.       case 'f':
  96.            force++;
  97.            break;
  98.       case 'i':
  99.            interactive++;
  100.            break;
  101.       case 'n':
  102.            noop++;
  103.            break;
  104.       case 'v':
  105.            verbose++;
  106.            break;
  107.       case 'F':
  108.            filesonly++;
  109.            if (directoriesonly) {
  110.             fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  111.                 whoami);
  112.             usage();
  113.             exit(! force);
  114.            }
  115.            break;
  116.       case 'D':
  117.            directoriesonly++;
  118.            if (recursive) {
  119.             fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  120.                 whoami);
  121.             usage();
  122.             exit(! force);
  123.            }
  124.            if (filesonly) {
  125.             fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  126.                 whoami);
  127.             usage();
  128.             exit(! force);
  129.            }
  130.            break;
  131.       default:
  132.            usage();
  133.            exit(! force);
  134.       }
  135.      }
  136.      if (optind == argc) {
  137.       fprintf(stderr, "%s: no files specified.\n", whoami);
  138.       usage();
  139.       exit(! force);
  140.      }
  141.      while (optind < argc) {
  142.       status = status | delete(argv[optind], 0);
  143.       optind++;
  144.      }
  145.      exit((! force) && (status & ERROR_MASK));
  146. }
  147.  
  148.  
  149.  
  150.  
  151. usage()
  152. {
  153.      printf("Usage: %s [ options ] filename ...\n", whoami);
  154.      printf("Options are:\n");
  155.      printf("     -r     recursive\n");
  156.      printf("     -i     interactive\n");
  157.      printf("     -f     force\n");
  158.      printf("     -n     noop\n");
  159.      printf("     -v     verbose\n");
  160.      printf("     -F     files only\n");
  161.      printf("     -D     directories only\n");
  162.      printf("     --     end options and start filenames\n");
  163.      printf("-r and -D are mutually exclusive\n");
  164.      printf("-F and -D are mutually exclusive\n");
  165. }
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172. delete(filename, recursed)
  173. char *filename;
  174. int recursed;
  175. {
  176.      struct stat stat_buf;
  177.  
  178.      /* can the file be lstat'd? */
  179.      if (lstat(filename, &stat_buf) == -1) {
  180.       if (! force)
  181.            fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
  182.       return(ERROR_MASK);
  183.      }
  184.      
  185.      /* is the file a directory? */
  186.      if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  187.       /* is the file a dot file? */
  188.       if (is_dotfile(filename)) {
  189.            if (! force)
  190.             fprintf(stderr, "%s: cannot remove `.' or `..'\n",
  191.                 whoami);
  192.            return(ERROR_MASK);
  193.       }
  194.       /* is the filesonly option set? */
  195.       if (filesonly) {
  196.            /* is the recursive option specified? */
  197.            if (recursive) {
  198.             return(recursive_delete(filename, stat_buf, recursed));
  199.            }
  200.            else {
  201.             if (! force)
  202.              fprintf(stderr, "%s: %s directory\n", whoami,
  203.                  filename);
  204.             return(ERROR_MASK);
  205.            }
  206.       }
  207.       else {
  208.            /* is the directory empty? */
  209.            if (empty_directory(filename)) {
  210.             /* remove it */
  211.             return(do_move(filename, stat_buf, 0));
  212.            }
  213.            else {
  214.             /* is the directoriesonly option set? */
  215.             if (directoriesonly) {
  216.              if (! force)
  217.                   fprintf(stderr, "%s: %s: Directory not empty\n",
  218.                      whoami, filename);
  219.              return(ERROR_MASK);
  220.             }
  221.             else {
  222.              /* is the recursive option specified? */
  223.              if (recursive) {
  224.                   return(recursive_delete(filename, stat_buf,
  225.                               recursed));
  226.              }
  227.              else {
  228.                   if (! force)
  229.                    fprintf(stderr, "%s: %s not empty\n",
  230.                        whoami, filename);
  231.                   return(ERROR_MASK);
  232.              }
  233.             }
  234.            }
  235.       }
  236.      }
  237.      else {
  238.       /* is the directoriesonly option set? */
  239.       if (directoriesonly) {
  240.            if (! force)
  241.             fprintf(stderr, "%s: %s: Not a directory\n", whoami,
  242.                 filename);
  243.            return(ERROR_MASK);
  244.       }
  245.       else
  246.            return(do_move(filename, stat_buf, 0));
  247.      }
  248. }
  249.  
  250.          
  251.              
  252.            
  253. empty_directory(filename)
  254. char *filename;
  255. {
  256.      DIR *dirp;
  257.      struct direct *dp;
  258.  
  259.      dirp = opendir(filename);
  260.      if (! dirp) {
  261.       return(0);
  262.      }
  263.      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  264.       if (is_dotfile(dp->d_name))
  265.            continue;
  266.       if (is_deleted(dp->d_name))
  267.            continue;
  268.       else {
  269.            closedir(dirp);
  270.            return(0);
  271.       }
  272.      }
  273.      closedir(dirp);
  274.      return(1);
  275. }
  276.  
  277.  
  278.  
  279.  
  280. recursive_delete(filename, stat_buf, recursed)
  281. char *filename;
  282. struct stat stat_buf;
  283. int recursed;
  284. {
  285.      DIR *dirp;
  286.      struct direct *dp;
  287.      int status = 0;
  288.      char newfile[MAXPATHLEN];
  289.      
  290.      if (interactive && recursed) {
  291.       printf("%s: remove directory %s? ", whoami, filename);
  292.       if (! yes())
  293.            return(NO_DELETE_MASK);
  294.      }
  295.      dirp = opendir(filename);
  296.      if (! dirp) {
  297.       if (! force)
  298.            fprintf(stderr, "%s: %s not changed\n", whoami, filename);
  299.       return(ERROR_MASK);
  300.      }
  301.      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  302.       if (is_dotfile(dp->d_name))
  303.            continue;
  304.       if (is_deleted(dp->d_name))
  305.            continue;
  306.       else {
  307.            strcpy(newfile, append(filename, dp->d_name, !force));
  308.            if (*newfile)
  309.             status = status | delete(newfile, 1);
  310.            else
  311.             status = ERROR_MASK;
  312.       }
  313.      }
  314.      closedir(dirp);
  315.      status = status | do_move(filename, stat_buf, status);
  316.      return(status);
  317. }
  318.  
  319.                      
  320.  
  321.  
  322.  
  323.  
  324. do_move(filename, stat_buf, err_mask)
  325. char *filename;
  326. struct stat stat_buf;
  327. int err_mask;
  328. {
  329.      char *last;
  330.      char buf[MAXPATHLEN];
  331.      char name[MAXNAMLEN];
  332.      struct stat deleted_buf;
  333.  
  334.      strncpy(buf, filename, MAXPATHLEN);
  335.      last = lastpart(buf);
  336.      if (strlen(last) > MAXNAMLEN) {
  337.       if (! force)
  338.            fprintf(stderr, "%s: %s: filename too long\n", whoami,
  339.                filename);
  340.       return(ERROR_MASK);
  341.      }
  342.      strcpy(name, last);
  343.      if (strlen(buf) + 3 > MAXPATHLEN) {
  344.       if (! force)
  345.            fprintf(stderr, "%s: %s: pathname too long\n", whoami,
  346.                filename);
  347.       return(ERROR_MASK);
  348.      }
  349.      *last = '\0';
  350.      strcat(buf, ".#");
  351.      strcat(buf, name);
  352.      if (err_mask) {
  353.       if (! force)
  354.            fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  355.       return(err_mask);
  356.      }
  357.      if (interactive) {
  358.       printf("%s: remove %s? ", whoami, filename);
  359.       if (! yes())
  360.            return(NO_DELETE_MASK);
  361.      }
  362.      else if ((! force) && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
  363.           && access(filename, W_OK)) {
  364.       printf("%s: override protection %o for %s? ", whoami,
  365.          stat_buf.st_mode & 0777, filename);
  366.       if (! yes())
  367.            return(NO_DELETE_MASK);
  368.      }
  369.      if (noop) {
  370.       fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
  371.       return(0);
  372.      }
  373.      if (! lstat(buf, &deleted_buf))
  374.       unlink_completely(buf);
  375.      if (rename(filename, buf)) {
  376.       if (! force)
  377.            fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  378.       return(ERROR_MASK);
  379.      }
  380.      else {
  381.       if (verbose)
  382.            fprintf(stderr, "%s: %s removed\n", whoami, filename);
  383.       return(0);
  384.      }
  385. }
  386.  
  387.  
  388.  
  389. unlink_completely(filename)
  390. char *filename;
  391. {
  392.      char buf[MAXPATHLEN];
  393.      struct stat stat_buf;
  394.      DIR *dirp;
  395.      struct direct *dp;
  396.      int status = 0;
  397.      
  398.      if (lstat(filename, &stat_buf))
  399.       return(1);
  400.  
  401.      if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  402.       dirp = opendir(filename);
  403.       if (! dirp)
  404.            return(1);
  405.       readdir(dirp); readdir(dirp); /* get rid of . and .. */
  406.       for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  407.            strcpy(buf, append(filename, dp->d_name, 0));
  408.            if (! buf) {
  409.             status = 1;
  410.             continue;
  411.            }
  412.            status = status | unlink_completely(buf);
  413.       }
  414.       closedir(dirp);
  415.       status = status | rmdir(filename);
  416.       return(status);
  417.      }
  418.      else
  419.       return(unlink(filename) == -1);
  420. }
  421.  
  422.