1#include "config.h"
2
3#include <errno.h>
4#include <fcntl.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12#if HAVE_FTS_OPEN
13#include <fts.h>
14#endif
15
16#include "srm.h"
17
18#ifndef FTS_D
19#define FTS_D      0
20#define FTS_DC     1
21#define FTS_DNR    2
22#define FTS_DOT    3
23#define FTS_DP     4
24#define FTS_ERR    5
25#define FTS_F      6
26#define FTS_SL     7
27#define FTS_SLNONE 8
28#define FTS_NS     9
29#endif /* ndef FTS_D */
30
31int prompt_user(const char *string) {
32  char inbuf[8];
33
34  printf("%s", string);
35  fgets(inbuf, 4, stdin);
36  return strncmp(inbuf, "y", 1) == 0;
37}
38
39int check_perms(const char *path) {
40  int fd;
41
42  if ( ((fd = open(path, O_WRONLY)) == -1) && (errno == EACCES) ) {
43    if ( chmod(path, S_IRUSR | S_IWUSR) == -1 ) {
44      errorp("Unable to reset %s to writable (probably not owner) "
45	     "... skipping", path);
46      return 0;
47    }
48  }
49
50  close(fd);
51  return 1;
52}
53
54int prompt_file(const char *path, int fts_flag) {
55  int fd, return_value = 1;
56  size_t bufsize = strlen(path) + 80;
57  char *buf;
58
59  if ( (buf = (char *)malloc(bufsize)) == NULL ) {
60    errorp("Out of memory at line %d in prompt_file()", __LINE__);
61    return 0;
62  }
63
64  if (options & OPT_F) {
65    if (options & OPT_V) {
66      printf("removing %s\n", path);
67      fflush(stdout);
68    }
69    return check_perms(path);
70  }
71
72  if ( (fts_flag != FTS_SL) && ((fd = open(path, O_WRONLY)) == -1) &&
73       (errno == EACCES) )
74  {
75    /* Not a symlink, not writable */
76    snprintf(buf, bufsize, "Remove write protected file %s? ", path);
77    if ( (return_value = prompt_user(buf)) == 1 )
78      return_value = check_perms(path);
79  } else {
80    /* Writable file or symlink */
81    if (options & OPT_I) {
82      snprintf(buf, bufsize, "Remove %s? ", path);
83      return_value = prompt_user(buf);
84    }
85  }
86
87  if ((options & OPT_V) && return_value)
88    printf("removing %s\n", path);
89
90  free(buf);
91  close(fd); /* close if open succeeded, or silently fail */
92
93  return return_value;
94}
95
96int process_file(char *path, int flag) {
97  while (path[strlen(path) - 1] == '/')
98    path[strlen(path)- 1] = '\0';
99
100  switch (flag) {
101  case FTS_D: break;
102  case FTS_DC:
103    error("cyclic directory entry %s", path);
104    break;
105  case FTS_DNR:
106    error("%s: permission denied", path);
107    break;
108  case FTS_DOT: break;
109  case FTS_DP:
110    if (options & OPT_R) {
111      if ( prompt_file(path, flag) && (rename_unlink(path) == -1) )
112        errorp("unable to remove %s", path);
113    } else {
114      error("%s is a directory", path);
115    }
116    break;
117  case FTS_ERR:
118    error("fts error on %s", path);
119    break;
120  case FTS_F:
121  case FTS_SL:
122  case FTS_SLNONE:
123    if ( prompt_file(path, flag) && (sunlink(path) == -1) ) {
124      if (errno == EMLINK)
125        error("%s has multiple links, this one has been removed but not "
126              "overwritten", path);
127      else
128        errorp("unable to remove %s", path);
129    }
130    break;
131  case FTS_NS:
132    if ( !(options & OPT_F) ) /* Ignore nonexistant files with -f */
133      error("unable to stat %s", path);
134  default:
135    break;
136  }
137  return 0;
138}
139
140#if HAVE_FTS_OPEN
141
142int tree_walker(char **trees) {
143  FTSENT *current_file;
144  FTS *stream;
145  int i = 0;
146
147  while (trees[i] != NULL) {
148    while (trees[i][strlen(trees[i]) - 1] == '/')
149      trees[i][strlen(trees[i]) -1] = '\0';
150    i++;
151  }
152
153  if ( (stream = fts_open(trees, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL )
154    errorp("fts_open() returned NULL");
155  while ( (current_file = fts_read(stream)) != NULL) {
156    process_file(current_file->fts_path, current_file->fts_info);
157    if ( !(options & OPT_R) )
158      fts_set(stream, current_file, FTS_SKIP);
159  }
160  return 0;
161}
162
163#elif HAVE_NFTW
164
165#if defined(__digital__) && defined(__unix__)
166/* Shut up tru64's cc(1) */
167#define _XOPEN_SOURCE_EXTENDED
168#endif
169#include <ftw.h>
170
171int ftw_process_path(const char *opath, const struct stat *statbuf, int flag,
172		 struct FTW *dummy)
173{
174  size_t path_size = strlen(opath) + 1;
175  char *path = (char *)alloca(path_size);
176
177  if (path == NULL) {
178    errno = ENOMEM;
179    return -1;
180  }
181  strncpy(path, opath, path_size);
182
183  switch (flag) {
184  case FTW_F:
185    process_file(path, FTS_F);
186    break;
187  case FTW_SL:
188    process_file(path, FTS_SL);
189    break;
190  case FTW_D:
191    process_file(path, FTS_D);
192    break;
193  case FTW_DP:
194    process_file(path, FTS_DP);
195    break;
196  case FTW_DNR:
197    process_file(path, FTS_DNR);
198    break;
199  case FTW_NS:
200    process_file(path, FTS_NS);
201    break;
202  }
203
204  if (options & OPT_R)
205    return 0;
206  return 1;
207}
208
209int tree_walker(char **trees) {
210  int i = 0;
211
212  while (trees[i] != NULL) {
213    while (trees[i][strlen(trees[i]) - 1] == '/')
214      trees[i][strlen(trees[i]) -1] = '\0';
215    if (options & OPT_R)
216      nftw(trees[i], ftw_process_path, 10, FTW_DEPTH);
217    else
218      nftw(trees[i], ftw_process_path, 10, 0);
219    i++;
220  }
221  return 0;
222}
223
224#else
225#error No tree traversal function found
226#endif
227