fts: Roll up changes from FreeBSD.
Notable changes include: * fts: Stat things relative to the directory fd, if possible. * fts: Fix double-free with conflicting concurrent modifications. * fts: Don't abort if an empty pathname is given. * fts: Don't return FTS_SLNONE if it's not a symlink (if race). * fts_children: preserve errno after running close/fchdir * Use ANSI C prototypes. Eliminates -Wold-style-definition warnings. * fts: Fix a potential memory leak in error case * libc: Check for readdir(2) errors in fts(3)
This commit is contained in:
+132
-141
@@ -1,4 +1,6 @@
|
|||||||
/*-
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
* Copyright (c) 1990, 1993, 1994
|
* Copyright (c) 1990, 1993, 1994
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
*
|
*
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
* may be used to endorse or promote products derived from this software
|
* may be used to endorse or promote products derived from this software
|
||||||
* without specific prior written permission.
|
* without specific prior written permission.
|
||||||
*
|
*
|
||||||
@@ -29,12 +31,6 @@
|
|||||||
* $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
|
* $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if 0
|
|
||||||
#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
|
||||||
#endif /* LIBC_SCCS and not lint */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
@@ -49,6 +45,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#else
|
#else
|
||||||
|
__SCCSID("@(#)fts.c 8.6 (Berkeley) 8/14/94");
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
@@ -76,22 +73,10 @@ 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 *, size_t);
|
static FTSENT *fts_sort(FTS *, FTSENT *, size_t);
|
||||||
static int fts_stat(FTS *, FTSENT *, int);
|
static int fts_stat(FTS *, FTSENT *, int, int);
|
||||||
static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
|
static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
|
||||||
static int fts_ufslinks(FTS *, const FTSENT *);
|
static int fts_ufslinks(FTS *, const FTSENT *);
|
||||||
|
|
||||||
|
|
||||||
FTS * __fts_open(char * const *argv, int options, int (*compar)(
|
|
||||||
const FTSENT * const *, const FTSENT * const *));
|
|
||||||
int __fts_close(FTS *sp);
|
|
||||||
FTSENT * __fts_read(FTS *sp);
|
|
||||||
int __fts_set(FTS *sp, FTSENT *p, int instr);
|
|
||||||
FTSENT * __fts_children(FTS *sp, int instr);
|
|
||||||
void *(__fts_get_clientptr)(FTS *sp);
|
|
||||||
FTS * (__fts_get_stream)(FTSENT *p);
|
|
||||||
void __fts_set_clientptr(FTS *sp, void *clientptr);
|
|
||||||
|
|
||||||
|
|
||||||
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
|
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
|
||||||
|
|
||||||
#define CLR(opt) (sp->fts_options &= ~(opt))
|
#define CLR(opt) (sp->fts_options &= ~(opt))
|
||||||
@@ -133,17 +118,28 @@ static const char *ufslike_filesystems[] = {
|
|||||||
"ufs",
|
"ufs",
|
||||||
"zfs",
|
"zfs",
|
||||||
"nfs",
|
"nfs",
|
||||||
"nfs4",
|
|
||||||
"ext2fs",
|
"ext2fs",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
#endif /* !__HAIKU__ */
|
#endif /* !__HAIKU__ */
|
||||||
|
|
||||||
|
#ifdef __HAIKU__
|
||||||
|
static void *
|
||||||
|
reallocf(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
void *nptr;
|
||||||
|
|
||||||
|
nptr = realloc(ptr, size);
|
||||||
|
|
||||||
|
if (!nptr)
|
||||||
|
free(ptr);
|
||||||
|
return (nptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
FTS *
|
FTS *
|
||||||
__fts_open(argv, options, compar)
|
fts_open(char * const *argv, int options,
|
||||||
char * const *argv;
|
int (*compar)(const FTSENT * const *, const FTSENT * const *))
|
||||||
int options;
|
|
||||||
int (*compar)(const FTSENT * const *, const FTSENT * const *);
|
|
||||||
{
|
{
|
||||||
struct _fts_private *priv;
|
struct _fts_private *priv;
|
||||||
FTS *sp;
|
FTS *sp;
|
||||||
@@ -170,9 +166,6 @@ __fts_open(argv, options, compar)
|
|||||||
sp->fts_compar = compar;
|
sp->fts_compar = compar;
|
||||||
sp->fts_options = options;
|
sp->fts_options = options;
|
||||||
|
|
||||||
/* Shush, GCC. */
|
|
||||||
tmp = NULL;
|
|
||||||
|
|
||||||
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
|
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
|
||||||
if (ISSET(FTS_LOGICAL))
|
if (ISSET(FTS_LOGICAL))
|
||||||
SET(FTS_NOCHDIR);
|
SET(FTS_NOCHDIR);
|
||||||
@@ -189,19 +182,18 @@ __fts_open(argv, options, compar)
|
|||||||
goto mem2;
|
goto mem2;
|
||||||
parent->fts_level = FTS_ROOTPARENTLEVEL;
|
parent->fts_level = FTS_ROOTPARENTLEVEL;
|
||||||
|
|
||||||
|
/* Shush, GCC. */
|
||||||
|
tmp = NULL;
|
||||||
|
|
||||||
/* Allocate/initialize root(s). */
|
/* Allocate/initialize root(s). */
|
||||||
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
|
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
|
||||||
/* Don't allow zero-length paths. */
|
len = strlen(*argv);
|
||||||
if ((len = strlen(*argv)) == 0) {
|
|
||||||
errno = ENOENT;
|
|
||||||
goto mem3;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = fts_alloc(sp, *argv, len);
|
p = fts_alloc(sp, *argv, len);
|
||||||
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;
|
||||||
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. */
|
/* Command-line "." and ".." are real directories. */
|
||||||
if (p->fts_info == FTS_DOT)
|
if (p->fts_info == FTS_DOT)
|
||||||
@@ -245,7 +237,7 @@ __fts_open(argv, options, compar)
|
|||||||
* descriptor we run anyway, just more slowly.
|
* descriptor we run anyway, just more slowly.
|
||||||
*/
|
*/
|
||||||
if (!ISSET(FTS_NOCHDIR) &&
|
if (!ISSET(FTS_NOCHDIR) &&
|
||||||
(sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
|
(sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
|
||||||
SET(FTS_NOCHDIR);
|
SET(FTS_NOCHDIR);
|
||||||
|
|
||||||
return (sp);
|
return (sp);
|
||||||
@@ -257,10 +249,6 @@ mem1: free(sp);
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_open, fts_open);
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fts_load(FTS *sp, FTSENT *p)
|
fts_load(FTS *sp, FTSENT *p)
|
||||||
{
|
{
|
||||||
@@ -286,7 +274,7 @@ fts_load(FTS *sp, FTSENT *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__fts_close(FTS *sp)
|
fts_close(FTS *sp)
|
||||||
{
|
{
|
||||||
FTSENT *freep, *p;
|
FTSENT *freep, *p;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
@@ -331,20 +319,16 @@ __fts_close(FTS *sp)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_close, fts_close);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special case of "/" at the end of the path so that slashes aren't
|
* Special case of "/" at the end of the path so that slashes aren't
|
||||||
* appended which would cause paths to be written as "....//foo".
|
* appended which would cause paths to be written as "....//foo".
|
||||||
*/
|
*/
|
||||||
#define NAPPEND(p) \
|
#define NAPPEND(p) \
|
||||||
(p->fts_path[p->fts_pathlen - 1] == '/' \
|
(p->fts_path[p->fts_pathlen - 1] == '/' \
|
||||||
? p->fts_pathlen - 1 : p->fts_pathlen)
|
? p->fts_pathlen - 1 : p->fts_pathlen)
|
||||||
|
|
||||||
FTSENT *
|
FTSENT *
|
||||||
__fts_read(FTS *sp)
|
fts_read(FTS *sp)
|
||||||
{
|
{
|
||||||
FTSENT *p, *tmp;
|
FTSENT *p, *tmp;
|
||||||
int instr;
|
int instr;
|
||||||
@@ -364,7 +348,7 @@ __fts_read(FTS *sp)
|
|||||||
|
|
||||||
/* Any type of file may be re-visited; re-stat and re-turn. */
|
/* Any type of file may be re-visited; re-stat and re-turn. */
|
||||||
if (instr == FTS_AGAIN) {
|
if (instr == FTS_AGAIN) {
|
||||||
p->fts_info = fts_stat(sp, p, 0);
|
p->fts_info = fts_stat(sp, p, 0, -1);
|
||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,11 +359,11 @@ __fts_read(FTS *sp)
|
|||||||
* pointer, follow fails.
|
* pointer, follow fails.
|
||||||
*/
|
*/
|
||||||
if (instr == FTS_FOLLOW &&
|
if (instr == FTS_FOLLOW &&
|
||||||
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
|
(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_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
|
||||||
if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC,
|
if ((p->fts_symfd = open(".", O_RDONLY | O_CLOEXEC,
|
||||||
0)) < 0) {
|
0)) < 0) {
|
||||||
p->fts_errno = errno;
|
p->fts_errno = errno;
|
||||||
p->fts_info = FTS_ERR;
|
p->fts_info = FTS_ERR;
|
||||||
} else
|
} else
|
||||||
@@ -392,7 +376,7 @@ __fts_read(FTS *sp)
|
|||||||
if (p->fts_info == FTS_D) {
|
if (p->fts_info == FTS_D) {
|
||||||
/* If skipped or crossed mount point, do post-order visit. */
|
/* If skipped or crossed mount point, do post-order visit. */
|
||||||
if (instr == FTS_SKIP ||
|
if (instr == FTS_SKIP ||
|
||||||
(ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
|
(ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
|
||||||
if (p->fts_flags & FTS_SYMFOLLOW)
|
if (p->fts_flags & FTS_SYMFOLLOW)
|
||||||
(void)close(p->fts_symfd);
|
(void)close(p->fts_symfd);
|
||||||
if (sp->fts_child) {
|
if (sp->fts_child) {
|
||||||
@@ -427,9 +411,9 @@ __fts_read(FTS *sp)
|
|||||||
p->fts_errno = errno;
|
p->fts_errno = errno;
|
||||||
p->fts_flags |= FTS_DONTCHDIR;
|
p->fts_flags |= FTS_DONTCHDIR;
|
||||||
for (p = sp->fts_child; p != NULL;
|
for (p = sp->fts_child; p != NULL;
|
||||||
p = p->fts_link)
|
p = p->fts_link)
|
||||||
p->fts_accpath =
|
p->fts_accpath =
|
||||||
p->fts_parent->fts_accpath;
|
p->fts_parent->fts_accpath;
|
||||||
}
|
}
|
||||||
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
|
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
|
||||||
if (ISSET(FTS_STOP))
|
if (ISSET(FTS_STOP))
|
||||||
@@ -444,8 +428,6 @@ __fts_read(FTS *sp)
|
|||||||
/* Move to the next node on this level. */
|
/* Move to the next node on this level. */
|
||||||
next: tmp = p;
|
next: tmp = p;
|
||||||
if ((p = p->fts_link) != NULL) {
|
if ((p = p->fts_link) != NULL) {
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If reached the top, return to the original directory (or
|
* If reached the top, return to the original directory (or
|
||||||
* 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.
|
||||||
@@ -455,6 +437,7 @@ next: tmp = p;
|
|||||||
SET(FTS_STOP);
|
SET(FTS_STOP);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
free(tmp);
|
||||||
fts_load(sp, p);
|
fts_load(sp, p);
|
||||||
return (sp->fts_cur = p);
|
return (sp->fts_cur = p);
|
||||||
}
|
}
|
||||||
@@ -464,13 +447,15 @@ next: tmp = p;
|
|||||||
* ignore. If followed, get a file descriptor so we can
|
* ignore. If followed, get a file descriptor so we can
|
||||||
* get back if necessary.
|
* get back if necessary.
|
||||||
*/
|
*/
|
||||||
if (p->fts_instr == FTS_SKIP)
|
if (p->fts_instr == FTS_SKIP) {
|
||||||
|
free(tmp);
|
||||||
goto next;
|
goto next;
|
||||||
|
}
|
||||||
if (p->fts_instr == FTS_FOLLOW) {
|
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_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
|
||||||
if ((p->fts_symfd =
|
if ((p->fts_symfd =
|
||||||
open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
|
open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
|
||||||
p->fts_errno = errno;
|
p->fts_errno = errno;
|
||||||
p->fts_info = FTS_ERR;
|
p->fts_info = FTS_ERR;
|
||||||
} else
|
} else
|
||||||
@@ -479,6 +464,8 @@ next: tmp = p;
|
|||||||
p->fts_instr = FTS_NOINSTR;
|
p->fts_instr = FTS_NOINSTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
name: t = sp->fts_path + NAPPEND(p->fts_parent);
|
name: t = sp->fts_path + NAPPEND(p->fts_parent);
|
||||||
*t++ = '/';
|
*t++ = '/';
|
||||||
memmove(t, p->fts_name, p->fts_namelen + 1);
|
memmove(t, p->fts_name, p->fts_namelen + 1);
|
||||||
@@ -487,13 +474,13 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent);
|
|||||||
|
|
||||||
/* Move up to the parent node. */
|
/* Move up to the parent node. */
|
||||||
p = tmp->fts_parent;
|
p = tmp->fts_parent;
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
|
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
|
||||||
/*
|
/*
|
||||||
* Done; free everything up and set errno to 0 so the user
|
* Done; free everything up and set errno to 0 so the user
|
||||||
* can distinguish between error and EOF.
|
* can distinguish between error and EOF.
|
||||||
*/
|
*/
|
||||||
|
free(tmp);
|
||||||
free(p);
|
free(p);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
return (sp->fts_cur = NULL);
|
return (sp->fts_cur = NULL);
|
||||||
@@ -522,18 +509,15 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent);
|
|||||||
}
|
}
|
||||||
(void)close(p->fts_symfd);
|
(void)close(p->fts_symfd);
|
||||||
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
|
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
|
||||||
fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
|
fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
|
||||||
SET(FTS_STOP);
|
SET(FTS_STOP);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
free(tmp);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_read, fts_read);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fts_set takes the stream as an argument although it's not used in this
|
* Fts_set takes the stream as an argument although it's not used in this
|
||||||
* implementation; it would be necessary if anyone wanted to add global
|
* implementation; it would be necessary if anyone wanted to add global
|
||||||
@@ -542,10 +526,10 @@ __weak_reference(__fts_read, fts_read);
|
|||||||
*/
|
*/
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
int
|
int
|
||||||
__fts_set(FTS *sp, FTSENT *p, int instr)
|
fts_set(FTS *sp, FTSENT *p, int instr)
|
||||||
{
|
{
|
||||||
if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
|
if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
|
||||||
instr != FTS_NOINSTR && instr != FTS_SKIP) {
|
instr != FTS_NOINSTR && instr != FTS_SKIP) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@@ -553,15 +537,11 @@ __fts_set(FTS *sp, FTSENT *p, int instr)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_set, fts_set);
|
|
||||||
|
|
||||||
|
|
||||||
FTSENT *
|
FTSENT *
|
||||||
__fts_children(FTS *sp, int instr)
|
fts_children(FTS *sp, int instr)
|
||||||
{
|
{
|
||||||
FTSENT *p;
|
FTSENT *p;
|
||||||
int fd;
|
int fd, rc, serrno;
|
||||||
|
|
||||||
if (instr != 0 && instr != FTS_NAMEONLY) {
|
if (instr != 0 && instr != FTS_NAMEONLY) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -611,63 +591,63 @@ __fts_children(FTS *sp, int instr)
|
|||||||
* fts_read will work.
|
* fts_read will work.
|
||||||
*/
|
*/
|
||||||
if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
|
if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
|
||||||
ISSET(FTS_NOCHDIR))
|
ISSET(FTS_NOCHDIR))
|
||||||
return (sp->fts_child = fts_build(sp, instr));
|
return (sp->fts_child = fts_build(sp, instr));
|
||||||
|
|
||||||
if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
|
if ((fd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
sp->fts_child = fts_build(sp, instr);
|
sp->fts_child = fts_build(sp, instr);
|
||||||
if (fchdir(fd)) {
|
serrno = (sp->fts_child == NULL) ? errno : 0;
|
||||||
(void)close(fd);
|
rc = fchdir(fd);
|
||||||
return (NULL);
|
if (rc < 0 && serrno == 0)
|
||||||
}
|
serrno = errno;
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
|
errno = serrno;
|
||||||
|
if (rc < 0)
|
||||||
|
return (NULL);
|
||||||
return (sp->fts_child);
|
return (sp->fts_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_children, fts_children);
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef fts_get_clientptr
|
#ifndef fts_get_clientptr
|
||||||
#error "fts_get_clientptr not defined"
|
#error "fts_get_clientptr not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *
|
void *
|
||||||
(__fts_get_clientptr)(FTS *sp)
|
(fts_get_clientptr)(FTS *sp)
|
||||||
{
|
{
|
||||||
|
|
||||||
return (fts_get_clientptr(sp));
|
return (fts_get_clientptr(sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_get_clientptr, fts_get_clientptr);
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef fts_get_stream
|
#ifndef fts_get_stream
|
||||||
#error "fts_get_stream not defined"
|
#error "fts_get_stream not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FTS *
|
FTS *
|
||||||
(__fts_get_stream)(FTSENT *p)
|
(fts_get_stream)(FTSENT *p)
|
||||||
{
|
{
|
||||||
return (fts_get_stream(p));
|
return (fts_get_stream(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__weak_reference(__fts_get_stream, fts_get_stream);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
__fts_set_clientptr(FTS *sp, void *clientptr)
|
fts_set_clientptr(FTS *sp, void *clientptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
sp->fts_clientptr = clientptr;
|
sp->fts_clientptr = clientptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dirent *
|
||||||
|
fts_safe_readdir(DIR *dirp, int *readdir_errno)
|
||||||
|
{
|
||||||
|
struct dirent *ret;
|
||||||
|
|
||||||
__weak_reference(__fts_set_clientptr, fts_set_clientptr);
|
errno = 0;
|
||||||
|
if (!dirp)
|
||||||
|
return (NULL);
|
||||||
|
ret = readdir(dirp);
|
||||||
|
*readdir_errno = errno;
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the tricky part -- do not casually change *anything* in here. The
|
* This is the tricky part -- do not casually change *anything* in here. The
|
||||||
@@ -692,7 +672,8 @@ fts_build(FTS *sp, int type)
|
|||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
void *oldaddr;
|
void *oldaddr;
|
||||||
char *cp;
|
char *cp;
|
||||||
int cderrno, descend, saved_errno, nostat, doadjust;
|
int cderrno, descend, saved_errno, nostat, doadjust,
|
||||||
|
readdir_errno;
|
||||||
#ifdef FTS_WHITEOUT
|
#ifdef FTS_WHITEOUT
|
||||||
int oflag;
|
int oflag;
|
||||||
#endif
|
#endif
|
||||||
@@ -709,9 +690,9 @@ fts_build(FTS *sp, int type)
|
|||||||
*/
|
*/
|
||||||
#ifdef FTS_WHITEOUT
|
#ifdef FTS_WHITEOUT
|
||||||
if (ISSET(FTS_WHITEOUT))
|
if (ISSET(FTS_WHITEOUT))
|
||||||
oflag = DTF_NODUP | DTF_REWIND;
|
oflag = DTF_NODUP;
|
||||||
else
|
else
|
||||||
oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND;
|
oflag = DTF_HIDEW | DTF_NODUP;
|
||||||
#else
|
#else
|
||||||
#define __opendir2(path, flag) opendir(path)
|
#define __opendir2(path, flag) opendir(path)
|
||||||
#endif
|
#endif
|
||||||
@@ -746,7 +727,7 @@ fts_build(FTS *sp, int type)
|
|||||||
#ifdef notdef
|
#ifdef notdef
|
||||||
(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
|
(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
|
||||||
(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
|
(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
|
||||||
ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
|
ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* If we're going to need to stat anything or we want to descend
|
* If we're going to need to stat anything or we want to descend
|
||||||
@@ -801,7 +782,9 @@ fts_build(FTS *sp, int type)
|
|||||||
|
|
||||||
/* Read the directory, attaching each entry to the `link' pointer. */
|
/* Read the directory, attaching each entry to the `link' pointer. */
|
||||||
doadjust = 0;
|
doadjust = 0;
|
||||||
for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
|
readdir_errno = 0;
|
||||||
|
for (head = tail = NULL, nitems = 0;
|
||||||
|
(dp = fts_safe_readdir(dirp, &readdir_errno));) {
|
||||||
dnamlen = strlen(dp->d_name);
|
dnamlen = strlen(dp->d_name);
|
||||||
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
|
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
|
||||||
continue;
|
continue;
|
||||||
@@ -853,26 +836,27 @@ mem1: saved_errno = errno;
|
|||||||
p->fts_accpath = cur->fts_accpath;
|
p->fts_accpath = cur->fts_accpath;
|
||||||
} else if (nlinks == 0
|
} else if (nlinks == 0
|
||||||
#ifdef DT_DIR
|
#ifdef DT_DIR
|
||||||
|| (nostat &&
|
|| (nostat &&
|
||||||
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
|
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
p->fts_accpath =
|
p->fts_accpath =
|
||||||
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
|
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
|
||||||
p->fts_info = FTS_NSOK;
|
p->fts_info = FTS_NSOK;
|
||||||
} else {
|
} else {
|
||||||
/* Build a file name for fts_stat to stat. */
|
/* Build a file name for fts_stat to stat. */
|
||||||
if (ISSET(FTS_NOCHDIR)) {
|
if (ISSET(FTS_NOCHDIR)) {
|
||||||
p->fts_accpath = p->fts_path;
|
p->fts_accpath = p->fts_path;
|
||||||
memmove(cp, p->fts_name, p->fts_namelen + 1);
|
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;
|
p->fts_accpath = p->fts_name;
|
||||||
/* Stat it. */
|
p->fts_info = fts_stat(sp, p, 0, -1);
|
||||||
p->fts_info = fts_stat(sp, p, 0);
|
}
|
||||||
|
|
||||||
/* Decrement link count if applicable. */
|
/* Decrement link count if applicable. */
|
||||||
if (nlinks > 0 && (p->fts_info == FTS_D ||
|
if (nlinks > 0 && (p->fts_info == FTS_D ||
|
||||||
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
|
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
|
||||||
--nlinks;
|
--nlinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -886,6 +870,16 @@ mem1: saved_errno = errno;
|
|||||||
}
|
}
|
||||||
++nitems;
|
++nitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (readdir_errno) {
|
||||||
|
cur->fts_errno = readdir_errno;
|
||||||
|
/*
|
||||||
|
* If we've not read any items yet, treat
|
||||||
|
* the error as if we can't access the dir.
|
||||||
|
*/
|
||||||
|
cur->fts_info = nitems ? FTS_ERR : FTS_DNR;
|
||||||
|
}
|
||||||
|
|
||||||
if (dirp)
|
if (dirp)
|
||||||
(void)closedir(dirp);
|
(void)closedir(dirp);
|
||||||
|
|
||||||
@@ -911,9 +905,10 @@ mem1: saved_errno = errno;
|
|||||||
* can't get back, we're done.
|
* can't get back, we're done.
|
||||||
*/
|
*/
|
||||||
if (descend && (type == BCHILD || !nitems) &&
|
if (descend && (type == BCHILD || !nitems) &&
|
||||||
(cur->fts_level == FTS_ROOTLEVEL ?
|
(cur->fts_level == FTS_ROOTLEVEL ?
|
||||||
FCHDIR(sp, sp->fts_rfd) :
|
FCHDIR(sp, sp->fts_rfd) :
|
||||||
fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
|
fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
|
||||||
|
fts_lfree(head);
|
||||||
cur->fts_info = FTS_ERR;
|
cur->fts_info = FTS_ERR;
|
||||||
SET(FTS_STOP);
|
SET(FTS_STOP);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -921,7 +916,8 @@ mem1: saved_errno = errno;
|
|||||||
|
|
||||||
/* If didn't find anything, return NULL. */
|
/* If didn't find anything, return NULL. */
|
||||||
if (!nitems) {
|
if (!nitems) {
|
||||||
if (type == BREAD)
|
if (type == BREAD &&
|
||||||
|
cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
|
||||||
cur->fts_info = FTS_DP;
|
cur->fts_info = FTS_DP;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@@ -933,13 +929,19 @@ mem1: saved_errno = errno;
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fts_stat(FTS *sp, FTSENT *p, int follow)
|
fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
|
||||||
{
|
{
|
||||||
FTSENT *t;
|
FTSENT *t;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
struct stat *sbp, sb;
|
struct stat *sbp, sb;
|
||||||
int saved_errno;
|
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. */
|
/* If user needs stat info, stat buffer already allocated. */
|
||||||
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
|
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
|
||||||
@@ -961,16 +963,17 @@ fts_stat(FTS *sp, FTSENT *p, int follow)
|
|||||||
* fail, set the errno from the stat call.
|
* fail, set the errno from the stat call.
|
||||||
*/
|
*/
|
||||||
if (ISSET(FTS_LOGICAL) || follow) {
|
if (ISSET(FTS_LOGICAL) || follow) {
|
||||||
if (stat(p->fts_accpath, sbp)) {
|
if (fstatat(dfd, path, sbp, 0)) {
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
if (!lstat(p->fts_accpath, sbp)) {
|
if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
|
||||||
errno = 0;
|
p->fts_errno = saved_errno;
|
||||||
return (FTS_SLNONE);
|
goto err;
|
||||||
}
|
}
|
||||||
p->fts_errno = saved_errno;
|
errno = 0;
|
||||||
goto err;
|
if (S_ISLNK(sbp->st_mode))
|
||||||
|
return (FTS_SLNONE);
|
||||||
}
|
}
|
||||||
} else if (lstat(p->fts_accpath, sbp)) {
|
} else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
|
||||||
p->fts_errno = errno;
|
p->fts_errno = errno;
|
||||||
err: memset(sbp, 0, sizeof(struct stat));
|
err: memset(sbp, 0, sizeof(struct stat));
|
||||||
return (FTS_NS);
|
return (FTS_NS);
|
||||||
@@ -998,7 +1001,7 @@ err: memset(sbp, 0, sizeof(struct stat));
|
|||||||
* something faster might be worthwhile.
|
* something faster might be worthwhile.
|
||||||
*/
|
*/
|
||||||
for (t = p->fts_parent;
|
for (t = p->fts_parent;
|
||||||
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
|
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
|
||||||
if (ino == t->fts_ino && dev == t->fts_dev) {
|
if (ino == t->fts_ino && dev == t->fts_dev) {
|
||||||
p->fts_cycle = t;
|
p->fts_cycle = t;
|
||||||
return (FTS_DC);
|
return (FTS_DC);
|
||||||
@@ -1031,7 +1034,6 @@ static FTSENT *
|
|||||||
fts_sort(FTS *sp, FTSENT *head, size_t nitems)
|
fts_sort(FTS *sp, FTSENT *head, size_t nitems)
|
||||||
{
|
{
|
||||||
FTSENT **ap, *p;
|
FTSENT **ap, *p;
|
||||||
FTSENT **new_array;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct an array of pointers to the structures and call qsort(3).
|
* Construct an array of pointers to the structures and call qsort(3).
|
||||||
@@ -1042,14 +1044,11 @@ fts_sort(FTS *sp, FTSENT *head, size_t nitems)
|
|||||||
*/
|
*/
|
||||||
if (nitems > sp->fts_nitems) {
|
if (nitems > sp->fts_nitems) {
|
||||||
sp->fts_nitems = nitems + 40;
|
sp->fts_nitems = nitems + 40;
|
||||||
new_array = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *));
|
if ((sp->fts_array = reallocf(sp->fts_array,
|
||||||
if (new_array == NULL) {
|
sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
|
||||||
free(sp->fts_array);
|
|
||||||
sp->fts_array = NULL;
|
|
||||||
sp->fts_nitems = 0;
|
sp->fts_nitems = 0;
|
||||||
return (head);
|
return (head);
|
||||||
}
|
}
|
||||||
sp->fts_array = new_array;
|
|
||||||
}
|
}
|
||||||
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
|
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
|
||||||
*ap++ = p;
|
*ap++ = p;
|
||||||
@@ -1128,17 +1127,9 @@ fts_lfree(FTSENT *head)
|
|||||||
static int
|
static int
|
||||||
fts_palloc(FTS *sp, size_t more)
|
fts_palloc(FTS *sp, size_t more)
|
||||||
{
|
{
|
||||||
char *new_path;
|
|
||||||
sp->fts_pathlen += more + 256;
|
sp->fts_pathlen += more + 256;
|
||||||
|
sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
|
||||||
new_path = realloc(sp->fts_path, sp->fts_pathlen);
|
|
||||||
if (new_path == NULL) {
|
|
||||||
free(sp->fts_path);
|
|
||||||
sp->fts_path = NULL;
|
|
||||||
} else {
|
|
||||||
sp->fts_path = new_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (sp->fts_path == NULL);
|
return (sp->fts_path == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1155,7 +1146,7 @@ fts_padjust(FTS *sp, FTSENT *head)
|
|||||||
#define ADJUST(p) do { \
|
#define ADJUST(p) do { \
|
||||||
if ((p)->fts_accpath != (p)->fts_name) { \
|
if ((p)->fts_accpath != (p)->fts_name) { \
|
||||||
(p)->fts_accpath = \
|
(p)->fts_accpath = \
|
||||||
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
|
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
|
||||||
} \
|
} \
|
||||||
(p)->fts_path = addr; \
|
(p)->fts_path = addr; \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -1171,8 +1162,7 @@ fts_padjust(FTS *sp, FTSENT *head)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
fts_maxarglen(argv)
|
fts_maxarglen(char * const *argv)
|
||||||
char * const *argv;
|
|
||||||
{
|
{
|
||||||
size_t len, max;
|
size_t len, max;
|
||||||
|
|
||||||
@@ -1196,7 +1186,8 @@ fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
|
|||||||
newfd = fd;
|
newfd = fd;
|
||||||
if (ISSET(FTS_NOCHDIR))
|
if (ISSET(FTS_NOCHDIR))
|
||||||
return (0);
|
return (0);
|
||||||
if (fd < 0 && (newfd = open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
|
if (fd < 0 && (newfd = open(path, O_RDONLY | O_DIRECTORY |
|
||||||
|
O_CLOEXEC, 0)) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
if (fstat(newfd, &sb)) {
|
if (fstat(newfd, &sb)) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@@ -1241,7 +1232,7 @@ fts_ufslinks(FTS *sp, const FTSENT *ent)
|
|||||||
priv->ftsp_linksreliable = 0;
|
priv->ftsp_linksreliable = 0;
|
||||||
for (cpp = ufslike_filesystems; *cpp; cpp++) {
|
for (cpp = ufslike_filesystems; *cpp; cpp++) {
|
||||||
if (strcmp(priv->ftsp_statfs.f_fstypename,
|
if (strcmp(priv->ftsp_statfs.f_fstypename,
|
||||||
*cpp) == 0) {
|
*cpp) == 0) {
|
||||||
priv->ftsp_linksreliable = 1;
|
priv->ftsp_linksreliable = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user