[BACK]Return to compat_fts.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/compat_fts.c between version 1.4 and 1.9

version 1.4, 2014/08/17 20:45:59 version 1.9, 2015/03/18 19:29:48
Line 38  int dummy;
Line 38  int dummy;
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 #include <sys/param.h>  
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/types.h>  #include <sys/types.h>
   
Line 51  int dummy;
Line 50  int dummy;
 #include <unistd.h>  #include <unistd.h>
 #include "compat_fts.h"  #include "compat_fts.h"
   
   #define MAXIMUM(a, b)   (((a) > (b)) ? (a) : (b))
   
 static FTSENT   *fts_alloc(FTS *, const char *, size_t);  static FTSENT   *fts_alloc(FTS *, const char *, size_t);
 static FTSENT   *fts_build(FTS *);  static FTSENT   *fts_build(FTS *);
 static void      fts_lfree(FTSENT *);  static void      fts_lfree(FTSENT *);
Line 59  static size_t  fts_maxarglen(char * const *);
Line 60  static size_t  fts_maxarglen(char * const *);
 static void      fts_padjust(FTS *, FTSENT *);  static void      fts_padjust(FTS *, FTSENT *);
 static int       fts_palloc(FTS *, size_t);  static int       fts_palloc(FTS *, size_t);
 static unsigned short    fts_stat(FTS *, FTSENT *);  static unsigned short    fts_stat(FTS *, FTSENT *);
 static int       fts_safe_changedir(FTS *, FTSENT *, int, const char *);  
   
 #define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))  #define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
   #ifndef O_DIRECTORY
   #define O_DIRECTORY     0
   #endif
   #ifndef O_CLOEXEC
   #define O_CLOEXEC       0
   #endif
   
 #define CLR(opt)        (sp->fts_options &= ~(opt))  #define CLR(opt)        (sp->fts_options &= ~(opt))
 #define ISSET(opt)      (sp->fts_options & (opt))  #define ISSET(opt)      (sp->fts_options & (opt))
 #define SET(opt)        (sp->fts_options |= (opt))  #define SET(opt)        (sp->fts_options |= (opt))
   
 #define FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))  
   
 FTS *  FTS *
 fts_open(char * const *argv, int options, void *dummy)  fts_open(char * const *argv, int options, void *dummy)
 {  {
Line 93  fts_open(char * const *argv, int options, void *dummy)
Line 97  fts_open(char * const *argv, int options, void *dummy)
          * Start out with 1K of path space, and enough, in any case,           * Start out with 1K of path space, and enough, in any case,
          * to hold the user's paths.           * to hold the user's paths.
          */           */
         if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX)))          if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX)))
                 goto mem1;                  goto mem1;
   
         /* Allocate/initialize root's parent. */          /* Allocate/initialize root's parent. */
Line 139  fts_open(char * const *argv, int options, void *dummy)
Line 143  fts_open(char * const *argv, int options, void *dummy)
         sp->fts_cur->fts_link = root;          sp->fts_cur->fts_link = root;
         sp->fts_cur->fts_info = FTS_INIT;          sp->fts_cur->fts_info = FTS_INIT;
   
         /*  
          * If using chdir(2), grab a file descriptor pointing to dot to ensure  
          * that we can get back here; this could be avoided for some paths,  
          * but almost certainly not worth the effort.  Slashes, symbolic links,  
          * and ".." are all fairly nasty problems.  Note, if we can't get the  
          * descriptor we run anyway, just more slowly.  
          */  
         if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)  
                 SET(FTS_NOCHDIR);  
   
         if (nitems == 0)          if (nitems == 0)
                 free(parent);                  free(parent);
   
Line 189  int
Line 183  int
 fts_close(FTS *sp)  fts_close(FTS *sp)
 {  {
         FTSENT *freep, *p;          FTSENT *freep, *p;
         int rfd, error = 0;  
   
         /*          /*
          * This still works if we haven't read anything -- the dummy structure           * This still works if we haven't read anything -- the dummy structure
Line 205  fts_close(FTS *sp)
Line 198  fts_close(FTS *sp)
                 free(p);                  free(p);
         }          }
   
         /* Stash the original directory fd if needed. */  
         rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd;  
   
         /* Free up child linked list, sort array, path buffer, stream ptr.*/          /* Free up child linked list, sort array, path buffer, stream ptr.*/
         if (sp->fts_child)          if (sp->fts_child)
                 fts_lfree(sp->fts_child);                  fts_lfree(sp->fts_child);
         free(sp->fts_path);          free(sp->fts_path);
         free(sp);          free(sp);
   
         /* Return to original directory, checking for error. */          return (0);
         if (rfd != -1) {  
                 int saved_errno;  
                 error = fchdir(rfd);  
                 saved_errno = errno;  
                 (void)close(rfd);  
                 errno = saved_errno;  
         }  
   
         return (error);  
 }  }
   
 /*  /*
Line 266  fts_read(FTS *sp)
Line 247  fts_read(FTS *sp)
                 }                  }
   
                 /*                  /*
                  * Cd to the subdirectory.  
                  *  
                  * If have already read and now fail to chdir, whack the list  
                  * to make the names come out right, and set the parent errno  
                  * so the application will eventually get an error condition.  
                  * Set the FTS_DONTCHDIR flag so that when we logically change  
                  * directories back to the parent we don't do a chdir.  
                  *  
                  * If haven't read do so.  If the read fails, fts_build sets                   * If haven't read do so.  If the read fails, fts_build sets
                  * FTS_STOP or the fts_info field of the node.                   * FTS_STOP or the fts_info field of the node.
                  */                   */
                 if (sp->fts_child) {                  if (sp->fts_child) {
                         if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {                          /* nothing */
                                 p->fts_errno = errno;  
                                 p->fts_flags |= FTS_DONTCHDIR;  
                                 for (p = sp->fts_child; p; p = p->fts_link)  
                                         p->fts_accpath =  
                                             p->fts_parent->fts_accpath;  
                         }  
                 } else if ((sp->fts_child = fts_build(sp)) == NULL) {                  } else if ((sp->fts_child = fts_build(sp)) == NULL) {
                         if (ISSET(FTS_STOP))                          if (ISSET(FTS_STOP))
                                 return (NULL);                                  return (NULL);
Line 305  next: tmp = p;
Line 272  next: tmp = p;
                  * the root of the tree), and load the paths for the next root.                   * the root of the tree), and load the paths for the next root.
                  */                   */
                 if (p->fts_level == FTS_ROOTLEVEL) {                  if (p->fts_level == FTS_ROOTLEVEL) {
                         if (FCHDIR(sp, sp->fts_rfd)) {  
                                 SET(FTS_STOP);  
                                 return (NULL);  
                         }  
                         fts_load(sp, p);                          fts_load(sp, p);
                         return (sp->fts_cur = p);                          return (sp->fts_cur = p);
                 }                  }
Line 344  name:  t = sp->fts_path + NAPPEND(p->fts_parent);
Line 307  name:  t = sp->fts_path + NAPPEND(p->fts_parent);
         /* NUL terminate the pathname. */          /* NUL terminate the pathname. */
         sp->fts_path[p->fts_pathlen] = '\0';          sp->fts_path[p->fts_pathlen] = '\0';
   
         /*  
          * Return to the parent directory.  If at a root node or came through  
          * a symlink, go back through the file descriptor.  Otherwise, cd up  
          * one directory.  
          */  
         if (p->fts_level == FTS_ROOTLEVEL) {  
                 if (FCHDIR(sp, sp->fts_rfd)) {  
                         SET(FTS_STOP);  
                         sp->fts_cur = p;  
                         return (NULL);  
                 }  
         } else if (!(p->fts_flags & FTS_DONTCHDIR) &&  
             fts_safe_changedir(sp, p->fts_parent, -1, "..")) {  
                 SET(FTS_STOP);  
                 sp->fts_cur = p;  
                 return (NULL);  
         }  
         p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;          p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
         return (sp->fts_cur = p);          return (sp->fts_cur = p);
 }  }
Line 406  fts_build(FTS *sp)
Line 352  fts_build(FTS *sp)
         DIR *dirp;          DIR *dirp;
         void *oldaddr;          void *oldaddr;
         size_t dlen, len, maxlen;          size_t dlen, len, maxlen;
         int nitems, cderrno, descend, level, nlinks, nostat, doadjust;          int nitems, level, doadjust;
         int saved_errno;          int saved_errno;
         char *cp;          char *cp;
   
Line 424  fts_build(FTS *sp)
Line 370  fts_build(FTS *sp)
         }          }
   
         /*          /*
          * Nlinks is the number of possible entries of type directory in the  
          * directory if we're cheating on stat calls, 0 if we're not doing  
          * any stat calls at all, -1 if we're doing stats on everything.  
          */  
         nlinks = -1;  
         nostat = 0;  
   
         /*  
          * If we're going to need to stat anything or we want to descend  
          * and stay in the directory, chdir.  If this fails we keep going,  
          * but set a flag so we don't chdir after the post-order visit.  
          * We won't be able to stat anything, but we can still return the  
          * names themselves.  Note, that since fts_read won't be able to  
          * chdir into the directory, it will have to return different path  
          * names than before, i.e. "a/b" instead of "b".  Since the node  
          * has already been visited in pre-order, have to wait until the  
          * post-order visit to return the error.  There is a special case  
          * here, if there was nothing to stat then it's not an error to  
          * not be able to stat.  This is all fairly nasty.  If a program  
          * needed sorted entries or stat information, they had better be  
          * checking FTS_NS on the returned nodes.  
          */  
         cderrno = 0;  
         if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {  
                 if (nlinks)  
                         cur->fts_errno = errno;  
                 cur->fts_flags |= FTS_DONTCHDIR;  
                 descend = 0;  
                 cderrno = errno;  
                 (void)closedir(dirp);  
                 dirp = NULL;  
         } else  
                 descend = 1;  
   
         /*  
          * Figure out the max file name length that can be stored in the           * Figure out the max file name length that can be stored in the
          * current path -- the inner loop allocates more path as necessary.           * current path -- the inner loop allocates more path as necessary.
          * We really wouldn't have to do the maxlen calculations here, we           * We really wouldn't have to do the maxlen calculations here, we
Line 469  fts_build(FTS *sp)
Line 380  fts_build(FTS *sp)
          * each new name into the path.           * each new name into the path.
          */           */
         len = NAPPEND(cur);          len = NAPPEND(cur);
         if (ISSET(FTS_NOCHDIR)) {          cp = sp->fts_path + len;
                 cp = sp->fts_path + len;          *cp++ = '/';
                 *cp++ = '/';  
         }  
         len++;          len++;
         maxlen = sp->fts_pathlen - len;          maxlen = sp->fts_pathlen - len;
   
Line 519  mem1:    saved_errno = errno;
Line 428  mem1:    saved_errno = errno;
                         /* Did realloc() change the pointer? */                          /* Did realloc() change the pointer? */
                         if (oldaddr != sp->fts_path) {                          if (oldaddr != sp->fts_path) {
                                 doadjust = 1;                                  doadjust = 1;
                                 if (ISSET(FTS_NOCHDIR))                                  cp = sp->fts_path + len;
                                         cp = sp->fts_path + len;  
                         }                          }
                         maxlen = sp->fts_pathlen - len;                          maxlen = sp->fts_pathlen - len;
                 }                  }
Line 543  mem1:    saved_errno = errno;
Line 451  mem1:    saved_errno = errno;
                         return (NULL);                          return (NULL);
                 }                  }
   
                 if (cderrno) {                  /* Build a file name for fts_stat to stat. */
                         if (nlinks) {                  p->fts_accpath = p->fts_path;
                                 p->fts_info = FTS_NS;                  memmove(cp, p->fts_name, p->fts_namelen + 1);
                                 p->fts_errno = cderrno;                  /* Stat it. */
                         } else                  p->fts_info = fts_stat(sp, p);
                                 p->fts_info = FTS_NSOK;  
                         p->fts_accpath = cur->fts_accpath;  
                 } else if (nlinks == 0  
 #ifdef DT_DIR  
                     || (nostat &&  
                     dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)  
 #endif  
                     ) {  
                         p->fts_accpath =  
                             ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;  
                         p->fts_info = FTS_NSOK;  
                 } else {  
                         /* Build a file name for fts_stat to stat. */  
                         if (ISSET(FTS_NOCHDIR)) {  
                                 p->fts_accpath = p->fts_path;  
                                 memmove(cp, p->fts_name, p->fts_namelen + 1);  
                         } else  
                                 p->fts_accpath = p->fts_name;  
                         /* Stat it. */  
                         p->fts_info = fts_stat(sp, p);  
   
                         /* Decrement link count if applicable. */  
                         if (nlinks > 0 && (p->fts_info == FTS_D ||  
                             p->fts_info == FTS_DC || p->fts_info == FTS_DOT))  
                                 --nlinks;  
                 }  
   
                 /* We walk in directory order so "ls -f" doesn't get upset. */                  /* We walk in directory order so "ls -f" doesn't get upset. */
                 p->fts_link = NULL;                  p->fts_link = NULL;
                 if (head == NULL)                  if (head == NULL)
Line 599  mem1:    saved_errno = errno;
Line 481  mem1:    saved_errno = errno;
          * If not changing directories, reset the path back to original           * If not changing directories, reset the path back to original
          * state.           * state.
          */           */
         if (ISSET(FTS_NOCHDIR)) {          if (len == sp->fts_pathlen || nitems == 0)
                 if (len == sp->fts_pathlen || nitems == 0)                  --cp;
                         --cp;          *cp = '\0';
                 *cp = '\0';  
         }  
   
         /*  
          * If descended after called from fts_children or after called from  
          * fts_read and nothing found, get back.  At the root level we use  
          * the saved fd; if one of fts_open()'s arguments is a relative path  
          * to an empty directory, we wind up here with no other way back.  If  
          * can't get back, we're done.  
          */  
         if (descend && !nitems &&  
             (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :  
             fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {  
                 cur->fts_info = FTS_ERR;  
                 SET(FTS_STOP);  
                 return (NULL);  
         }  
   
         /* If didn't find anything, return NULL. */          /* If didn't find anything, return NULL. */
         if (!nitems) {          if (!nitems) {
                 cur->fts_info = FTS_DP;                  cur->fts_info = FTS_DP;
Line 787  fts_maxarglen(char * const *argv)
Line 652  fts_maxarglen(char * const *argv)
                 if ((len = strlen(*argv)) > max)                  if ((len = strlen(*argv)) > max)
                         max = len;                          max = len;
         return (max + 1);          return (max + 1);
 }  
   
 /*  
  * Change to dir specified by fd or p->fts_accpath without getting  
  * tricked by someone changing the world out from underneath us.  
  * Assumes p->fts_dev and p->fts_ino are filled in.  
  */  
 static int  
 fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)  
 {  
         int ret, oerrno, newfd;  
         struct stat sb;  
   
         newfd = fd;  
         if (ISSET(FTS_NOCHDIR))  
                 return (0);  
         if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)  
                 return (-1);  
         if (fstat(newfd, &sb)) {  
                 ret = -1;  
                 goto bail;  
         }  
         if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {  
                 errno = ENOENT;         /* disinformation */  
                 ret = -1;  
                 goto bail;  
         }  
         ret = fchdir(newfd);  
 bail:  
         oerrno = errno;  
         if (fd < 0)  
                 (void)close(newfd);  
         errno = oerrno;  
         return (ret);  
 }  }
   
 #endif  #endif

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.9

CVSweb