aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/cp/cp.c4
-rw-r--r--bin/ls/ls.c4
-rw-r--r--include/fts.h13
-rw-r--r--lib/libc/gen/fts-compat.c80
-rw-r--r--lib/libc/gen/fts-compat.h13
-rw-r--r--lib/libc/gen/fts.345
-rw-r--r--lib/libc/gen/fts.c80
-rw-r--r--usr.bin/find/find.c4
-rw-r--r--usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c4
-rw-r--r--usr.sbin/mtree/create.c4
-rw-r--r--usr.sbin/pkg_install/lib/match.c4
11 files changed, 206 insertions, 49 deletions
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 5a7834e7c1f3..10072094b3f0 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -92,7 +92,7 @@ static int Rflag, rflag;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
static int copy(char *[], enum op, int);
-static int mastercmp(const FTSENT **, const FTSENT **);
+static int mastercmp(const FTSENT * const *, const FTSENT * const *);
int
main(int argc, char *argv[])
@@ -484,7 +484,7 @@ copy(char *argv[], enum op type, int fts_options)
* files first reduces seeking.
*/
int
-mastercmp(const FTSENT **a, const FTSENT **b)
+mastercmp(const FTSENT * const *a, const FTSENT * const *b)
{
int a_info, b_info;
diff --git a/bin/ls/ls.c b/bin/ls/ls.c
index 71158deead22..be19f3634a82 100644
--- a/bin/ls/ls.c
+++ b/bin/ls/ls.c
@@ -82,7 +82,7 @@ __FBSDID("$FreeBSD$");
static void display(FTSENT *, FTSENT *);
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 (*printfcn)(DISPLAY *);
@@ -759,7 +759,7 @@ display(FTSENT *p, FTSENT *list)
* All other levels use the sort function. Error entries remain unsorted.
*/
static int
-mastercmp(const FTSENT **a, const FTSENT **b)
+mastercmp(const FTSENT * const *a, const FTSENT * const *b)
{
int a_info, b_info;
diff --git a/include/fts.h b/include/fts.h
index 8dd2c4160c10..09c4600a1072 100644
--- a/include/fts.h
+++ b/include/fts.h
@@ -47,7 +47,7 @@ typedef struct {
int fts_pathlen; /* sizeof(path) */
int fts_nitems; /* elements in the sort array */
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_LOGICAL 0x002 /* logical walk */
@@ -62,6 +62,7 @@ typedef struct {
#define FTS_NAMEONLY 0x100 /* (private) child names only */
#define FTS_STOP 0x200 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
+ void *fts_clientptr; /* thunk for sort function */
} FTS;
typedef struct _ftsent {
@@ -113,7 +114,8 @@ typedef struct _ftsent {
u_short fts_instr; /* fts_set() instructions */
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;
#include <sys/cdefs.h>
@@ -121,10 +123,15 @@ typedef struct _ftsent {
__BEGIN_DECLS
FTSENT *fts_children(FTS *, int);
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,
- int (*)(const FTSENT **, const FTSENT **));
+ int (*)(const FTSENT * const *, const FTSENT * const *));
FTSENT *fts_read(FTS *);
int fts_set(FTS *, FTSENT *, int);
+void fts_set_clientptr(FTS *, void *);
__END_DECLS
#endif /* !_FTS_H_ */
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
index 6220dc6f130c..7a0b068f6b57 100644
--- a/lib/libc/gen/fts-compat.c
+++ b/lib/libc/gen/fts-compat.c
@@ -81,7 +81,7 @@ FTS *
fts_open(argv, options, compar)
char * const *argv;
int options;
- int (*compar)(const FTSENT **, const FTSENT **);
+ int (*compar)(const FTSENT * const *, const FTSENT * const *);
{
FTS *sp;
FTSENT *p, *root;
@@ -96,7 +96,7 @@ fts_open(argv, options, compar)
}
/* Allocate/initialize the stream */
- if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
+ if ((sp = malloc(sizeof(FTS))) == NULL)
return (NULL);
memset(sp, 0, sizeof(FTS));
sp->fts_compar = compar;
@@ -547,6 +547,34 @@ fts_children(sp, instr)
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
* 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);
}
+/*
+ * 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 *
fts_sort(sp, head, nitems)
FTS *sp;
@@ -932,7 +975,7 @@ fts_sort(sp, head, nitems)
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*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)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
@@ -948,26 +991,36 @@ fts_alloc(sp, name, namelen)
FTSENT *p;
size_t len;
+ struct ftsent_withstat {
+ FTSENT ent;
+ struct stat statbuf;
+ };
+
/*
* 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.
+ * be careful that the stat structure is reasonably aligned.
*/
- len = sizeof(FTSENT) + namelen;
- if (!ISSET(FTS_NOSTAT))
- len += sizeof(struct stat) + ALIGNBYTES;
+ if (ISSET(FTS_NOSTAT))
+ len = sizeof(FTSENT) + namelen + 1;
+ else
+ len = sizeof(struct ftsent_withstat) + namelen + 1;
+
if ((p = malloc(len)) == NULL)
return (NULL);
+ if (ISSET(FTS_NOSTAT)) {
+ p->fts_name = (char *)(p + 1);
+ p->fts_statp = NULL;
+ } else {
+ p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
+ p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
+ }
+
/* Copy the name and guarantee NUL termination. */
- memmove(p->fts_name, name, namelen);
+ memcpy(p->fts_name, name, namelen);
p->fts_name[namelen] = '\0';
-
- if (!ISSET(FTS_NOSTAT))
- p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
p->fts_namelen = namelen;
p->fts_path = sp->fts_path;
p->fts_errno = 0;
@@ -975,6 +1028,7 @@ fts_alloc(sp, name, namelen)
p->fts_instr = FTS_NOINSTR;
p->fts_number = 0;
p->fts_pointer = NULL;
+ p->fts_fts = sp;
return (p);
}
diff --git a/lib/libc/gen/fts-compat.h b/lib/libc/gen/fts-compat.h
index 8dd2c4160c10..09c4600a1072 100644
--- a/lib/libc/gen/fts-compat.h
+++ b/lib/libc/gen/fts-compat.h
@@ -47,7 +47,7 @@ typedef struct {
int fts_pathlen; /* sizeof(path) */
int fts_nitems; /* elements in the sort array */
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_LOGICAL 0x002 /* logical walk */
@@ -62,6 +62,7 @@ typedef struct {
#define FTS_NAMEONLY 0x100 /* (private) child names only */
#define FTS_STOP 0x200 /* (private) unrecoverable error */
int fts_options; /* fts_open options, global flags */
+ void *fts_clientptr; /* thunk for sort function */
} FTS;
typedef struct _ftsent {
@@ -113,7 +114,8 @@ typedef struct _ftsent {
u_short fts_instr; /* fts_set() instructions */
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;
#include <sys/cdefs.h>
@@ -121,10 +123,15 @@ typedef struct _ftsent {
__BEGIN_DECLS
FTSENT *fts_children(FTS *, int);
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,
- int (*)(const FTSENT **, const FTSENT **));
+ int (*)(const FTSENT * const *, const FTSENT * const *));
FTSENT *fts_read(FTS *);
int fts_set(FTS *, FTSENT *, int);
+void fts_set_clientptr(FTS *, void *);
__END_DECLS
#endif /* !_FTS_H_ */
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index 1e40a81f924a..452626654db3 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -32,7 +32,7 @@
.\" @(#)fts.3 8.5 (Berkeley) 4/16/94
.\" $FreeBSD$
.\"
-.Dd April 16, 1994
+.Dd September 15, 2002
.Dt FTS 3
.Os
.Sh NAME
@@ -52,6 +52,12 @@
.Fn fts_children "FTS *ftsp" "int options"
.Ft int
.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
.Fn fts_close "FTS *ftsp"
.Sh DESCRIPTION
@@ -105,6 +111,26 @@ and
.Dq Fa FTSENT No structure
are generally
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
.Fa FTSENT
structure contains at least the following fields, which are
@@ -753,9 +779,18 @@ The options were invalid.
.Xr chdir 2 ,
.Xr stat 2 ,
.Xr qsort 3
-.Sh STANDARDS
+.Sh HISTORY
The
.Nm
-utility is expected to be included in a future
-.St -p1003.1-88
-revision.
+interface was first introduced in
+.Bx 4.4 .
+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.
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index 6220dc6f130c..7a0b068f6b57 100644
--- a/lib/libc/gen/fts.c
+++ b/lib/libc/gen/fts.c
@@ -81,7 +81,7 @@ FTS *
fts_open(argv, options, compar)
char * const *argv;
int options;
- int (*compar)(const FTSENT **, const FTSENT **);
+ int (*compar)(const FTSENT * const *, const FTSENT * const *);
{
FTS *sp;
FTSENT *p, *root;
@@ -96,7 +96,7 @@ fts_open(argv, options, compar)
}
/* Allocate/initialize the stream */
- if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
+ if ((sp = malloc(sizeof(FTS))) == NULL)
return (NULL);
memset(sp, 0, sizeof(FTS));
sp->fts_compar = compar;
@@ -547,6 +547,34 @@ fts_children(sp, instr)
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
* 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);
}
+/*
+ * 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 *
fts_sort(sp, head, nitems)
FTS *sp;
@@ -932,7 +975,7 @@ fts_sort(sp, head, nitems)
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*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)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
@@ -948,26 +991,36 @@ fts_alloc(sp, name, namelen)
FTSENT *p;
size_t len;
+ struct ftsent_withstat {
+ FTSENT ent;
+ struct stat statbuf;
+ };
+
/*
* 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.
+ * be careful that the stat structure is reasonably aligned.
*/
- len = sizeof(FTSENT) + namelen;
- if (!ISSET(FTS_NOSTAT))
- len += sizeof(struct stat) + ALIGNBYTES;
+ if (ISSET(FTS_NOSTAT))
+ len = sizeof(FTSENT) + namelen + 1;
+ else
+ len = sizeof(struct ftsent_withstat) + namelen + 1;
+
if ((p = malloc(len)) == NULL)
return (NULL);
+ if (ISSET(FTS_NOSTAT)) {
+ p->fts_name = (char *)(p + 1);
+ p->fts_statp = NULL;
+ } else {
+ p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
+ p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
+ }
+
/* Copy the name and guarantee NUL termination. */
- memmove(p->fts_name, name, namelen);
+ memcpy(p->fts_name, name, namelen);
p->fts_name[namelen] = '\0';
-
- if (!ISSET(FTS_NOSTAT))
- p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
p->fts_namelen = namelen;
p->fts_path = sp->fts_path;
p->fts_errno = 0;
@@ -975,6 +1028,7 @@ fts_alloc(sp, name, namelen)
p->fts_instr = FTS_NOINSTR;
p->fts_number = 0;
p->fts_pointer = NULL;
+ p->fts_fts = sp;
return (p);
}
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
index 5006e9ec7e32..4ef37e880807 100644
--- a/usr.bin/find/find.c
+++ b/usr.bin/find/find.c
@@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
#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 --
@@ -66,7 +66,7 @@ static int find_compare(const FTSENT **s1, const FTSENT **s2);
*/
static int
find_compare(s1, s2)
- const FTSENT **s1, **s2;
+ const FTSENT * const *s1, * const *s2;
{
return (strcoll((*s1)->fts_name, (*s2)->fts_name));
diff --git a/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c b/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
index b5a1411adeb4..783fd3f4a1a6 100644
--- a/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
+++ b/usr.sbin/ctm/ctm_dequeue/ctm_dequeue.c
@@ -53,7 +53,7 @@
#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
@@ -156,7 +156,7 @@ main(int argc, char **argv)
}
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)
return(0);
diff --git a/usr.sbin/mtree/create.c b/usr.sbin/mtree/create.c
index 3ab160299624..ae82966fe10e 100644
--- a/usr.sbin/mtree/create.c
+++ b/usr.sbin/mtree/create.c
@@ -80,7 +80,7 @@ static uid_t uid;
static mode_t mode;
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 int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
static void statf(int, FTSENT *);
@@ -398,7 +398,7 @@ statd(t, parent, puid, pgid, pmode, pflags)
static int
dsort(a, b)
- const FTSENT **a, **b;
+ const FTSENT * const *a, * const *b;
{
if (S_ISDIR((*a)->fts_statp->st_mode)) {
if (!S_ISDIR((*b)->fts_statp->st_mode))
diff --git a/usr.sbin/pkg_install/lib/match.c b/usr.sbin/pkg_install/lib/match.c
index cf745c32105c..5312c27c2041 100644
--- a/usr.sbin/pkg_install/lib/match.c
+++ b/usr.sbin/pkg_install/lib/match.c
@@ -40,7 +40,7 @@ struct store {
static int rex_match(const char *, const char *);
struct store *storecreate(struct store *);
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.
@@ -337,7 +337,7 @@ storeappend(struct store *store, const char *item)
}
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);
}