source: trunk/athena/bin/delete/delete.c @ 1811

Revision 1811, 9.7 KB checked in by jik, 35 years ago (diff)
added mit-copyright stuff
Line 
1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/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: /afs/dev.mit.edu/source/repository/athena/bin/delete/delete.c,v 1.17 1989-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
67int force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
68char *whoami;
69char *malloc();
70
71main(argc, argv)
72int argc;
73char *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
151usage()
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
172delete(filename, recursed)
173char *filename;
174int 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               
253empty_directory(filename)
254char *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
280recursive_delete(filename, stat_buf, recursed)
281char *filename;
282struct stat stat_buf;
283int 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
324do_move(filename, stat_buf, err_mask)
325char *filename;
326struct stat stat_buf;
327int 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
389unlink_completely(filename)
390char *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
Note: See TracBrowser for help on using the repository browser.