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