[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.7 and 1.12

version 1.7, 2015/02/07 07:42:56 version 1.12, 2016/10/18 23:58:12
Line 59  static void  fts_load(FTS *, FTSENT *);
Line 59  static void  fts_load(FTS *, FTSENT *);
 static size_t    fts_maxarglen(char * const *);  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 FTSENT   *fts_sort(FTS *, FTSENT *, int);
 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  #ifndef O_DIRECTORY
 #define O_DIRECTORY     0  #define O_DIRECTORY     0
 #endif  #endif
   #ifndef O_CLOEXEC
   #define O_CLOEXEC       0
   #endif
   #ifndef PATH_MAX
   #define PATH_MAX        4096
   #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,
       int (*compar)(const FTSENT **, const FTSENT **))
 {  {
         FTS *sp;          FTS *sp;
         FTSENT *p, *root;          FTSENT *p, *root;
         int nitems;          int nitems;
         FTSENT *parent, *tmp;          FTSENT *parent, *tmp;
         size_t len;  
   
         /* Options check. */          /* Options check. */
         if (options & ~FTS_OPTIONMASK) {          if (options & ~FTS_OPTIONMASK) {
Line 88  fts_open(char * const *argv, int options, void *dummy)
Line 92  fts_open(char * const *argv, int options, void *dummy)
                 return (NULL);                  return (NULL);
         }          }
   
           /* At least one path must be specified. */
           if (*argv == NULL) {
                   errno = EINVAL;
                   return (NULL);
           }
   
         /* Allocate/initialize the stream */          /* Allocate/initialize the stream */
         if ((sp = calloc(1, sizeof(FTS))) == NULL)          if ((sp = calloc(1, sizeof(FTS))) == NULL)
                 return (NULL);                  return (NULL);
           sp->fts_compar = compar;
         sp->fts_options = options;          sp->fts_options = options;
   
         /*          /*
Line 107  fts_open(char * const *argv, int options, void *dummy)
Line 118  fts_open(char * const *argv, int options, void *dummy)
   
         /* Allocate/initialize root(s). */          /* Allocate/initialize root(s). */
         for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {          for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
                 /* Don't allow zero-length paths. */                  if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL)
                 if ((len = strlen(*argv)) == 0) {  
                         errno = ENOENT;  
                         goto mem3;                          goto mem3;
                 }  
   
                 if ((p = fts_alloc(sp, *argv, len)) == NULL)  
                         goto mem3;  
                 p->fts_level = FTS_ROOTLEVEL;                  p->fts_level = FTS_ROOTLEVEL;
                 p->fts_parent = parent;                  p->fts_parent = parent;
                 p->fts_accpath = p->fts_name;                  p->fts_accpath = p->fts_name;
Line 124  fts_open(char * const *argv, int options, void *dummy)
Line 129  fts_open(char * const *argv, int options, void *dummy)
                 if (p->fts_info == FTS_DOT)                  if (p->fts_info == FTS_DOT)
                         p->fts_info = FTS_D;                          p->fts_info = FTS_D;
   
                 p->fts_link = NULL;                  /*
                 if (root == NULL)                   * If comparison routine supplied, traverse in sorted
                         tmp = root = p;                   * order; otherwise traverse in the order specified.
                 else {                   */
                         tmp->fts_link = p;                  if (compar) {
                         tmp = p;                          p->fts_link = root;
                           root = p;
                   } else {
                           p->fts_link = NULL;
                           if (root == NULL)
                                   tmp = root = p;
                           else {
                                   tmp->fts_link = p;
                                   tmp = p;
                           }
                 }                  }
         }          }
           if (compar && nitems > 1)
                   root = fts_sort(sp, root, nitems);
   
         /*          /*
          * Allocate a dummy pointer and make fts_read think that we've just           * Allocate a dummy pointer and make fts_read think that we've just
Line 143  fts_open(char * const *argv, int options, void *dummy)
Line 159  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 | O_CLOEXEC)) < 0)  
                 SET(FTS_NOCHDIR);  
   
         if (nitems == 0)          if (nitems == 0)
                 free(parent);                  free(parent);
   
Line 194  int
Line 199  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 210  fts_close(FTS *sp)
Line 214  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_array);
         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 271  fts_read(FTS *sp)
Line 264  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 310  next: tmp = p;
Line 289  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 349  name:  t = sp->fts_path + NAPPEND(p->fts_parent);
Line 324  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 376  name:  t = sp->fts_path + NAPPEND(p->fts_parent);
Line 334  name:  t = sp->fts_path + NAPPEND(p->fts_parent);
  * semantics to fts using fts_set.  An error return is allowed for similar   * semantics to fts using fts_set.  An error return is allowed for similar
  * reasons.   * reasons.
  */   */
 /* ARGSUSED */  
 int  int
 fts_set(FTS *sp, FTSENT *p, int instr)  fts_set(FTS *sp, FTSENT *p, int instr)
 {  {
Line 411  fts_build(FTS *sp)
Line 368  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, doadjust;          int nitems, level, doadjust;
         int saved_errno;          int saved_errno;
         char *cp;          char *cp;
   
Line 429  fts_build(FTS *sp)
Line 386  fts_build(FTS *sp)
         }          }
   
         /*          /*
          * 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)) {  
                 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 465  fts_build(FTS *sp)
Line 396  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 503  fts_build(FTS *sp)
Line 432  fts_build(FTS *sp)
                                  * structures already allocated.                                   * structures already allocated.
                                  */                                   */
 mem1:                           saved_errno = errno;  mem1:                           saved_errno = errno;
                                 if (p)                                  free(p);
                                         free(p);  
                                 fts_lfree(head);                                  fts_lfree(head);
                                 (void)closedir(dirp);                                  (void)closedir(dirp);
                                 cur->fts_info = FTS_ERR;                                  cur->fts_info = FTS_ERR;
Line 515  mem1:    saved_errno = errno;
Line 443  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 539  mem1:    saved_errno = errno;
Line 466  mem1:    saved_errno = errno;
                         return (NULL);                          return (NULL);
                 }                  }
   
                 if (cderrno) {                  /* Build a file name for fts_stat to stat. */
                         p->fts_info = FTS_NS;                  p->fts_accpath = p->fts_path;
                         p->fts_errno = cderrno;                  memmove(cp, p->fts_name, p->fts_namelen + 1);
                         p->fts_accpath = cur->fts_accpath;                  /* Stat it. */
                 } else {                  p->fts_info = fts_stat(sp, p);
                         /* 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);  
                 }  
   
                 /* 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;
Line 578  mem1:    saved_errno = errno;
Line 496  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;
                 return (NULL);                  return (NULL);
         }          }
   
           /* Sort the entries. */
           if (sp->fts_compar && nitems > 1)
                   head = fts_sort(sp, head, nitems);
         return (head);          return (head);
 }  }
   
Line 661  fts_stat(FTS *sp, FTSENT *p)
Line 566  fts_stat(FTS *sp, FTSENT *p)
 }  }
   
 static FTSENT *  static FTSENT *
   fts_sort(FTS *sp, FTSENT *head, int nitems)
   {
           FTSENT **ap, *p;
   
           /*
            * Construct an array of pointers to the structures and call qsort(3).
            * Reassemble the array in the order returned by qsort.  If unable to
            * sort for memory reasons, return the directory entries in their
            * current order.  Allocate enough space for the current needs plus
            * 40 so don't realloc one entry at a time.
            */
           if (nitems > sp->fts_nitems) {
                   struct _ftsent **a;
   
                   sp->fts_nitems = nitems + 40;
                   if ((a = reallocarray(sp->fts_array,
                       sp->fts_nitems, sizeof(FTSENT *))) == NULL) {
                           free(sp->fts_array);
                           sp->fts_array = NULL;
                           sp->fts_nitems = 0;
                           return (head);
                   }
                   sp->fts_array = a;
           }
           for (ap = sp->fts_array, p = head; p; p = p->fts_link)
                   *ap++ = p;
           qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
           for (head = *(ap = sp->fts_array); --nitems; ++ap)
                   ap[0]->fts_link = ap[1];
           ap[0]->fts_link = NULL;
           return (head);
   }
   
   static FTSENT *
 fts_alloc(FTS *sp, const char *name, size_t namelen)  fts_alloc(FTS *sp, const char *name, size_t namelen)
 {  {
         FTSENT *p;          FTSENT *p;
Line 711  fts_palloc(FTS *sp, size_t more)
Line 650  fts_palloc(FTS *sp, size_t more)
          */           */
         more += 256;          more += 256;
         if (sp->fts_pathlen + more < sp->fts_pathlen) {          if (sp->fts_pathlen + more < sp->fts_pathlen) {
                 if (sp->fts_path)                  free(sp->fts_path);
                         free(sp->fts_path);  
                 sp->fts_path = NULL;                  sp->fts_path = NULL;
                 errno = ENAMETOOLONG;                  errno = ENAMETOOLONG;
                 return (1);                  return (1);
Line 720  fts_palloc(FTS *sp, size_t more)
Line 658  fts_palloc(FTS *sp, size_t more)
         sp->fts_pathlen += more;          sp->fts_pathlen += more;
         p = realloc(sp->fts_path, sp->fts_pathlen);          p = realloc(sp->fts_path, sp->fts_pathlen);
         if (p == NULL) {          if (p == NULL) {
                 if (sp->fts_path)                  free(sp->fts_path);
                         free(sp->fts_path);  
                 sp->fts_path = NULL;                  sp->fts_path = NULL;
                 return (1);                  return (1);
         }          }
Line 766  fts_maxarglen(char * const *argv)
Line 703  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|O_DIRECTORY|O_CLOEXEC)) < 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.7  
changed lines
  Added in v.1.12

CVSweb