home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 264_01 / rm.c < prev    next >
Text File  |  1979-12-31  |  7KB  |  303 lines

  1. /*
  2.  * rm - remove files and directories
  3.  *
  4.  * Usage: rm [-fiv] [-] file...
  5.  *        rm [-fiv] -r [-] file|dir...
  6.  *
  7.  * Flags:
  8.  * -    interpret following arguments starting with '-' as filenames
  9.  * -f   force; don't report errors, override readonly attribute
  10.  * -i   interactive; asks whether to remove each file or directory
  11.  * -r   recursively remove arguments which are directories
  12.  * -v   verbose; display name of each file as it's removed
  13.  *
  14.  * This program is in the public domain.
  15.  * David MacKenzie
  16.  * 6522 Elgin Lane
  17.  * Bethesda, MD 20817
  18.  *
  19.  * Latest revision: 05/10/88
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stat.h>
  24. #include <ctype.h>
  25. #ifndef tolower(c)
  26. #define tolower(c) _tolower(c)
  27. #endif
  28. #include "getdir.h"
  29.  
  30. #define MAXPATH 125        /* Arbitrary internal limit on path lengths. */
  31.  
  32. int     fflag = 0;        /* Force success? */
  33. int     iflag = 0;        /* Interactive (query before removing)? */
  34. int     rflag = 0;        /* Remove subdirectories recursively? */
  35. int     vflag = 0;        /* Verbose (display names as removed)? */
  36.  
  37. struct stat statbuf;
  38.  
  39. _main(argc, argv)
  40.     int     argc;
  41.     char  **argv;
  42. {
  43.     void    usage(), rm();
  44.     int     optind;        /* Loop index. */
  45.  
  46.     for (optind = 1; optind < argc && *argv[optind] == '-'; ++optind) {
  47.     if (argv[optind][1] == 0)
  48.         break;
  49.     else
  50.         while (*++argv[optind])
  51.         switch (*argv[optind]) {
  52.         case 'f':
  53.             fflag = 1;
  54.             break;
  55.         case 'i':
  56.             iflag = 1;
  57.             break;
  58.         case 'r':
  59.             rflag = 1;
  60.             break;
  61.         case 'v':
  62.             vflag = 1;
  63.             break;
  64.         default:
  65.             usage();
  66.             break;
  67.         }
  68.     }
  69.  
  70.     if (optind == argc)
  71.     usage();
  72.  
  73.     for (; optind < argc; ++optind)
  74.     rm(argv[optind]);
  75.  
  76.     exit(0);
  77. }
  78.  
  79. /*
  80.  * Remove file or directory specified by path.
  81.  */
  82. void
  83. rm(path)
  84.     char   *path;
  85. {
  86.     void    rrmdir(), rmfile();
  87.     char   *strtolower();
  88.  
  89.     (void) strtolower(path);
  90.     if (vflag)
  91.     printf("%s\n", path);
  92.  
  93.     if (isroot(path) || isdot(path)) {
  94.     fprintf(stderr, "rm: Cannot remove %s\n", path);
  95.     return;
  96.     }
  97.     if (stat(path, &statbuf) == -1) {
  98.     if (!fflag)
  99.         fprintf(stderr, "%s: File not found\n", path);
  100.     return;
  101.     }
  102.     if (isdir(&statbuf)) {
  103.     if (!rflag) {
  104.         if (!fflag)
  105.         fprintf(stderr, "rm: %s directory\n", path);
  106.         return;
  107.     }
  108.     rrmdir(path);
  109.     } else
  110.     rmfile(path);
  111. }
  112.  
  113. /*
  114.  * Recursively remove a directory.
  115.  * Only used when -r flag is given.
  116.  */
  117. void
  118. rrmdir(path)
  119.     char   *path;
  120. {
  121.     void    rmfile();
  122.     char   *basename(), *concat();
  123.     char    dirbuf[512];    /* Buffer for disk input. */
  124.     struct ffblk *dir = (struct ffblk *) dirbuf;
  125.     char    pathbuf[MAXPATH];    /* Path of globbed dir contents. */
  126.     char   *tail;        /* Tail component of pathbuf. */
  127.     int     i;            /* Loop control. */
  128.  
  129.     if (!permit(path, 1))
  130.     return;
  131.     /*
  132.      * Save any leading drive and/or path in pathbuf because the MS-DOS
  133.      * globbing routines return only the base of the filenames. 
  134.      */
  135.     (void) strcpy(pathbuf, concat(path, "*.*"));
  136.     tail = basename(pathbuf);
  137.  
  138.     /* Must reset the disk transfer area because stat() uses it. */
  139.     for (setdta(dirbuf), i = getfirst(pathbuf, FA_ALL); !i;
  140.     setdta(dirbuf), i = getnext(pathbuf, FA_ALL)) {
  141.     if (dir->ff_fname[0] != '.') {
  142.         (void) strcpy(tail, dir->ff_fname);
  143.         rm(pathbuf);
  144.     }
  145.     }
  146.     if (rmdir(path) == -1)
  147.     perr(path);
  148. }
  149.  
  150. /*
  151.  * Remove a file.
  152.  */
  153. void
  154. rmfile(path)
  155.     char   *path;
  156. {
  157.     if (!permit(path, 0) || !writable(path, &statbuf))
  158.     return;
  159.     if (unlink(path) == -1)
  160.     perr(path);
  161. }
  162.  
  163. /*
  164.  * Determine if overwriting destination file is permissible.
  165.  * Returns 1 if permission granted, 0 if not.
  166.  */
  167. permit(path, isdir)
  168.     char   *path;
  169.     int     isdir;
  170. {
  171.     int     r;            /* Response character. */
  172.     int     c;            /* One character of input. */
  173.  
  174.     if (!iflag || fflag || !isatty(0))
  175.     return 1;
  176.     fprintf(stderr, isdir ? "remove directory %s? " : "remove %s? ", path);
  177.     fflush(stderr);
  178.     c = r = getchar();
  179.     while (c != '\n' && c != EOF)
  180.     c = getchar();
  181.     return r == 'y' || r == 'Y';
  182. }
  183.  
  184. /*
  185.  * Return 1 if write permission is granted on the path, 0 otherwise.
  186.  */
  187. writable(path, statp)
  188.     char   *path;
  189.     struct stat *statp;
  190. {
  191.     int     r;            /* Response character. */
  192.     int     c;            /* One character of input. */
  193.  
  194.     if (statp->st_attr & ST_RDONLY) {
  195.     if (!fflag && isatty(0)) {
  196.         fprintf(stderr, "override protection for %s? ", path);
  197.         fflush(stderr);
  198.         c = r = getchar();
  199.         while (c != '\n' && c != EOF)
  200.         c = getchar();
  201.         if (r != 'y' && r != 'Y')
  202.         return 0;
  203.     }
  204.     return chmod(path, statp->st_attr & ~ST_RDONLY) != -1;
  205.     }
  206.     return 1;
  207. }
  208.  
  209. /*
  210.  * Convert a string to lowercase.  Return the argument.
  211.  */
  212. char   *
  213. strtolower(s)
  214.     char   *s;
  215. {
  216.     char   *t;
  217.  
  218.     for (t = s; *t; ++t)
  219.     if (isascii(*t) && isupper(*t) && *t != '_')
  220.         *t = tolower(*t);
  221.     return s;
  222. }
  223.  
  224. /*
  225.  * Return true if the path has the form "d:" or "\" or "d:\".
  226.  */
  227. isroot(p)
  228.     char   *p;
  229. {
  230.     int     i = strlen(p);
  231.  
  232.     return i == 2 && p[1] == ':' ||
  233.     !strcmp(p, "\\") ||
  234.     i == 3 && !strcmp(p + 1, ":\\");
  235. }
  236.  
  237. /*
  238.  * Return true if the path has the form:
  239.  * ".." or "d:.." or "." or "d:." or "\." or "d:\.".
  240.  */
  241. isdot(p)
  242.     char   *p;
  243. {
  244.     int     i = strlen(p);
  245.  
  246.     return !strcmp(p, "..") ||
  247.     i == 4 && !strcmp(p + 1, ":..") ||
  248.     !strcmp(p, ".") ||
  249.     i == 3 && !strcmp(p + 1, ":.") ||
  250.     !strcmp(p, "\\.") ||
  251.     i == 4 && !strcmp(p + 1, ":\\.");
  252. }
  253.  
  254. /*
  255.  * Return true if s is an existing directory, false otherwise.
  256.  */
  257. isdir(statp)
  258.     struct stat *statp;
  259. {
  260.     return (statp->st_attr & ST_DIRECT) != 0;
  261. }
  262.  
  263. /*
  264.  * Return file stuck on to the end of dir.
  265.  */
  266. char   *
  267. concat(dir, file)
  268.     char   *dir, *file;
  269. {
  270.     static char catbuf[MAXPATH];
  271.     int     i;
  272.  
  273.     if (strlen(dir) + strlen(file) + 2 > sizeof(catbuf)) {
  274.     printf("cp: filename too long\n");
  275.     exit(1);
  276.     }
  277.     if (!strcmp(dir, "") || !strcmp(dir, ".")) {
  278.     (void) strcpy(catbuf, file);
  279.     } else {
  280.     (void) strcpy(catbuf, dir);
  281.     i = strlen(dir) - 1;
  282.     if (dir[i] != '\\' && dir[i] != ':' && file[0] != '\\')
  283.         (void) strcat(catbuf, "\\");
  284.     strcat(catbuf, file);
  285.     }
  286.     return catbuf;
  287. }
  288.  
  289. perr(s)
  290.     char   *s;
  291. {
  292.     if (!fflag)
  293.     perror(s);
  294. }
  295.  
  296. void
  297. usage()
  298. {
  299.     fprintf(stderr, "Usage: rm [-fiv] [-] file...\n");
  300.     fprintf(stderr, "       rm [-fiv] -r [-] file|dir...\n");
  301.     exit(1);
  302. }
  303.