Make the threatened fts(3) ABI fix. FTSENT now avoids the use of the struct
hack, thereby allowing future extensions to the structure (e.g., for extended attributes) without rebreaking the ABI. FTSENT now contains a pointer to the parent stream, which fts_compar() can then take advantage of, avoiding the undefined behavior previously warned about. As a consequence of this change, the prototype of the comparison function passed to fts_open() has changed to reflect the required amount of constness for its use. All callers in the tree are updated to use the correct prototype. Comparison functions can now make use of the new parent pointer to access the new stream-specific private data pointer, which is intended to assist creation of reentrant library routines which use fts(3) internally. Not objected to in spirit by: -arch
This commit is contained in:
parent
0c7fb5347c
commit
0d3bcc2e80
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=103726
@ -92,7 +92,7 @@ static int Rflag, rflag;
|
|||||||
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
|
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
|
||||||
|
|
||||||
static int copy(char *[], enum op, int);
|
static int copy(char *[], enum op, int);
|
||||||
static int mastercmp(const FTSENT **, const FTSENT **);
|
static int mastercmp(const FTSENT * const *, const FTSENT * const *);
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
@ -484,7 +484,7 @@ copy(char *argv[], enum op type, int fts_options)
|
|||||||
* files first reduces seeking.
|
* files first reduces seeking.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
mastercmp(const FTSENT **a, const FTSENT **b)
|
mastercmp(const FTSENT * const *a, const FTSENT * const *b)
|
||||||
{
|
{
|
||||||
int a_info, b_info;
|
int a_info, b_info;
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
static void display(FTSENT *, FTSENT *);
|
static void display(FTSENT *, FTSENT *);
|
||||||
static u_quad_t makenines(u_long);
|
static u_quad_t makenines(u_long);
|
||||||
static int mastercmp(const FTSENT **, const FTSENT **);
|
static int mastercmp(const FTSENT * const *, const FTSENT * const *);
|
||||||
static void traverse(int, char **, int);
|
static void traverse(int, char **, int);
|
||||||
|
|
||||||
static void (*printfcn)(DISPLAY *);
|
static void (*printfcn)(DISPLAY *);
|
||||||
@ -759,7 +759,7 @@ display(FTSENT *p, FTSENT *list)
|
|||||||
* All other levels use the sort function. Error entries remain unsorted.
|
* All other levels use the sort function. Error entries remain unsorted.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mastercmp(const FTSENT **a, const FTSENT **b)
|
mastercmp(const FTSENT * const *a, const FTSENT * const *b)
|
||||||
{
|
{
|
||||||
int a_info, b_info;
|
int a_info, b_info;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ typedef struct {
|
|||||||
int fts_pathlen; /* sizeof(path) */
|
int fts_pathlen; /* sizeof(path) */
|
||||||
int fts_nitems; /* elements in the sort array */
|
int fts_nitems; /* elements in the sort array */
|
||||||
int (*fts_compar) /* compare function */
|
int (*fts_compar) /* compare function */
|
||||||
(const struct _ftsent **, const struct _ftsent **);
|
(const struct _ftsent * const *, const struct _ftsent * const *);
|
||||||
|
|
||||||
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
|
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
|
||||||
#define FTS_LOGICAL 0x002 /* logical walk */
|
#define FTS_LOGICAL 0x002 /* logical walk */
|
||||||
@ -62,6 +62,7 @@ typedef struct {
|
|||||||
#define FTS_NAMEONLY 0x100 /* (private) child names only */
|
#define FTS_NAMEONLY 0x100 /* (private) child names only */
|
||||||
#define FTS_STOP 0x200 /* (private) unrecoverable error */
|
#define FTS_STOP 0x200 /* (private) unrecoverable error */
|
||||||
int fts_options; /* fts_open options, global flags */
|
int fts_options; /* fts_open options, global flags */
|
||||||
|
void *fts_clientptr; /* thunk for sort function */
|
||||||
} FTS;
|
} FTS;
|
||||||
|
|
||||||
typedef struct _ftsent {
|
typedef struct _ftsent {
|
||||||
@ -113,7 +114,8 @@ typedef struct _ftsent {
|
|||||||
u_short fts_instr; /* fts_set() instructions */
|
u_short fts_instr; /* fts_set() instructions */
|
||||||
|
|
||||||
struct stat *fts_statp; /* stat(2) information */
|
struct stat *fts_statp; /* stat(2) information */
|
||||||
char fts_name[1]; /* file name */
|
char *fts_name; /* file name */
|
||||||
|
FTS *fts_fts; /* back pointer to main FTS */
|
||||||
} FTSENT;
|
} FTSENT;
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
@ -121,10 +123,15 @@ typedef struct _ftsent {
|
|||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
FTSENT *fts_children(FTS *, int);
|
FTSENT *fts_children(FTS *, int);
|
||||||
int fts_close(FTS *);
|
int fts_close(FTS *);
|
||||||
|
void *fts_get_clientptr(FTS *);
|
||||||
|
#define fts_get_clientptr(fts) ((fts)->fts_clientptr)
|
||||||
|
FTS *fts_get_stream(FTSENT *);
|
||||||
|
#define fts_get_stream(ftsent) ((ftsent)->fts_fts)
|
||||||
FTS *fts_open(char * const *, int,
|
FTS *fts_open(char * const *, int,
|
||||||
int (*)(const FTSENT **, const FTSENT **));
|
int (*)(const FTSENT * const *, const FTSENT * const *));
|
||||||
FTSENT *fts_read(FTS *);
|
FTSENT *fts_read(FTS *);
|
||||||
int fts_set(FTS *, FTSENT *, int);
|
int fts_set(FTS *, FTSENT *, int);
|
||||||
|
void fts_set_clientptr(FTS *, void *);
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* !_FTS_H_ */
|
#endif /* !_FTS_H_ */
|
||||||
|
@ -81,7 +81,7 @@ FTS *
|
|||||||
fts_open(argv, options, compar)
|
fts_open(argv, options, compar)
|
||||||
char * const *argv;
|
char * const *argv;
|
||||||
int options;
|
int options;
|
||||||
int (*compar)(const FTSENT **, const FTSENT **);
|
int (*compar)(const FTSENT * const *, const FTSENT * const *);
|
||||||
{
|
{
|
||||||
FTS *sp;
|
FTS *sp;
|
||||||
FTSENT *p, *root;
|
FTSENT *p, *root;
|
||||||
@ -96,7 +96,7 @@ fts_open(argv, options, compar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate/initialize the stream */
|
/* Allocate/initialize the stream */
|
||||||
if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
|
if ((sp = malloc(sizeof(FTS))) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
memset(sp, 0, sizeof(FTS));
|
memset(sp, 0, sizeof(FTS));
|
||||||
sp->fts_compar = compar;
|
sp->fts_compar = compar;
|
||||||
@ -547,6 +547,34 @@ fts_children(sp, instr)
|
|||||||
return (sp->fts_child);
|
return (sp->fts_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef fts_get_clientptr
|
||||||
|
#error "fts_get_clientptr not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *
|
||||||
|
(fts_get_clientptr)(FTS *sp)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (fts_get_clientptr(sp));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef fts_get_stream
|
||||||
|
#error "fts_get_stream not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FTS *
|
||||||
|
(fts_get_stream)(FTSENT *p)
|
||||||
|
{
|
||||||
|
return (fts_get_stream(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fts_set_clientptr(FTS *sp, void *clientptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
sp->fts_clientptr = clientptr;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
* idea is to build the linked list of entries that are used by fts_children
|
* idea is to build the linked list of entries that are used by fts_children
|
||||||
@ -907,6 +935,21 @@ err: memset(sbp, 0, sizeof(struct stat));
|
|||||||
return (FTS_DEFAULT);
|
return (FTS_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The comparison function takes pointers to pointers to FTSENT structures.
|
||||||
|
* Qsort wants a comparison function that takes pointers to void.
|
||||||
|
* (Both with appropriate levels of const-poisoning, of course!)
|
||||||
|
* Use a trampoline function to deal with the difference.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
fts_compar(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
FTS *parent;
|
||||||
|
|
||||||
|
parent = (*(const FTSENT * const *)a)->fts_fts;
|
||||||
|
return (*parent->fts_compar)(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
static FTSENT *
|
static FTSENT *
|
||||||
fts_sort(sp, head, nitems)
|
fts_sort(sp, head, nitems)
|
||||||
FTS *sp;
|
FTS *sp;
|
||||||
@ -932,7 +975,7 @@ fts_sort(sp, head, nitems)
|
|||||||
}
|
}
|
||||||
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;
|
||||||
qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
|
qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
|
||||||
for (head = *(ap = sp->fts_array); --nitems; ++ap)
|
for (head = *(ap = sp->fts_array); --nitems; ++ap)
|
||||||
ap[0]->fts_link = ap[1];
|
ap[0]->fts_link = ap[1];
|
||||||
ap[0]->fts_link = NULL;
|
ap[0]->fts_link = NULL;
|
||||||
@ -948,26 +991,36 @@ fts_alloc(sp, name, namelen)
|
|||||||
FTSENT *p;
|
FTSENT *p;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
struct ftsent_withstat {
|
||||||
|
FTSENT ent;
|
||||||
|
struct stat statbuf;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The file name is a variable length array and no stat structure is
|
* 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
|
* necessary if the user has set the nostat bit. Allocate the FTSENT
|
||||||
* structure, the file name and the stat structure in one chunk, but
|
* structure, the file name and the stat structure in one chunk, but
|
||||||
* be careful that the stat structure is reasonably aligned. Since the
|
* be careful that the stat structure is reasonably aligned.
|
||||||
* 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;
|
if (ISSET(FTS_NOSTAT))
|
||||||
if (!ISSET(FTS_NOSTAT))
|
len = sizeof(FTSENT) + namelen + 1;
|
||||||
len += sizeof(struct stat) + ALIGNBYTES;
|
else
|
||||||
|
len = sizeof(struct ftsent_withstat) + namelen + 1;
|
||||||
|
|
||||||
if ((p = malloc(len)) == NULL)
|
if ((p = malloc(len)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
/* Copy the name and guarantee NUL termination. */
|
if (ISSET(FTS_NOSTAT)) {
|
||||||
memmove(p->fts_name, name, namelen);
|
p->fts_name = (char *)(p + 1);
|
||||||
p->fts_name[namelen] = '\0';
|
p->fts_statp = NULL;
|
||||||
|
} else {
|
||||||
|
p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
|
||||||
|
p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ISSET(FTS_NOSTAT))
|
/* Copy the name and guarantee NUL termination. */
|
||||||
p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
|
memcpy(p->fts_name, name, namelen);
|
||||||
|
p->fts_name[namelen] = '\0';
|
||||||
p->fts_namelen = namelen;
|
p->fts_namelen = namelen;
|
||||||
p->fts_path = sp->fts_path;
|
p->fts_path = sp->fts_path;
|
||||||
p->fts_errno = 0;
|
p->fts_errno = 0;
|
||||||
@ -975,6 +1028,7 @@ fts_alloc(sp, name, namelen)
|
|||||||
p->fts_instr = FTS_NOINSTR;
|
p->fts_instr = FTS_NOINSTR;
|
||||||
p->fts_number = 0;
|
p->fts_number = 0;
|
||||||
p->fts_pointer = NULL;
|
p->fts_pointer = NULL;
|
||||||
|
p->fts_fts = sp;
|
||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ typedef struct {
|
|||||||
int fts_pathlen; /* sizeof(path) */
|
int fts_pathlen; /* sizeof(path) */
|
||||||
int fts_nitems; /* elements in the sort array */
|
int fts_nitems; /* elements in the sort array */
|
||||||
int (*fts_compar) /* compare function */
|
int (*fts_compar) /* compare function */
|
||||||
(const struct _ftsent **, const struct _ftsent **);
|
(const struct _ftsent * const *, const struct _ftsent * const *);
|
||||||
|
|
||||||
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
|
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
|
||||||
#define FTS_LOGICAL 0x002 /* logical walk */
|
#define FTS_LOGICAL 0x002 /* logical walk */
|
||||||
@ -62,6 +62,7 @@ typedef struct {
|
|||||||
#define FTS_NAMEONLY 0x100 /* (private) child names only */
|
#define FTS_NAMEONLY 0x100 /* (private) child names only */
|
||||||
#define FTS_STOP 0x200 /* (private) unrecoverable error */
|
#define FTS_STOP 0x200 /* (private) unrecoverable error */
|
||||||
int fts_options; /* fts_open options, global flags */
|
int fts_options; /* fts_open options, global flags */
|
||||||
|
void *fts_clientptr; /* thunk for sort function */
|
||||||
} FTS;
|
} FTS;
|
||||||
|
|
||||||
typedef struct _ftsent {
|
typedef struct _ftsent {
|
||||||
@ -113,7 +114,8 @@ typedef struct _ftsent {
|
|||||||
u_short fts_instr; /* fts_set() instructions */
|
u_short fts_instr; /* fts_set() instructions */
|
||||||
|
|
||||||
struct stat *fts_statp; /* stat(2) information */
|
struct stat *fts_statp; /* stat(2) information */
|
||||||
char fts_name[1]; /* file name */
|
char *fts_name; /* file name */
|
||||||
|
FTS *fts_fts; /* back pointer to main FTS */
|
||||||
} FTSENT;
|
} FTSENT;
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
@ -121,10 +123,15 @@ typedef struct _ftsent {
|
|||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
FTSENT *fts_children(FTS *, int);
|
FTSENT *fts_children(FTS *, int);
|
||||||
int fts_close(FTS *);
|
int fts_close(FTS *);
|
||||||
|
void *fts_get_clientptr(FTS *);
|
||||||
|
#define fts_get_clientptr(fts) ((fts)->fts_clientptr)
|
||||||
|
FTS *fts_get_stream(FTSENT *);
|
||||||
|
#define fts_get_stream(ftsent) ((ftsent)->fts_fts)
|
||||||
FTS *fts_open(char * const *, int,
|
FTS *fts_open(char * const *, int,
|
||||||
int (*)(const FTSENT **, const FTSENT **));
|
int (*)(const FTSENT * const *, const FTSENT * const *));
|
||||||
FTSENT *fts_read(FTS *);
|
FTSENT *fts_read(FTS *);
|
||||||
int fts_set(FTS *, FTSENT *, int);
|
int fts_set(FTS *, FTSENT *, int);
|
||||||
|
void fts_set_clientptr(FTS *, void *);
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* !_FTS_H_ */
|
#endif /* !_FTS_H_ */
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
.\" @(#)fts.3 8.5 (Berkeley) 4/16/94
|
.\" @(#)fts.3 8.5 (Berkeley) 4/16/94
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd April 16, 1994
|
.Dd September 15, 2002
|
||||||
.Dt FTS 3
|
.Dt FTS 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -52,6 +52,12 @@
|
|||||||
.Fn fts_children "FTS *ftsp" "int options"
|
.Fn fts_children "FTS *ftsp" "int options"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn fts_set "FTS *ftsp" "FTSENT *f" "int options"
|
.Fn fts_set "FTS *ftsp" "FTSENT *f" "int options"
|
||||||
|
.Ft void
|
||||||
|
.Fn fts_set_clientptr "FTS *ftsp" "void *clientdata"
|
||||||
|
.Ft void *
|
||||||
|
.Fn fts_get_clientptr "FTS *ftsp"
|
||||||
|
.Ft FTS *
|
||||||
|
.Fn fts_get_stream "FTSENT *f"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn fts_close "FTS *ftsp"
|
.Fn fts_close "FTS *ftsp"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
@ -105,6 +111,26 @@ and
|
|||||||
.Dq Fa FTSENT No structure
|
.Dq Fa FTSENT No structure
|
||||||
are generally
|
are generally
|
||||||
interchangeable.
|
interchangeable.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fa FTS
|
||||||
|
structure contains space for a single pointer, which may be used to
|
||||||
|
store application data or per-hierarchy state.
|
||||||
|
The
|
||||||
|
.Fn fts_set_clientptr
|
||||||
|
and
|
||||||
|
.Fn fts_get_clientptr
|
||||||
|
functions may be used to set and retrieve this pointer.
|
||||||
|
This is likely to be useful only when accessed from the sort
|
||||||
|
comparison function, which can determine the original
|
||||||
|
.Fa FTS
|
||||||
|
stream of its arguments using the
|
||||||
|
.Fn fts_get_stream
|
||||||
|
function.
|
||||||
|
The two
|
||||||
|
.Li get
|
||||||
|
functions are also available as macros of the same name.
|
||||||
|
.Pp
|
||||||
The
|
The
|
||||||
.Fa FTSENT
|
.Fa FTSENT
|
||||||
structure contains at least the following fields, which are
|
structure contains at least the following fields, which are
|
||||||
@ -753,9 +779,18 @@ The options were invalid.
|
|||||||
.Xr chdir 2 ,
|
.Xr chdir 2 ,
|
||||||
.Xr stat 2 ,
|
.Xr stat 2 ,
|
||||||
.Xr qsort 3
|
.Xr qsort 3
|
||||||
.Sh STANDARDS
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
utility is expected to be included in a future
|
interface was first introduced in
|
||||||
.St -p1003.1-88
|
.Bx 4.4 .
|
||||||
revision.
|
The
|
||||||
|
.Fn fts_get_clientptr ,
|
||||||
|
.Fn fts_get_stream ,
|
||||||
|
and
|
||||||
|
.Fn fts_set_clientptr
|
||||||
|
functions were introduced in
|
||||||
|
.Fx 5.0 ,
|
||||||
|
principally to provide for alternative interfaces to the
|
||||||
|
.Nm
|
||||||
|
functionality using different data structures.
|
||||||
|
@ -81,7 +81,7 @@ FTS *
|
|||||||
fts_open(argv, options, compar)
|
fts_open(argv, options, compar)
|
||||||
char * const *argv;
|
char * const *argv;
|
||||||
int options;
|
int options;
|
||||||
int (*compar)(const FTSENT **, const FTSENT **);
|
int (*compar)(const FTSENT * const *, const FTSENT * const *);
|
||||||
{
|
{
|
||||||
FTS *sp;
|
FTS *sp;
|
||||||
FTSENT *p, *root;
|
FTSENT *p, *root;
|
||||||
@ -96,7 +96,7 @@ fts_open(argv, options, compar)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate/initialize the stream */
|
/* Allocate/initialize the stream */
|
||||||
if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
|
if ((sp = malloc(sizeof(FTS))) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
memset(sp, 0, sizeof(FTS));
|
memset(sp, 0, sizeof(FTS));
|
||||||
sp->fts_compar = compar;
|
sp->fts_compar = compar;
|
||||||
@ -547,6 +547,34 @@ fts_children(sp, instr)
|
|||||||
return (sp->fts_child);
|
return (sp->fts_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef fts_get_clientptr
|
||||||
|
#error "fts_get_clientptr not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *
|
||||||
|
(fts_get_clientptr)(FTS *sp)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (fts_get_clientptr(sp));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef fts_get_stream
|
||||||
|
#error "fts_get_stream not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FTS *
|
||||||
|
(fts_get_stream)(FTSENT *p)
|
||||||
|
{
|
||||||
|
return (fts_get_stream(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fts_set_clientptr(FTS *sp, void *clientptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
sp->fts_clientptr = clientptr;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
* idea is to build the linked list of entries that are used by fts_children
|
* idea is to build the linked list of entries that are used by fts_children
|
||||||
@ -907,6 +935,21 @@ err: memset(sbp, 0, sizeof(struct stat));
|
|||||||
return (FTS_DEFAULT);
|
return (FTS_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The comparison function takes pointers to pointers to FTSENT structures.
|
||||||
|
* Qsort wants a comparison function that takes pointers to void.
|
||||||
|
* (Both with appropriate levels of const-poisoning, of course!)
|
||||||
|
* Use a trampoline function to deal with the difference.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
fts_compar(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
FTS *parent;
|
||||||
|
|
||||||
|
parent = (*(const FTSENT * const *)a)->fts_fts;
|
||||||
|
return (*parent->fts_compar)(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
static FTSENT *
|
static FTSENT *
|
||||||
fts_sort(sp, head, nitems)
|
fts_sort(sp, head, nitems)
|
||||||
FTS *sp;
|
FTS *sp;
|
||||||
@ -932,7 +975,7 @@ fts_sort(sp, head, nitems)
|
|||||||
}
|
}
|
||||||
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;
|
||||||
qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
|
qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
|
||||||
for (head = *(ap = sp->fts_array); --nitems; ++ap)
|
for (head = *(ap = sp->fts_array); --nitems; ++ap)
|
||||||
ap[0]->fts_link = ap[1];
|
ap[0]->fts_link = ap[1];
|
||||||
ap[0]->fts_link = NULL;
|
ap[0]->fts_link = NULL;
|
||||||
@ -948,26 +991,36 @@ fts_alloc(sp, name, namelen)
|
|||||||
FTSENT *p;
|
FTSENT *p;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
struct ftsent_withstat {
|
||||||
|
FTSENT ent;
|
||||||
|
struct stat statbuf;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The file name is a variable length array and no stat structure is
|
* 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
|
* necessary if the user has set the nostat bit. Allocate the FTSENT
|
||||||
* structure, the file name and the stat structure in one chunk, but
|
* structure, the file name and the stat structure in one chunk, but
|
||||||
* be careful that the stat structure is reasonably aligned. Since the
|
* be careful that the stat structure is reasonably aligned.
|
||||||
* 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;
|
if (ISSET(FTS_NOSTAT))
|
||||||
if (!ISSET(FTS_NOSTAT))
|
len = sizeof(FTSENT) + namelen + 1;
|
||||||
len += sizeof(struct stat) + ALIGNBYTES;
|
else
|
||||||
|
len = sizeof(struct ftsent_withstat) + namelen + 1;
|
||||||
|
|
||||||
if ((p = malloc(len)) == NULL)
|
if ((p = malloc(len)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
/* Copy the name and guarantee NUL termination. */
|
if (ISSET(FTS_NOSTAT)) {
|
||||||
memmove(p->fts_name, name, namelen);
|
p->fts_name = (char *)(p + 1);
|
||||||
p->fts_name[namelen] = '\0';
|
p->fts_statp = NULL;
|
||||||
|
} else {
|
||||||
|
p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
|
||||||
|
p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ISSET(FTS_NOSTAT))
|
/* Copy the name and guarantee NUL termination. */
|
||||||
p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
|
memcpy(p->fts_name, name, namelen);
|
||||||
|
p->fts_name[namelen] = '\0';
|
||||||
p->fts_namelen = namelen;
|
p->fts_namelen = namelen;
|
||||||
p->fts_path = sp->fts_path;
|
p->fts_path = sp->fts_path;
|
||||||
p->fts_errno = 0;
|
p->fts_errno = 0;
|
||||||
@ -975,6 +1028,7 @@ fts_alloc(sp, name, namelen)
|
|||||||
p->fts_instr = FTS_NOINSTR;
|
p->fts_instr = FTS_NOINSTR;
|
||||||
p->fts_number = 0;
|
p->fts_number = 0;
|
||||||
p->fts_pointer = NULL;
|
p->fts_pointer = NULL;
|
||||||
|
p->fts_fts = sp;
|
||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "find.h"
|
#include "find.h"
|
||||||
|
|
||||||
static int find_compare(const FTSENT **s1, const FTSENT **s2);
|
static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_compare --
|
* find_compare --
|
||||||
@ -66,7 +66,7 @@ static int find_compare(const FTSENT **s1, const FTSENT **s2);
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
find_compare(s1, s2)
|
find_compare(s1, s2)
|
||||||
const FTSENT **s1, **s2;
|
const FTSENT * const *s1, * const *s2;
|
||||||
{
|
{
|
||||||
|
|
||||||
return (strcoll((*s1)->fts_name, (*s2)->fts_name));
|
return (strcoll((*s1)->fts_name, (*s2)->fts_name));
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
#define DEFAULT_NUM 1 /* Default number of pieces mailed per run. */
|
#define DEFAULT_NUM 1 /* Default number of pieces mailed per run. */
|
||||||
|
|
||||||
int fts_sort(const FTSENT **, const FTSENT **);
|
int fts_sort(const FTSENT * const *, const FTSENT * const *);
|
||||||
int run_sendmail(int ifd);
|
int run_sendmail(int ifd);
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -156,7 +156,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fts_sort(const FTSENT ** a, const FTSENT ** b)
|
fts_sort(const FTSENT * const * a, const FTSENT * const * b)
|
||||||
{
|
{
|
||||||
if ((*a)->fts_info != FTS_F)
|
if ((*a)->fts_info != FTS_F)
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -80,7 +80,7 @@ static uid_t uid;
|
|||||||
static mode_t mode;
|
static mode_t mode;
|
||||||
static u_long flags = 0xffffffff;
|
static u_long flags = 0xffffffff;
|
||||||
|
|
||||||
static int dsort(const FTSENT **, const FTSENT **);
|
static int dsort(const FTSENT * const *, const FTSENT * const *);
|
||||||
static void output(int, int *, const char *, ...) __printflike(3, 4);
|
static void output(int, int *, const char *, ...) __printflike(3, 4);
|
||||||
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
|
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
|
||||||
static void statf(int, FTSENT *);
|
static void statf(int, FTSENT *);
|
||||||
@ -398,7 +398,7 @@ statd(t, parent, puid, pgid, pmode, pflags)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
dsort(a, b)
|
dsort(a, b)
|
||||||
const FTSENT **a, **b;
|
const FTSENT * const *a, * const *b;
|
||||||
{
|
{
|
||||||
if (S_ISDIR((*a)->fts_statp->st_mode)) {
|
if (S_ISDIR((*a)->fts_statp->st_mode)) {
|
||||||
if (!S_ISDIR((*b)->fts_statp->st_mode))
|
if (!S_ISDIR((*b)->fts_statp->st_mode))
|
||||||
|
@ -40,7 +40,7 @@ struct store {
|
|||||||
static int rex_match(const char *, const char *);
|
static int rex_match(const char *, const char *);
|
||||||
struct store *storecreate(struct store *);
|
struct store *storecreate(struct store *);
|
||||||
static int storeappend(struct store *, const char *);
|
static int storeappend(struct store *, const char *);
|
||||||
static int fname_cmp(const FTSENT **, const FTSENT **);
|
static int fname_cmp(const FTSENT * const *, const FTSENT * const *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to query names of installed packages.
|
* Function to query names of installed packages.
|
||||||
@ -337,7 +337,7 @@ storeappend(struct store *store, const char *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fname_cmp(const FTSENT **a, const FTSENT **b)
|
fname_cmp(const FTSENT * const *a, const FTSENT * const *b)
|
||||||
{
|
{
|
||||||
return strcmp((*a)->fts_name, (*b)->fts_name);
|
return strcmp((*a)->fts_name, (*b)->fts_name);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user