]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blobdiff - libc/bionic/fts.c
Sync with upstream OpenBSD fts.c.
[android-sdk/platform-bionic.git] / libc / bionic / fts.c
index c7770b6b63b0cb83deda023391162c449f172b2c..31a4b2ff504a7653ac3120a30d36fd36f82bb9ce 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fts.c,v 1.43 2009/08/27 16:19:27 millert Exp $        */
+/*     $OpenBSD: fts.c,v 1.48 2014/11/20 04:14:15 guenther Exp $       */
 
 /*-
  * Copyright (c) 1990, 1993, 1994
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#define MAX(a,b) ((a)>(b)?(a):(b))
-
 static FTSENT  *fts_alloc(FTS *, char *, size_t);
 static FTSENT  *fts_build(FTS *, int);
 static void     fts_lfree(FTSENT *);
@@ -50,9 +49,13 @@ static size_t         fts_maxarglen(char * const *);
 static void     fts_padjust(FTS *, FTSENT *);
 static int      fts_palloc(FTS *, size_t);
 static FTSENT  *fts_sort(FTS *, FTSENT *, int);
-static u_short  fts_stat(FTS *, FTSENT *, int);
+static u_short  fts_stat(FTS *, FTSENT *, int, int);
 static int      fts_safe_changedir(FTS *, FTSENT *, int, char *);
 
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+void* reallocarray(void*, size_t, size_t);
+
 #define        ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
 
 #define        CLR(opt)        (sp->fts_options &= ~(opt))
@@ -96,7 +99,7 @@ fts_open(char * const *argv, int options,
         * Start out with 1K of path space, and enough, in any case,
         * to hold the user's paths.
         */
-       if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+       if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX)))
                goto mem1;
 
        /* Allocate/initialize root's parent. */
@@ -117,7 +120,7 @@ fts_open(char * const *argv, int options,
                p->fts_level = FTS_ROOTLEVEL;
                p->fts_parent = parent;
                p->fts_accpath = p->fts_name;
-               p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
+               p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
 
                /* Command-line "." and ".." are real directories. */
                if (p->fts_info == FTS_DOT)
@@ -271,7 +274,7 @@ fts_read(FTS *sp)
 
        /* Any type of file may be re-visited; re-stat and re-turn. */
        if (instr == FTS_AGAIN) {
-               p->fts_info = fts_stat(sp, p, 0);
+               p->fts_info = fts_stat(sp, p, 0, -1);
                return (p);
        }
 
@@ -283,7 +286,7 @@ fts_read(FTS *sp)
         */
        if (instr == FTS_FOLLOW &&
            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
-               p->fts_info = fts_stat(sp, p, 1);
+               p->fts_info = fts_stat(sp, p, 1, -1);
                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
                        if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
                                p->fts_errno = errno;
@@ -372,7 +375,7 @@ next:       tmp = p;
                if (p->fts_instr == FTS_SKIP)
                        goto next;
                if (p->fts_instr == FTS_FOLLOW) {
-                       p->fts_info = fts_stat(sp, p, 1);
+                       p->fts_info = fts_stat(sp, p, 1, -1);
                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
                                if ((p->fts_symfd =
                                    open(".", O_RDONLY, 0)) < 0) {
@@ -446,7 +449,7 @@ name:               t = sp->fts_path + NAPPEND(p->fts_parent);
  */
 /* ARGSUSED */
 int
-fts_set(FTS *sp, FTSENT *p, int instr)
+fts_set(FTS *sp __unused, FTSENT *p, int instr)
 {
        if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
            instr != FTS_NOINSTR && instr != FTS_SKIP) {
@@ -636,7 +639,7 @@ fts_build(FTS *sp, int type)
        maxlen = sp->fts_pathlen - len;
 
        /*
-        * fts_level is a short so we must prevent it from wrapping
+        * fts_level is signed so we must prevent it from wrapping
         * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
         */
        level = cur->fts_level;
@@ -717,10 +720,11 @@ mem1:                             saved_errno = errno;
                        if (ISSET(FTS_NOCHDIR)) {
                                p->fts_accpath = p->fts_path;
                                memmove(cp, p->fts_name, p->fts_namelen + 1);
-                       } else
+                               p->fts_info = fts_stat(sp, p, 0, dirfd(dirp));
+                       } else {
                                p->fts_accpath = p->fts_name;
-                       /* Stat it. */
-                       p->fts_info = fts_stat(sp, p, 0);
+                               p->fts_info = fts_stat(sp, p, 0, -1);
+                       }
 
                        /* Decrement link count if applicable. */
                        if (nlinks > 0 && (p->fts_info == FTS_D ||
@@ -787,13 +791,20 @@ mem1:                             saved_errno = errno;
 }
 
 static u_short
-fts_stat(FTS *sp, FTSENT *p, int follow)
+fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
 {
        FTSENT *t;
        dev_t dev;
        ino_t ino;
        struct stat *sbp, sb;
        int saved_errno;
+       const char *path;
+
+       if (dfd == -1) {
+               path = p->fts_accpath;
+               dfd = AT_FDCWD;
+       } else
+               path = p->fts_name;
 
        /* If user needs stat info, stat buffer already allocated. */
        sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
@@ -804,16 +815,16 @@ fts_stat(FTS *sp, FTSENT *p, int follow)
         * fail, set the errno from the stat call.
         */
        if (ISSET(FTS_LOGICAL) || follow) {
-               if (stat(p->fts_accpath, sbp)) {
+               if (fstatat(dfd, path, sbp, 0)) {
                        saved_errno = errno;
-                       if (!lstat(p->fts_accpath, sbp)) {
+                       if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
                                errno = 0;
                                return (FTS_SLNONE);
                        }
                        p->fts_errno = saved_errno;
                        goto err;
                }
-       } else if (lstat(p->fts_accpath, sbp)) {
+       } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
                p->fts_errno = errno;
 err:           memset(sbp, 0, sizeof(struct stat));
                return (FTS_NS);
@@ -871,8 +882,8 @@ fts_sort(FTS *sp, FTSENT *head, int nitems)
                struct _ftsent **a;
 
                sp->fts_nitems = nitems + 40;
-               if ((a = realloc(sp->fts_array,
-                   sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
+               if ((a = reallocarray(sp->fts_array,
+                   sp->fts_nitems, sizeof(FTSENT *))) == NULL) {
                        if (sp->fts_array)
                                free(sp->fts_array);
                        sp->fts_array = NULL;
@@ -907,10 +918,9 @@ fts_alloc(FTS *sp, char *name, size_t namelen)
        len = sizeof(FTSENT) + namelen;
        if (!ISSET(FTS_NOSTAT))
                len += sizeof(struct stat) + ALIGNBYTES;
-       if ((p = malloc(len)) == NULL)
+       if ((p = calloc(1, len)) == NULL)
                return (NULL);
 
-       memset(p, 0, len);
        p->fts_path = sp->fts_path;
        p->fts_namelen = namelen;
        p->fts_instr = FTS_NOINSTR;
@@ -935,7 +945,7 @@ fts_lfree(FTSENT *head)
 
 /*
  * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
- * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * Most systems will allow creation of paths much longer than PATH_MAX, even
  * though the kernel won't resolve them.  Add the size (not just what's needed)
  * plus 256 bytes so don't realloc the path 2 bytes at a time.
  */