version 1.1, 2014/08/11 01:39:00 |
version 1.6, 2014/12/11 18:20:07 |
|
|
#include "config.h" |
#include "config.h" |
|
|
#ifdef HAVE_FTS |
#if HAVE_FTS |
|
|
int dummy; |
int dummy; |
|
|
#else |
#else |
|
|
|
/* $Id$ */ |
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/*- |
/*- |
Line 61 static unsigned short fts_stat(FTS *, FTSENT *); |
|
Line 62 static unsigned short fts_stat(FTS *, FTSENT *); |
|
static int fts_safe_changedir(FTS *, FTSENT *, int, const char *); |
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]))) |
|
#define MAX(a,b) (((a)>(b))?(a):(b)) |
|
#ifndef O_DIRECTORY |
|
#define O_DIRECTORY 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)) |
Line 145 fts_open(char * const *argv, int options, void *dummy) |
|
Line 150 fts_open(char * const *argv, int options, void *dummy) |
|
* and ".." are all fairly nasty problems. Note, if we can't get the |
* and ".." are all fairly nasty problems. Note, if we can't get the |
* descriptor we run anyway, just more slowly. |
* descriptor we run anyway, just more slowly. |
*/ |
*/ |
if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) |
if (!ISSET(FTS_NOCHDIR) && |
|
(sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC)) < 0) |
SET(FTS_NOCHDIR); |
SET(FTS_NOCHDIR); |
|
|
if (nitems == 0) |
if (nitems == 0) |
Line 404 fts_build(FTS *sp) |
|
Line 410 fts_build(FTS *sp) |
|
FTSENT *cur, *tail; |
FTSENT *cur, *tail; |
DIR *dirp; |
DIR *dirp; |
void *oldaddr; |
void *oldaddr; |
size_t len, maxlen; |
size_t dlen, len, maxlen; |
int nitems, cderrno, descend, level, nlinks, nostat, doadjust; |
int nitems, cderrno, descend, level, doadjust; |
int saved_errno; |
int saved_errno; |
char *cp; |
char *cp; |
|
|
Line 423 fts_build(FTS *sp) |
|
Line 429 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 |
* 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, |
* 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. |
* but set a flag so we don't chdir after the post-order visit. |
Line 447 fts_build(FTS *sp) |
|
Line 445 fts_build(FTS *sp) |
|
*/ |
*/ |
cderrno = 0; |
cderrno = 0; |
if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { |
if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { |
if (nlinks) |
cur->fts_errno = errno; |
cur->fts_errno = errno; |
|
cur->fts_flags |= FTS_DONTCHDIR; |
cur->fts_flags |= FTS_DONTCHDIR; |
descend = 0; |
descend = 0; |
cderrno = errno; |
cderrno = errno; |
Line 489 fts_build(FTS *sp) |
|
Line 486 fts_build(FTS *sp) |
|
if (ISDOT(dp->d_name)) |
if (ISDOT(dp->d_name)) |
continue; |
continue; |
|
|
if (!(p = fts_alloc(sp, dp->d_name, (size_t)dp->d_namlen))) |
#if HAVE_DIRENT_NAMLEN |
|
dlen = dp->d_namlen; |
|
#else |
|
dlen = strlen(dp->d_name); |
|
#endif |
|
|
|
if (!(p = fts_alloc(sp, dp->d_name, dlen))) |
goto mem1; |
goto mem1; |
if (dp->d_namlen >= maxlen) { /* include space for NUL */ |
if (dlen >= maxlen) { /* include space for NUL */ |
oldaddr = sp->fts_path; |
oldaddr = sp->fts_path; |
if (fts_palloc(sp, dp->d_namlen +len + 1)) { |
if (fts_palloc(sp, dlen + len + 1)) { |
/* |
/* |
* No more memory for path or structures. Save |
* No more memory for path or structures. Save |
* errno, free up the current structure and the |
* errno, free up the current structure and the |
Line 520 mem1: saved_errno = errno; |
|
Line 523 mem1: saved_errno = errno; |
|
|
|
p->fts_level = level; |
p->fts_level = level; |
p->fts_parent = sp->fts_cur; |
p->fts_parent = sp->fts_cur; |
p->fts_pathlen = len + dp->d_namlen; |
p->fts_pathlen = len + dlen; |
if (p->fts_pathlen < len) { |
if (p->fts_pathlen < len) { |
/* |
/* |
* If we wrap, free up the current structure and |
* If we wrap, free up the current structure and |
Line 537 mem1: saved_errno = errno; |
|
Line 540 mem1: saved_errno = errno; |
|
} |
} |
|
|
if (cderrno) { |
if (cderrno) { |
if (nlinks) { |
p->fts_info = FTS_NS; |
p->fts_info = FTS_NS; |
p->fts_errno = cderrno; |
p->fts_errno = cderrno; |
|
} else |
|
p->fts_info = FTS_NSOK; |
|
p->fts_accpath = cur->fts_accpath; |
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 { |
} 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)) { |
Line 561 mem1: saved_errno = errno; |
|
Line 552 mem1: saved_errno = errno; |
|
p->fts_accpath = p->fts_name; |
p->fts_accpath = p->fts_name; |
/* Stat it. */ |
/* Stat it. */ |
p->fts_info = fts_stat(sp, p); |
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. */ |
Line 680 fts_alloc(FTS *sp, const char *name, size_t namelen) |
|
Line 666 fts_alloc(FTS *sp, const char *name, size_t namelen) |
|
FTSENT *p; |
FTSENT *p; |
size_t len; |
size_t len; |
|
|
/* |
|
* The file name is a variable length array and no stat structure is |
|
* necessary if the user has set the nostat bit. Allocate the FTSENT |
|
* structure, the file name and the stat structure in one chunk, but |
|
* be careful that the stat structure is reasonably aligned. Since the |
|
* fts_name field is declared to be of size 1, the fts_name pointer is |
|
* namelen + 2 before the first possible address of the stat structure. |
|
*/ |
|
len = sizeof(FTSENT) + namelen; |
len = sizeof(FTSENT) + namelen; |
len += sizeof(struct stat) + ALIGNBYTES; |
|
if ((p = calloc(1, len)) == NULL) |
if ((p = calloc(1, len)) == NULL) |
return (NULL); |
return (NULL); |
|
|
p->fts_path = sp->fts_path; |
p->fts_path = sp->fts_path; |
p->fts_namelen = namelen; |
p->fts_namelen = namelen; |
p->fts_instr = FTS_NOINSTR; |
p->fts_instr = FTS_NOINSTR; |
p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); |
p->fts_statp = malloc(sizeof(struct stat)); |
|
if (p->fts_statp == NULL) { |
|
free(p); |
|
return (NULL); |
|
} |
memcpy(p->fts_name, name, namelen); |
memcpy(p->fts_name, name, namelen); |
|
|
return (p); |
return (p); |
Line 801 fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const c |
|
Line 782 fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const c |
|
newfd = fd; |
newfd = fd; |
if (ISSET(FTS_NOCHDIR)) |
if (ISSET(FTS_NOCHDIR)) |
return (0); |
return (0); |
if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0) |
if (fd < 0 && (newfd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC)) < 0) |
return (-1); |
return (-1); |
if (fstat(newfd, &sb)) { |
if (fstat(newfd, &sb)) { |
ret = -1; |
ret = -1; |