"Fossies" - the Fresh Open Source Software Archive

Member "srm-1.2.15/src/tree_walker.c" (26 Feb 2015, 8667 Bytes) of package /linux/privat/srm-1.2.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tree_walker.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.14_vs_1.2.15.

    1 /* this file is part of srm http://srm.sourceforge.net/
    2    It is licensed under the MIT/X11 license */
    3 
    4 #include "config.h"
    5 
    6 #if defined(__linux__)
    7 /* Three kludges for the price of one; glibc's fts package doesn't
    8    support LFS, so fall back to nftw. Do it here, before the headers
    9    define _BSD_SOURCE and set the prefer BSD behavior, preventing us
   10    from including XPG behavior with nftw later on. Check for linux and
   11    not glibc for the same reason. Can't include features.h without
   12    prefering bsd.
   13 
   14    Once glibc has a working fts, remove nftw completely along with
   15    this hack.
   16  */
   17 
   18 #undef HAVE_FTS_OPEN
   19 #define _GNU_SOURCE
   20 #endif
   21 
   22 #if defined(__linux__) && defined(HAVE_FTS_OPEN)
   23 /* the fts function does not like 64bit-on-32bit, but we don't need it here anyway. */
   24 #ifdef _FILE_OFFSET_BITS
   25 #undef _FILE_OFFSET_BITS
   26 #define LARGE_FILES_ARE_ENABLED 1
   27 #endif
   28 #ifdef _LARGE_FILES
   29 #undef _LARGE_FILES
   30 #define LARGE_FILES_ARE_ENABLED 1
   31 #endif
   32 #endif
   33 
   34 #include <errno.h>
   35 #include <fcntl.h>
   36 #include <stdlib.h>
   37 #include <stdio.h>
   38 #include <string.h>
   39 #include <sys/stat.h>
   40 #include <sys/types.h>
   41 #include <unistd.h>
   42 
   43 #if HAVE_FTS_OPEN
   44 #include <fts.h>
   45 #endif
   46 
   47 #include "srm.h"
   48 #include "impl.h"
   49 
   50 /**
   51  * show msg and arg to the user and wait for a reply.
   52  * @return true if the user said YES; false otherwise.
   53  */
   54 static int prompt_user(const char *msg, const char *arg)
   55 {
   56   char inbuf[8];
   57   printf(msg, arg); fflush(stdout);
   58   if(fgets(inbuf, sizeof(inbuf), stdin) == 0) return 0;
   59   return inbuf[0]=='y' || inbuf[0]=='Y';
   60 }
   61 
   62 /**
   63  * check file permissions for path and modify them so we can remove the file eventually.
   64  * @return true if permissions are find; false otherwise.
   65  */
   66 static int check_perms(const char *path)
   67 {
   68   int fd=-1;
   69 #ifdef _MSC_VER
   70   struct __stat64 statbuf;
   71 #else
   72   struct stat statbuf;
   73 #endif
   74 
   75   if(!path) return 0;
   76 
   77 #ifdef _MSC_VER
   78   if (_stat64(path, &statbuf) < 0)
   79 #else
   80   if (lstat(path, &statbuf) < 0)
   81 #endif
   82     {
   83       return 0;
   84     }
   85 
   86   if ( S_ISREG(statbuf.st_mode) && ((fd = open(path, O_WRONLY)) < 0) && (errno == EACCES) )
   87     {
   88       if ( chmod(path, S_IRUSR | S_IWUSR) < 0 )
   89     {
   90       errorp("Unable to reset %s to writable (probably not owner) ... skipping", path);
   91       return 0;
   92     }
   93     }
   94 
   95   if(fd>=0)
   96     close(fd);
   97   return 1;
   98 }
   99 
  100 /**
  101  * ask the user for confirmation to remove path.
  102  * @param options bitfield of SRM_OPT_* bits
  103  * @return true if the file should be removed; false otherwise.
  104  */
  105 static int prompt_file(const char *path, const int options)
  106 {
  107   int fd=-1, return_value=1;
  108 #ifdef _MSC_VER
  109   struct __stat64 statbuf;
  110 #else
  111   struct stat statbuf;
  112 #endif
  113 
  114   if(!path) return 0;
  115 
  116   if (options & SRM_OPT_F)
  117     {
  118       if (options & SRM_OPT_V)
  119     error("removing %s", path);
  120       return check_perms(path);
  121     }
  122 
  123 #ifdef _MSC_VER
  124   if (_stat64(path, &statbuf) < 0)
  125 #else
  126   if (lstat(path, &statbuf) < 0)
  127 #endif
  128     {
  129       errorp("could not stat %s", path);
  130       return 0;
  131     }
  132 
  133   if ( S_ISREG(statbuf.st_mode) && ((fd = open(path, O_WRONLY)) < 0) && (errno == EACCES) )
  134     {
  135       /* Not a symlink, not writable */
  136       return_value = prompt_user("Remove write protected file %s? (y/n) ", path);
  137       if(return_value == 1)
  138     return_value = check_perms(path);
  139     }
  140   else
  141     {
  142       /* Writable file or symlink */
  143       if (options & SRM_OPT_I)
  144     return_value = prompt_user("Remove %s? (y/n) ", path);
  145     }
  146 
  147   if ((options & SRM_OPT_V) && return_value)
  148     error("removing %s", path);
  149 
  150   if(fd >= 0)
  151     close(fd); /* close if open succeeded, or silently fail */
  152 
  153   return return_value;
  154 }
  155 
  156 /**
  157  * callback function for FTS/FTW.
  158  * @param flag FTS/FTW flag.
  159  * @param options bitfield of SRM_OPT_* bits
  160  * @return true if the file was removed; false otherwise.
  161  */
  162 int process_file(char *path, const int flag, const int options)
  163 {
  164   if(!path) return 0;
  165 
  166   while (path[strlen(path) - 1] == SRM_DIRSEP)
  167     path[strlen(path)- 1] = '\0';
  168 
  169   switch (flag) {
  170 #ifdef FTS_D
  171   case FTS_D:
  172     /* ignore directories */
  173     return 1;
  174 #endif
  175 
  176 #ifdef FTS_DC
  177   case FTS_DC:
  178     error("cyclic directory entry %s", path);
  179     return 0;
  180 #endif
  181 
  182 #ifdef FTS_DNR
  183   case FTS_DNR:
  184     error("%s: permission denied", path);
  185     return 0;
  186 #endif
  187 
  188 #ifdef FTS_DOT
  189   case FTS_DOT:
  190     return 1;
  191 #endif
  192 
  193 #ifdef FTS_DP
  194   case FTS_DP:
  195     if (options & SRM_OPT_R) {
  196       if (! prompt_file(path, options)) {
  197     return 0;
  198       }
  199       if (rename_unlink(path) < 0) {
  200     errorp("unable to remove %s", path);
  201     return 0;
  202       }
  203     } else {
  204       error("%s is a directory", path);
  205       return 0;
  206     }
  207     return 1;
  208 #endif
  209 
  210 #ifdef FTS_ERR
  211   case FTS_ERR:
  212     error("fts error on %s", path);
  213     return 0;
  214 #endif
  215 
  216 #ifdef FTS_NS
  217   case FTS_NS:
  218 #endif
  219 #ifdef FTS_NSOK
  220   case FTS_NSOK:
  221 #endif
  222     /* if we have 32bit system and file is >2GiB the fts functions can not stat them, so we just ignore the fts error. */
  223 #ifndef LARGE_FILES_ARE_ENABLED
  224     /* Ignore nonexistant files with -f */
  225     if ( !(options & SRM_OPT_F) )
  226       {
  227     error("unable to stat %s", path);
  228     return 0;
  229       }
  230 #endif
  231     /* no break here */
  232 
  233 #ifdef FTS_DEFAULT
  234   case FTS_DEFAULT:
  235 #endif
  236 #ifdef FTS_F
  237   case FTS_F:
  238 #endif
  239 #ifdef FTS_SL
  240   case FTS_SL:
  241 #endif
  242 #ifdef FTS_SLNONE
  243   case FTS_SLNONE:
  244 #endif
  245     if (! prompt_file(path, options)) {
  246       return 0;
  247     }
  248     if (sunlink(path, options) < 0) {
  249       if (errno == EMLINK) {
  250     if (options & SRM_OPT_V) {
  251       error("%s has multiple links, this one has been unlinked but not overwritten", path);
  252     }
  253     return 1;
  254       }
  255       errorp("unable to remove %s", path);
  256       return 0;
  257     }
  258     return 1;
  259 
  260   default:
  261     error("unknown fts flag: %i", flag);
  262   }
  263   return 0;
  264 }
  265 
  266 #ifdef HAVE_FTS_OPEN
  267 
  268 /**
  269  * @param options bitfield of SRM_OPT_* bits
  270  * @return 0 if all files/directories could be removed; > 0 otherwise.
  271  */
  272 int tree_walker(char **trees, const int options)
  273 {
  274   FTSENT *current_file=0;
  275   FTS *stream=0;
  276   int i = 0, opt = FTS_PHYSICAL | FTS_NOCHDIR, ret = 0;
  277 
  278   if(!trees) return +1;
  279 
  280   /* remove trailing slashes free trees */
  281   while (trees[i] != NULL) {
  282     while (trees[i][strlen(trees[i]) - 1] == SRM_DIRSEP)
  283       trees[i][strlen(trees[i]) -1] = '\0';
  284     i++;
  285   }
  286 
  287   if(options & SRM_OPT_X)
  288     opt |= FTS_XDEV;
  289 
  290   if ( (stream = fts_open(trees, opt, NULL)) == NULL ) {
  291     errorp("fts_open() returned NULL");
  292     return +2;
  293   } else {
  294     while ( (current_file = fts_read(stream)) != NULL) {
  295       if (! process_file(current_file->fts_path, current_file->fts_info, options)) {
  296     ret = 1;
  297       }
  298       if ( !(options & SRM_OPT_R) )
  299     fts_set(stream, current_file, FTS_SKIP);
  300     }
  301     fts_close(stream);
  302   }
  303   return ret;
  304 }
  305 
  306 #elif HAVE_NFTW
  307 
  308 #if defined(__digital__) && defined(__unix__)
  309 /* Shut up tru64's cc(1) */
  310 #define _XOPEN_SOURCE_EXTENDED
  311 #endif
  312 
  313 #define _GNU_SOURCE
  314 #include <ftw.h>
  315 
  316 static int ftw_options;
  317 static int ftw_ret;
  318 
  319 /**
  320  * @return true if walking the FTS tree should continue; false otherwise.
  321  */
  322 static int ftw_process_path(const char *opath, const struct stat* statbuf, int flag, struct FTW* dummy)
  323 {
  324   size_t path_size;
  325   char *path;
  326   int ret = 0;
  327 
  328   (void)statbuf;
  329   (void)dummy;
  330 
  331   if(!opath) return 0;
  332 
  333   path_size = strlen(opath) + 1;
  334   path = (char *)alloca(path_size);
  335 
  336   if (path == NULL) {
  337     errno = ENOMEM;
  338     return 0;
  339   }
  340   strncpy(path, opath, path_size);
  341 
  342   switch (flag) {
  343   case FTW_F:
  344     ret = process_file(path, FTS_F, ftw_options);
  345     break;
  346   case FTW_SL:
  347     ret = process_file(path, FTS_SL, ftw_options);
  348     break;
  349   case FTW_SLN:
  350     ret = process_file(path, FTS_SLNONE, ftw_options);
  351     break;
  352   case FTW_D:
  353     ret = process_file(path, FTS_D, ftw_options);
  354     break;
  355   case FTW_DP:
  356     ret = process_file(path, FTS_DP, ftw_options);
  357     break;
  358   case FTW_DNR:
  359     ret = process_file(path, FTS_DNR, ftw_options);
  360     break;
  361   case FTW_NS:
  362     ret = process_file(path, FTS_NS, ftw_options);
  363     break;
  364   default:
  365     error("unknown nftw flag: %i", flag);
  366   }
  367   if (! ret) {
  368     ftw_ret = +1;
  369   }
  370   return 0;
  371 }
  372 
  373 /**
  374  * @param options bitfield of SRM_OPT_* bits
  375  * @return 0 if all files/directories could be removed; > 0 otherwise.
  376  */
  377 int tree_walker(char **trees, const int options)
  378 {
  379   int i = 0;
  380   int opt = 0;
  381 
  382   if(!trees) return +2;
  383   ftw_options = options;
  384   ftw_ret = 0;
  385 
  386   if(ftw_options & SRM_OPT_X)
  387     opt |= FTW_MOUNT;
  388   if(ftw_options & SRM_OPT_R)
  389     opt |= FTW_DEPTH|FTW_PHYS;
  390 
  391   while (trees[i] != NULL)
  392     {
  393       /* remove trailing slashes */
  394       while (trees[i][strlen(trees[i]) - 1] == SRM_DIRSEP)
  395     trees[i][strlen(trees[i]) -1] = '\0';
  396 
  397       nftw(trees[i], ftw_process_path, 10, opt);
  398       ++i;
  399     }
  400   return ftw_ret;
  401 }
  402 
  403 #elif defined(_WIN32)
  404 /* code is in win/tree.cpp */
  405 
  406 #else
  407 #error No tree traversal function found
  408 #endif