summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen/fts.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/gen/fts.c')
-rw-r--r--lib/libc/gen/fts.c80
1 files changed, 67 insertions, 13 deletions
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index 6220dc6..7a0b068 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);
}
OpenPOWER on IntegriCloud