version 1.10, 2016/08/02 11:09:46 |
version 1.15, 2020/06/14 22:49:36 |
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 *); |
|
|
|
typedef int (*qsort_compar_proto)(const void *, const void *); |
|
|
#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 |
|
#define O_DIRECTORY 0 |
|
#endif |
|
#ifndef O_CLOEXEC |
#ifndef O_CLOEXEC |
#define O_CLOEXEC 0 |
#define O_CLOEXEC 0 |
#endif |
#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)) |
|
|
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, *prev; |
size_t len; |
|
|
|
/* Options check. */ |
/* Options check. */ |
if (options & ~FTS_OPTIONMASK) { |
if (options & ~FTS_OPTIONMASK) { |
Line 91 fts_open(char * const *argv, int options, void *dummy) |
|
Line 88 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 109 fts_open(char * const *argv, int options, void *dummy) |
|
Line 113 fts_open(char * const *argv, int options, void *dummy) |
|
parent->fts_level = FTS_ROOTPARENTLEVEL; |
parent->fts_level = FTS_ROOTPARENTLEVEL; |
|
|
/* Allocate/initialize root(s). */ |
/* Allocate/initialize root(s). */ |
for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { |
for (root = prev = 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 127 fts_open(char * const *argv, int options, void *dummy) |
|
Line 125 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) |
|
root = p; |
|
else |
|
prev->fts_link = p; |
|
prev = 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 204 fts_close(FTS *sp) |
|
Line 212 fts_close(FTS *sp) |
|
/* 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); |
|
|
Line 320 name: t = sp->fts_path + NAPPEND(p->fts_parent); |
|
Line 329 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 419 fts_build(FTS *sp) |
|
Line 427 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 493 mem1: saved_errno = errno; |
|
Line 500 mem1: saved_errno = errno; |
|
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 550 fts_stat(FTS *sp, FTSENT *p) |
|
Line 561 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 *), |
|
(qsort_compar_proto)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 600 fts_palloc(FTS *sp, size_t more) |
|
Line 646 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 609 fts_palloc(FTS *sp, size_t more) |
|
Line 654 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); |
} |
} |