summaryrefslogtreecommitdiff
path: root/lib/fts.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2015-07-04 17:13:50 +0300
committerIgor Pashev <pashev.igor@gmail.com>2015-07-04 17:13:50 +0300
commit71cd8e3a743046573744123777061b64881bf372 (patch)
tree82522befe647f4fff186a5630cad0cad33f8ef53 /lib/fts.c
parentc18578632fd3c9e513e613a86ba2b7c4ebee6c45 (diff)
downloadcoreutils-upstream.tar.gz
Imported Upstream version 8.24upstream/8.24upstream
Diffstat (limited to 'lib/fts.c')
-rw-r--r--lib/fts.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/lib/fts.c b/lib/fts.c
index 500e92c6..a2f65eb8 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -1,6 +1,6 @@
/* Traverse a file hierarchy.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -62,6 +62,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
#endif
#include <fcntl.h>
#include <errno.h>
+#include <stdalign.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -189,7 +190,7 @@ enum Fts_stat
#endif
#ifdef NDEBUG
-# define fts_assert(expr) ((void) 0)
+# define fts_assert(expr) ((void) (0 && (expr)))
#else
# define fts_assert(expr) \
do \
@@ -1079,9 +1080,6 @@ cd_dot_dot:
}
} else if (p->fts_flags & FTS_SYMFOLLOW) {
if (FCHDIR(sp, p->fts_symfd)) {
- int saved_errno = errno;
- (void)close(p->fts_symfd);
- __set_errno (saved_errno);
p->fts_errno = errno;
SET(FTS_STOP);
}
@@ -1091,9 +1089,15 @@ cd_dot_dot:
p->fts_errno = errno;
SET(FTS_STOP);
}
- p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
- if (p->fts_errno == 0)
- LEAVE_DIR (sp, p, "3");
+
+ /* If the directory causes a cycle, preserve the FTS_DC flag and keep
+ the corresponding dev/ino pair in the hash table. It is going to be
+ removed when leaving the original directory. */
+ if (p->fts_info != FTS_DC) {
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ if (p->fts_errno == 0)
+ LEAVE_DIR (sp, p, "3");
+ }
return ISSET(FTS_STOP) ? NULL : p;
}
@@ -1293,6 +1297,7 @@ fts_build (register FTS *sp, int type)
int dir_fd;
FTSENT *cur = sp->fts_cur;
bool continue_readdir = !!cur->fts_dirp;
+ size_t max_entries;
/* When cur->fts_dirp is non-NULL, that means we should
continue calling readdir on that existing DIR* pointer
@@ -1354,8 +1359,7 @@ fts_build (register FTS *sp, int type)
function. But when no such function is specified, we can read
entries in batches that are large enough to help us with inode-
sorting, yet not so large that we risk exhausting memory. */
- size_t max_entries = (sp->fts_compar == NULL
- ? FTS_MAX_READDIR_ENTRIES : SIZE_MAX);
+ max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES;
/*
* Nlinks is the number of possible entries of type directory in the
@@ -1902,7 +1906,13 @@ fts_alloc (FTS *sp, const char *name, register size_t namelen)
* The file name is a variable length array. Allocate the FTSENT
* structure and the file name in one chunk.
*/
- len = sizeof(FTSENT) + namelen;
+ len = offsetof(FTSENT, fts_name) + namelen + 1;
+ /* Round the allocation up so it has the same alignment as FTSENT,
+ so that trailing padding may be referenced by direct access
+ to the flexible array members, without triggering undefined behavior
+ by accessing bytes beyond the heap allocation. This implicit access
+ was seen for example with ISDOT() and GCC 5.1.1 at -O2. */
+ len = (len + alignof(FTSENT) - 1) & ~(alignof(FTSENT) - 1);
if ((p = malloc(len)) == NULL)
return (NULL);