1 Add an implementation of the fts_*() functions
3 The fts_*() functions are optional in uClibc, and not compiled in our
4 default configuration. The best option would be to migrate this
5 elfutils code to the nftw family of functions, but it requires quite
8 So we have several options here:
10 *) Enable fts_*() functions in our default uClibc configuration. Not
11 nice since only one package needs them (the help text of uClibc
12 for fts_*() functions explicitly mention that they have been added
13 to be able to build elfutils).
15 *) Use gnulib, but it is quite heavy to setup, requires modifications
16 to configure.ac, and other things.
18 *) Copy the fts function from uClibc into elfutils source code. This
19 is the solution used below. uClibc is LGPL, and elfutils is
20 LGPL/GPL, so there should not be any licensing issue.
22 Of course, the fts_*() functions are only built if they are not
23 already provided by the C library.
25 Based on the former patch by Thomas Petazzoni.
27 [Vincent: tweak patch for 0.166]
29 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
30 Signed-off-by: Vicente Olivert Riera <Vincent.Riera@imgtec.com>
32 diff -Nrup a/configure.ac b/configure.ac
33 --- a/configure.ac 2016-06-17 14:47:03.561704498 +0100
34 +++ b/configure.ac 2016-06-17 14:52:35.038200412 +0100
35 @@ -259,6 +259,10 @@ AC_ARG_ENABLE([progs],
37 AM_CONDITIONAL(ENABLE_PROGS, test "$enable_progs" = yes)
39 +AC_CHECK_HEADER([fts.h],
40 + AC_DEFINE([HAVE_FTS_H], [], [Define if <fts.h> is available in C library]))
41 +AM_CONDITIONAL(HAVE_FTS, test "$ac_cv_header_fts_h" = yes)
43 dnl zlib is mandatory.
46 diff -Nrup a/libdwfl/fts.c b/libdwfl/fts.c
47 --- a/libdwfl/fts.c 1970-01-01 01:00:00.000000000 +0100
48 +++ b/libdwfl/fts.c 2016-06-17 14:57:26.649912084 +0100
51 + * Copyright (c) 1990, 1993, 1994
52 + * The Regents of the University of California. All rights reserved.
54 + * Redistribution and use in source and binary forms, with or without
55 + * modification, are permitted provided that the following conditions
57 + * 1. Redistributions of source code must retain the above copyright
58 + * notice, this list of conditions and the following disclaimer.
59 + * 2. Redistributions in binary form must reproduce the above copyright
60 + * notice, this list of conditions and the following disclaimer in the
61 + * documentation and/or other materials provided with the distribution.
62 + * 4. Neither the name of the University nor the names of its contributors
63 + * may be used to endorse or promote products derived from this software
64 + * without specific prior written permission.
66 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
67 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
68 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
69 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
70 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
71 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
72 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
73 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
74 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
75 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
79 +#include <sys/param.h>
80 +#include <sys/stat.h>
89 +/* Largest alignment size needed, minus one.
90 + Usually long double is the worst case. */
92 +#define ALIGNBYTES (__alignof__ (long double) - 1)
94 +/* Align P to that size. */
96 +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
100 +static FTSENT *fts_alloc (FTS *, const char *, size_t);
101 +static FTSENT *fts_build (FTS *, int);
102 +static void fts_lfree (FTSENT *);
103 +static void fts_load (FTS *, FTSENT *);
104 +static size_t fts_maxarglen (char * const *);
105 +static void fts_padjust (FTS *, FTSENT *);
106 +static int fts_palloc (FTS *, size_t);
107 +static FTSENT *fts_sort (FTS *, FTSENT *, int);
108 +static u_short fts_stat (FTS *, FTSENT *, int);
109 +static int fts_safe_changedir (FTS *, FTSENT *, int, const char *);
112 +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
113 + __typeof__ (b) _b = (b); \
114 + _a > _b ? _a : _b; })
117 +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
119 +#define CLR(opt) (sp->fts_options &= ~(opt))
120 +#define ISSET(opt) (sp->fts_options & (opt))
121 +#define SET(opt) (sp->fts_options |= (opt))
123 +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
125 +/* fts_build flags */
126 +#define BCHILD 1 /* fts_children */
127 +#define BNAMES 2 /* fts_children, names only */
128 +#define BREAD 3 /* fts_read */
131 +fts_open( char * const *argv, register int options,
132 + int (*compar) (const FTSENT **, const FTSENT **))
135 + register FTSENT *p, *root;
136 + register int nitems;
137 + FTSENT *parent = NULL;
138 + FTSENT *tmp = NULL;
140 + /* Options check. */
141 + if (options & ~FTS_OPTIONMASK) {
146 + /* Allocate/initialize the stream */
147 + if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
149 + memset(sp, 0, sizeof(FTS));
150 + sp->fts_compar = (int (*) (const void *, const void *)) compar;
151 + sp->fts_options = options;
153 + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
154 + if (ISSET(FTS_LOGICAL))
158 + * Start out with 1K of path space, and enough, in any case,
159 + * to hold the user's paths.
162 +#define MAXPATHLEN 1024
164 + size_t maxarglen = fts_maxarglen(argv);
165 + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
168 + /* Allocate/initialize root's parent. */
169 + if (*argv != NULL) {
170 + if ((parent = fts_alloc(sp, "", 0)) == NULL)
172 + parent->fts_level = FTS_ROOTPARENTLEVEL;
175 + /* Allocate/initialize root(s). */
176 + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
177 + /* Don't allow zero-length paths. */
178 + size_t len = strlen(*argv);
184 + p = fts_alloc(sp, *argv, len);
185 + p->fts_level = FTS_ROOTLEVEL;
186 + p->fts_parent = parent;
187 + p->fts_accpath = p->fts_name;
188 + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
190 + /* Command-line "." and ".." are real directories. */
191 + if (p->fts_info == FTS_DOT)
192 + p->fts_info = FTS_D;
195 + * If comparison routine supplied, traverse in sorted
196 + * order; otherwise traverse in the order specified.
199 + p->fts_link = root;
202 + p->fts_link = NULL;
211 + if (compar && nitems > 1)
212 + root = fts_sort(sp, root, nitems);
215 + * Allocate a dummy pointer and make fts_read think that we've just
216 + * finished the node before the root(s); set p->fts_info to FTS_INIT
217 + * so that everything about the "current" node is ignored.
219 + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
221 + sp->fts_cur->fts_link = root;
222 + sp->fts_cur->fts_info = FTS_INIT;
225 + * If using chdir(2), grab a file descriptor pointing to dot to ensure
226 + * that we can get back here; this could be avoided for some paths,
227 + * but almost certainly not worth the effort. Slashes, symbolic links,
228 + * and ".." are all fairly nasty problems. Note, if we can't get the
229 + * descriptor we run anyway, just more slowly.
231 + if (!ISSET(FTS_NOCHDIR)
232 + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
237 +mem3: fts_lfree(root);
239 +mem2: free(sp->fts_path);
245 +fts_load(FTS *sp, register FTSENT *p)
251 + * Load the stream structure for the next traversal. Since we don't
252 + * actually enter the directory until after the preorder visit, set
253 + * the fts_accpath field specially so the chdir gets done to the right
254 + * place and the user can access the first node. From fts_open it's
255 + * known that the path will fit.
257 + len = p->fts_pathlen = p->fts_namelen;
258 + memmove(sp->fts_path, p->fts_name, len + 1);
259 + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
260 + len = strlen(++cp);
261 + memmove(p->fts_name, cp, len + 1);
262 + p->fts_namelen = len;
264 + p->fts_accpath = p->fts_path = sp->fts_path;
265 + sp->fts_dev = p->fts_dev;
271 + register FTSENT *freep, *p;
275 + * This still works if we haven't read anything -- the dummy structure
276 + * points to the root list, so we step through to the end of the root
277 + * list which has a valid parent pointer.
280 + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
282 + p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
288 + /* Free up child linked list, sort array, path buffer. */
290 + fts_lfree(sp->fts_child);
291 + free(sp->fts_array);
292 + free(sp->fts_path);
294 + /* Return to original directory, save errno if necessary. */
295 + if (!ISSET(FTS_NOCHDIR)) {
296 + saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
297 + (void)close(sp->fts_rfd);
299 + /* Set errno and return. */
300 + if (saved_errno != 0) {
301 + /* Free up the stream pointer. */
303 + errno = saved_errno;
308 + /* Free up the stream pointer. */
314 + * Special case of "/" at the end of the path so that slashes aren't
315 + * appended which would cause paths to be written as "....//foo".
317 +#define NAPPEND(p) \
318 + (p->fts_path[p->fts_pathlen - 1] == '/' \
319 + ? p->fts_pathlen - 1 : p->fts_pathlen)
322 +fts_read(register FTS *sp)
324 + register FTSENT *p, *tmp;
325 + register int instr;
329 + /* If finished or unrecoverable error, return NULL. */
330 + if (sp->fts_cur == NULL || ISSET(FTS_STOP))
333 + /* Set current node pointer. */
336 + /* Save and zero out user instructions. */
337 + instr = p->fts_instr;
338 + p->fts_instr = FTS_NOINSTR;
340 + /* Any type of file may be re-visited; re-stat and re-turn. */
341 + if (instr == FTS_AGAIN) {
342 + p->fts_info = fts_stat(sp, p, 0);
347 + * Following a symlink -- SLNONE test allows application to see
348 + * SLNONE and recover. If indirecting through a symlink, have
349 + * keep a pointer to current location. If unable to get that
350 + * pointer, follow fails.
352 + if (instr == FTS_FOLLOW &&
353 + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
354 + p->fts_info = fts_stat(sp, p, 1);
355 + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
356 + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
357 + p->fts_errno = errno;
358 + p->fts_info = FTS_ERR;
360 + p->fts_flags |= FTS_SYMFOLLOW;
365 + /* Directory in pre-order. */
366 + if (p->fts_info == FTS_D) {
367 + /* If skipped or crossed mount point, do post-order visit. */
368 + if (instr == FTS_SKIP ||
369 + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
370 + if (p->fts_flags & FTS_SYMFOLLOW)
371 + (void)close(p->fts_symfd);
372 + if (sp->fts_child) {
373 + fts_lfree(sp->fts_child);
374 + sp->fts_child = NULL;
376 + p->fts_info = FTS_DP;
380 + /* Rebuild if only read the names and now traversing. */
381 + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
383 + fts_lfree(sp->fts_child);
384 + sp->fts_child = NULL;
388 + * Cd to the subdirectory.
390 + * If have already read and now fail to chdir, whack the list
391 + * to make the names come out right, and set the parent errno
392 + * so the application will eventually get an error condition.
393 + * Set the FTS_DONTCHDIR flag so that when we logically change
394 + * directories back to the parent we don't do a chdir.
396 + * If haven't read do so. If the read fails, fts_build sets
397 + * FTS_STOP or the fts_info field of the node.
399 + if (sp->fts_child != NULL) {
400 + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
401 + p->fts_errno = errno;
402 + p->fts_flags |= FTS_DONTCHDIR;
403 + for (p = sp->fts_child; p != NULL;
406 + p->fts_parent->fts_accpath;
408 + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
409 + if (ISSET(FTS_STOP))
414 + sp->fts_child = NULL;
419 + /* Move to the next node on this level. */
421 + if ((p = p->fts_link) != NULL) {
426 + * If reached the top, return to the original directory (or
427 + * the root of the tree), and load the paths for the next root.
429 + if (p->fts_level == FTS_ROOTLEVEL) {
430 + if (FCHDIR(sp, sp->fts_rfd)) {
439 + * User may have called fts_set on the node. If skipped,
440 + * ignore. If followed, get a file descriptor so we can
441 + * get back if necessary.
443 + if (p->fts_instr == FTS_SKIP)
445 + if (p->fts_instr == FTS_FOLLOW) {
446 + p->fts_info = fts_stat(sp, p, 1);
447 + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
448 + if ((p->fts_symfd =
449 + open(".", O_RDONLY, 0)) < 0) {
450 + p->fts_errno = errno;
451 + p->fts_info = FTS_ERR;
453 + p->fts_flags |= FTS_SYMFOLLOW;
455 + p->fts_instr = FTS_NOINSTR;
458 +name: t = sp->fts_path + NAPPEND(p->fts_parent);
460 + memmove(t, p->fts_name, p->fts_namelen + 1);
464 + /* Move up to the parent node. */
465 + p = tmp->fts_parent;
469 + if (p->fts_level == FTS_ROOTPARENTLEVEL) {
471 + * Done; free everything up and set errno to 0 so the user
472 + * can distinguish between error and EOF.
476 + return (sp->fts_cur = NULL);
479 + /* NUL terminate the pathname. */
480 + sp->fts_path[p->fts_pathlen] = '\0';
483 + * Return to the parent directory. If at a root node or came through
484 + * a symlink, go back through the file descriptor. Otherwise, cd up
487 + if (p->fts_level == FTS_ROOTLEVEL) {
488 + if (FCHDIR(sp, sp->fts_rfd)) {
492 + } else if (p->fts_flags & FTS_SYMFOLLOW) {
493 + if (FCHDIR(sp, p->fts_symfd)) {
494 + saved_errno = errno;
495 + (void)close(p->fts_symfd);
496 + errno = saved_errno;
500 + (void)close(p->fts_symfd);
501 + } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
502 + fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
506 + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
511 + * Fts_set takes the stream as an argument although it's not used in this
512 + * implementation; it would be necessary if anyone wanted to add global
513 + * semantics to fts using fts_set. An error return is allowed for similar
518 +fts_set(FTS *sp, FTSENT *p, int instr)
520 + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
521 + instr != FTS_NOINSTR && instr != FTS_SKIP) {
525 + p->fts_instr = instr;
530 +fts_children(register FTS *sp, int instr)
532 + register FTSENT *p;
535 + if (instr != 0 && instr != FTS_NAMEONLY) {
540 + /* Set current node pointer. */
544 + * Errno set to 0 so user can distinguish empty directory from
549 + /* Fatal errors stop here. */
550 + if (ISSET(FTS_STOP))
553 + /* Return logical hierarchy of user's arguments. */
554 + if (p->fts_info == FTS_INIT)
555 + return (p->fts_link);
558 + * If not a directory being visited in pre-order, stop here. Could
559 + * allow FTS_DNR, assuming the user has fixed the problem, but the
560 + * same effect is available with FTS_AGAIN.
562 + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
565 + /* Free up any previous child list. */
566 + if (sp->fts_child != NULL)
567 + fts_lfree(sp->fts_child);
569 + if (instr == FTS_NAMEONLY) {
576 + * If using chdir on a relative path and called BEFORE fts_read does
577 + * its chdir to the root of a traversal, we can lose -- we need to
578 + * chdir into the subdirectory, and we don't know where the current
579 + * directory is, so we can't get back so that the upcoming chdir by
580 + * fts_read will work.
582 + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
583 + ISSET(FTS_NOCHDIR))
584 + return (sp->fts_child = fts_build(sp, instr));
586 + if ((fd = open(".", O_RDONLY, 0)) < 0)
588 + sp->fts_child = fts_build(sp, instr);
592 + return (sp->fts_child);
596 + * This is the tricky part -- do not casually change *anything* in here. The
597 + * idea is to build the linked list of entries that are used by fts_children
598 + * and fts_read. There are lots of special cases.
600 + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
601 + * set and it's a physical walk (so that symbolic links can't be directories),
602 + * we can do things quickly. First, if it's a 4.4BSD file system, the type
603 + * of the file is in the directory entry. Otherwise, we assume that the number
604 + * of subdirectories in a node is equal to the number of links to the parent.
605 + * The former skips all stat calls. The latter skips stat calls in any leaf
606 + * directories and for any files after the subdirectories in the directory have
607 + * been found, cutting the stat calls by about 2/3.
610 +fts_build(register FTS *sp, int type)
612 + register struct dirent *dp;
613 + register FTSENT *p, *head;
614 + register int nitems;
615 + FTSENT *cur, *tail;
618 + int cderrno, descend, len, level, nlinks, saved_errno,
623 + /* Set current node pointer. */
627 + * Open the directory for reading. If this fails, we're done.
628 + * If being called from fts_read, set the fts_info field.
630 +#if defined FTS_WHITEOUT && 0
631 + if (ISSET(FTS_WHITEOUT))
632 + oflag = DTF_NODUP|DTF_REWIND;
634 + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
636 +# define opendir2(path, flag) opendir(path)
638 + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
639 + if (type == BREAD) {
640 + cur->fts_info = FTS_DNR;
641 + cur->fts_errno = errno;
647 + * Nlinks is the number of possible entries of type directory in the
648 + * directory if we're cheating on stat calls, 0 if we're not doing
649 + * any stat calls at all, -1 if we're doing stats on everything.
651 + if (type == BNAMES) {
653 + /* Be quiet about nostat, GCC. */
655 + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
656 + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
664 + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
665 + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
666 + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
669 + * If we're going to need to stat anything or we want to descend
670 + * and stay in the directory, chdir. If this fails we keep going,
671 + * but set a flag so we don't chdir after the post-order visit.
672 + * We won't be able to stat anything, but we can still return the
673 + * names themselves. Note, that since fts_read won't be able to
674 + * chdir into the directory, it will have to return different path
675 + * names than before, i.e. "a/b" instead of "b". Since the node
676 + * has already been visited in pre-order, have to wait until the
677 + * post-order visit to return the error. There is a special case
678 + * here, if there was nothing to stat then it's not an error to
679 + * not be able to stat. This is all fairly nasty. If a program
680 + * needed sorted entries or stat information, they had better be
681 + * checking FTS_NS on the returned nodes.
684 + if (nlinks || type == BREAD) {
685 + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
686 + if (nlinks && type == BREAD)
687 + cur->fts_errno = errno;
688 + cur->fts_flags |= FTS_DONTCHDIR;
691 + (void)closedir(dirp);
699 + * Figure out the max file name length that can be stored in the
700 + * current path -- the inner loop allocates more path as necessary.
701 + * We really wouldn't have to do the maxlen calculations here, we
702 + * could do them in fts_read before returning the path, but it's a
703 + * lot easier here since the length is part of the dirent structure.
705 + * If not changing directories set a pointer so that can just append
706 + * each new name into the path.
708 + len = NAPPEND(cur);
709 + if (ISSET(FTS_NOCHDIR)) {
710 + cp = sp->fts_path + len;
713 + /* GCC, you're too verbose. */
717 + maxlen = sp->fts_pathlen - len;
719 + level = cur->fts_level + 1;
721 + /* Read the directory, attaching each entry to the `link' pointer. */
723 + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
724 + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
727 + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
729 + if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
730 + oldaddr = sp->fts_path;
731 + if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
733 + * No more memory for path or structures. Save
734 + * errno, free up the current structure and the
735 + * structures already allocated.
737 +mem1: saved_errno = errno;
740 + (void)closedir(dirp);
741 + cur->fts_info = FTS_ERR;
743 + errno = saved_errno;
746 + /* Did realloc() change the pointer? */
747 + if (oldaddr != sp->fts_path) {
749 + if (ISSET(FTS_NOCHDIR))
750 + cp = sp->fts_path + len;
752 + maxlen = sp->fts_pathlen - len;
755 + if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
757 + * In an FTSENT, fts_pathlen is a u_short so it is
758 + * possible to wraparound here. If we do, free up
759 + * the current structure and the structures already
760 + * allocated, then error out with ENAMETOOLONG.
764 + (void)closedir(dirp);
765 + cur->fts_info = FTS_ERR;
767 + errno = ENAMETOOLONG;
770 + p->fts_level = level;
771 + p->fts_parent = sp->fts_cur;
772 + p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
774 +#if defined FTS_WHITEOUT && 0
775 + if (dp->d_type == DT_WHT)
776 + p->fts_flags |= FTS_ISW;
780 + /* Unreachable code. cderrno is only ever set to a nonnull
781 + value if dirp is closed at the same time. But then we
782 + cannot enter this loop. */
785 + p->fts_info = FTS_NS;
786 + p->fts_errno = cderrno;
788 + p->fts_info = FTS_NSOK;
789 + p->fts_accpath = cur->fts_accpath;
793 +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
795 + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
799 + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
800 + p->fts_info = FTS_NSOK;
802 + /* Build a file name for fts_stat to stat. */
803 + if (ISSET(FTS_NOCHDIR)) {
804 + p->fts_accpath = p->fts_path;
805 + memmove(cp, p->fts_name, p->fts_namelen + 1);
807 + p->fts_accpath = p->fts_name;
809 + p->fts_info = fts_stat(sp, p, 0);
811 + /* Decrement link count if applicable. */
812 + if (nlinks > 0 && (p->fts_info == FTS_D ||
813 + p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
817 + /* We walk in directory order so "ls -f" doesn't get upset. */
818 + p->fts_link = NULL;
822 + tail->fts_link = p;
828 + (void)closedir(dirp);
831 + * If realloc() changed the address of the path, adjust the
832 + * addresses for the rest of the tree and the dir list.
835 + fts_padjust(sp, head);
838 + * If not changing directories, reset the path back to original
841 + if (ISSET(FTS_NOCHDIR)) {
842 + if (len == sp->fts_pathlen || nitems == 0)
848 + * If descended after called from fts_children or after called from
849 + * fts_read and nothing found, get back. At the root level we use
850 + * the saved fd; if one of fts_open()'s arguments is a relative path
851 + * to an empty directory, we wind up here with no other way back. If
852 + * can't get back, we're done.
854 + if (descend && (type == BCHILD || !nitems) &&
855 + (cur->fts_level == FTS_ROOTLEVEL ?
856 + FCHDIR(sp, sp->fts_rfd) :
857 + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
858 + cur->fts_info = FTS_ERR;
864 + /* If didn't find anything, return NULL. */
867 + cur->fts_info = FTS_DP;
872 + /* Sort the entries. */
873 + if (sp->fts_compar && nitems > 1)
874 + head = fts_sort(sp, head, nitems);
879 +fts_stat(FTS *sp, register FTSENT *p, int follow)
881 + register FTSENT *t;
882 + register dev_t dev;
883 + register ino_t ino;
884 + struct stat *sbp, sb;
887 + /* If user needs stat info, stat buffer already allocated. */
888 + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
890 +#if defined FTS_WHITEOUT && 0
891 + /* check for whiteout */
892 + if (p->fts_flags & FTS_ISW) {
894 + memset(sbp, '\0', sizeof (*sbp));
895 + sbp->st_mode = S_IFWHT;
902 + * If doing a logical walk, or application requested FTS_FOLLOW, do
903 + * a stat(2). If that fails, check for a non-existent symlink. If
904 + * fail, set the errno from the stat call.
906 + if (ISSET(FTS_LOGICAL) || follow) {
907 + if (stat(p->fts_accpath, sbp)) {
908 + saved_errno = errno;
909 + if (!lstat(p->fts_accpath, sbp)) {
911 + return (FTS_SLNONE);
913 + p->fts_errno = saved_errno;
916 + } else if (lstat(p->fts_accpath, sbp)) {
917 + p->fts_errno = errno;
918 +err: memset(sbp, 0, sizeof(struct stat));
922 + if (S_ISDIR(sbp->st_mode)) {
924 + * Set the device/inode. Used to find cycles and check for
925 + * crossing mount points. Also remember the link count, used
926 + * in fts_build to limit the number of stat calls. It is
927 + * understood that these fields are only referenced if fts_info
930 + dev = p->fts_dev = sbp->st_dev;
931 + ino = p->fts_ino = sbp->st_ino;
932 + p->fts_nlink = sbp->st_nlink;
934 + if (ISDOT(p->fts_name))
938 + * Cycle detection is done by brute force when the directory
939 + * is first encountered. If the tree gets deep enough or the
940 + * number of symbolic links to directories is high enough,
941 + * something faster might be worthwhile.
943 + for (t = p->fts_parent;
944 + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
945 + if (ino == t->fts_ino && dev == t->fts_dev) {
951 + if (S_ISLNK(sbp->st_mode))
953 + if (S_ISREG(sbp->st_mode))
955 + return (FTS_DEFAULT);
959 +fts_sort(FTS *sp, FTSENT *head, register int nitems)
961 + register FTSENT **ap, *p;
964 + * Construct an array of pointers to the structures and call qsort(3).
965 + * Reassemble the array in the order returned by qsort. If unable to
966 + * sort for memory reasons, return the directory entries in their
967 + * current order. Allocate enough space for the current needs plus
968 + * 40 so don't realloc one entry at a time.
970 + if (nitems > sp->fts_nitems) {
971 + struct _ftsent **a;
973 + sp->fts_nitems = nitems + 40;
974 + if ((a = realloc(sp->fts_array,
975 + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
976 + free(sp->fts_array);
977 + sp->fts_array = NULL;
978 + sp->fts_nitems = 0;
983 + for (ap = sp->fts_array, p = head; p; p = p->fts_link)
985 + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
986 + for (head = *(ap = sp->fts_array); --nitems; ++ap)
987 + ap[0]->fts_link = ap[1];
988 + ap[0]->fts_link = NULL;
993 +fts_alloc(FTS *sp, const char *name, size_t namelen)
995 + register FTSENT *p;
999 + * The file name is a variable length array and no stat structure is
1000 + * necessary if the user has set the nostat bit. Allocate the FTSENT
1001 + * structure, the file name and the stat structure in one chunk, but
1002 + * be careful that the stat structure is reasonably aligned. Since the
1003 + * fts_name field is declared to be of size 1, the fts_name pointer is
1004 + * namelen + 2 before the first possible address of the stat structure.
1006 + len = sizeof(FTSENT) + namelen;
1007 + if (!ISSET(FTS_NOSTAT))
1008 + len += sizeof(struct stat) + ALIGNBYTES;
1009 + if ((p = malloc(len)) == NULL)
1012 + /* Copy the name and guarantee NUL termination. */
1013 + memmove(p->fts_name, name, namelen);
1014 + p->fts_name[namelen] = '\0';
1016 + if (!ISSET(FTS_NOSTAT))
1017 + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
1018 + p->fts_namelen = namelen;
1019 + p->fts_path = sp->fts_path;
1022 + p->fts_instr = FTS_NOINSTR;
1023 + p->fts_number = 0;
1024 + p->fts_pointer = NULL;
1029 +fts_lfree(register FTSENT *head)
1031 + register FTSENT *p;
1033 + /* Free a linked list of structures. */
1034 + while ((p = head)) {
1035 + head = head->fts_link;
1041 + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
1042 + * Most systems will allow creation of paths much longer than MAXPATHLEN, even
1043 + * though the kernel won't resolve them. Add the size (not just what's needed)
1044 + * plus 256 bytes so don't realloc the path 2 bytes at a time.
1047 +fts_palloc(FTS *sp, size_t more)
1051 + sp->fts_pathlen += more + 256;
1053 + * Check for possible wraparound. In an FTS, fts_pathlen is
1054 + * a signed int but in an FTSENT it is an unsigned short.
1055 + * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
1057 + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
1058 + free(sp->fts_path);
1059 + sp->fts_path = NULL;
1060 + errno = ENAMETOOLONG;
1063 + p = realloc(sp->fts_path, sp->fts_pathlen);
1065 + free(sp->fts_path);
1066 + sp->fts_path = NULL;
1074 + * When the path is realloc'd, have to fix all of the pointers in structures
1075 + * already returned.
1078 +fts_padjust(FTS *sp, FTSENT *head)
1081 + char *addr = sp->fts_path;
1083 +#define ADJUST(p) do { \
1084 + if ((p)->fts_accpath != (p)->fts_name) { \
1085 + (p)->fts_accpath = \
1086 + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
1088 + (p)->fts_path = addr; \
1090 + /* Adjust the current set of children. */
1091 + for (p = sp->fts_child; p; p = p->fts_link)
1094 + /* Adjust the rest of the tree, including the current level. */
1095 + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1097 + p = p->fts_link ? p->fts_link : p->fts_parent;
1102 +fts_maxarglen(char * const *argv)
1106 + for (max = 0; *argv; ++argv)
1107 + if ((len = strlen(*argv)) > max)
1113 + * Change to dir specified by fd or p->fts_accpath without getting
1114 + * tricked by someone changing the world out from underneath us.
1115 + * Assumes p->fts_dev and p->fts_ino are filled in.
1118 +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
1120 + int ret, oerrno, newfd;
1124 + if (ISSET(FTS_NOCHDIR))
1126 + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
1128 + if (fstat64(newfd, &sb)) {
1132 + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
1133 + errno = ENOENT; /* disinformation */
1137 + ret = fchdir(newfd);
1141 + (void)close(newfd);
1145 diff -Nrup a/libdwfl/fts_.h b/libdwfl/fts_.h
1146 --- a/libdwfl/fts_.h 1970-01-01 01:00:00.000000000 +0100
1147 +++ b/libdwfl/fts_.h 2016-06-17 14:58:42.003387566 +0100
1150 + * Copyright (c) 1989, 1993
1151 + * The Regents of the University of California. All rights reserved.
1153 + * Redistribution and use in source and binary forms, with or without
1154 + * modification, are permitted provided that the following conditions
1156 + * 1. Redistributions of source code must retain the above copyright
1157 + * notice, this list of conditions and the following disclaimer.
1158 + * 2. Redistributions in binary form must reproduce the above copyright
1159 + * notice, this list of conditions and the following disclaimer in the
1160 + * documentation and/or other materials provided with the distribution.
1161 + * 4. Neither the name of the University nor the names of its contributors
1162 + * may be used to endorse or promote products derived from this software
1163 + * without specific prior written permission.
1165 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1166 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1167 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1168 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1169 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1170 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1171 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1172 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1173 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1174 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1177 + * @(#)fts.h 8.3 (Berkeley) 8/14/94
1183 +#include <features.h>
1184 +#include <sys/types.h>
1186 +/* The fts interface is incompatible with the LFS interface which
1187 + transparently uses the 64-bit file access functions. */
1188 +#ifdef __USE_FILE_OFFSET64
1189 +# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
1194 + struct _ftsent *fts_cur; /* current node */
1195 + struct _ftsent *fts_child; /* linked list of children */
1196 + struct _ftsent **fts_array; /* sort array */
1197 + dev_t fts_dev; /* starting device # */
1198 + char *fts_path; /* path for this descent */
1199 + int fts_rfd; /* fd for root */
1200 + int fts_pathlen; /* sizeof(path) */
1201 + int fts_nitems; /* elements in the sort array */
1202 + int (*fts_compar) (const void *, const void *); /* compare fn */
1204 +#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
1205 +#define FTS_LOGICAL 0x0002 /* logical walk */
1206 +#define FTS_NOCHDIR 0x0004 /* don't change directories */
1207 +#define FTS_NOSTAT 0x0008 /* don't get stat info */
1208 +#define FTS_PHYSICAL 0x0010 /* physical walk */
1209 +#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
1210 +#define FTS_XDEV 0x0040 /* don't cross devices */
1211 +#define FTS_WHITEOUT 0x0080 /* return whiteout information */
1212 +#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
1214 +#define FTS_NAMEONLY 0x0100 /* (private) child names only */
1215 +#define FTS_STOP 0x0200 /* (private) unrecoverable error */
1216 + int fts_options; /* fts_open options, global flags */
1219 +typedef struct _ftsent {
1220 + struct _ftsent *fts_cycle; /* cycle node */
1221 + struct _ftsent *fts_parent; /* parent directory */
1222 + struct _ftsent *fts_link; /* next file in directory */
1223 + long fts_number; /* local numeric value */
1224 + void *fts_pointer; /* local address value */
1225 + char *fts_accpath; /* access path */
1226 + char *fts_path; /* root path */
1227 + int fts_errno; /* errno for this node */
1228 + int fts_symfd; /* fd for symlink */
1229 + u_short fts_pathlen; /* strlen(fts_path) */
1230 + u_short fts_namelen; /* strlen(fts_name) */
1232 + ino_t fts_ino; /* inode */
1233 + dev_t fts_dev; /* device */
1234 + nlink_t fts_nlink; /* link count */
1236 +#define FTS_ROOTPARENTLEVEL -1
1237 +#define FTS_ROOTLEVEL 0
1238 + short fts_level; /* depth (-1 to N) */
1240 +#define FTS_D 1 /* preorder directory */
1241 +#define FTS_DC 2 /* directory that causes cycles */
1242 +#define FTS_DEFAULT 3 /* none of the above */
1243 +#define FTS_DNR 4 /* unreadable directory */
1244 +#define FTS_DOT 5 /* dot or dot-dot */
1245 +#define FTS_DP 6 /* postorder directory */
1246 +#define FTS_ERR 7 /* error; errno is set */
1247 +#define FTS_F 8 /* regular file */
1248 +#define FTS_INIT 9 /* initialized only */
1249 +#define FTS_NS 10 /* stat(2) failed */
1250 +#define FTS_NSOK 11 /* no stat(2) requested */
1251 +#define FTS_SL 12 /* symbolic link */
1252 +#define FTS_SLNONE 13 /* symbolic link without target */
1253 +#define FTS_W 14 /* whiteout object */
1254 + u_short fts_info; /* user flags for FTSENT structure */
1256 +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
1257 +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
1258 + u_short fts_flags; /* private flags for FTSENT structure */
1260 +#define FTS_AGAIN 1 /* read node again */
1261 +#define FTS_FOLLOW 2 /* follow symbolic link */
1262 +#define FTS_NOINSTR 3 /* no instructions */
1263 +#define FTS_SKIP 4 /* discard node */
1264 + u_short fts_instr; /* fts_set() instructions */
1266 + struct stat *fts_statp; /* stat(2) information */
1267 + char fts_name[1]; /* file name */
1271 +FTSENT *fts_children (FTS *, int);
1272 +int fts_close (FTS *);
1273 +FTS *fts_open (char * const *, int,
1274 + int (*)(const FTSENT **, const FTSENT **));
1275 +FTSENT *fts_read (FTS *);
1276 +int fts_set (FTS *, FTSENT *, int) __THROW;
1280 diff -Nrup a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
1281 --- a/libdwfl/linux-kernel-modules.c 2016-03-02 16:25:38.000000000 +0000
1282 +++ b/libdwfl/linux-kernel-modules.c 2016-06-17 14:59:50.267724089 +0100
1284 /* We include this before config.h because it can't handle _FILE_OFFSET_BITS.
1285 Everything we need here is fine if its declarations just come first. */
1295 diff -Nrup a/libdwfl/Makefile.am b/libdwfl/Makefile.am
1296 --- a/libdwfl/Makefile.am 2016-01-12 12:49:19.000000000 +0000
1297 +++ b/libdwfl/Makefile.am 2016-06-17 15:01:03.492157569 +0100
1298 @@ -77,6 +77,9 @@ endif
1300 libdwfl_a_SOURCES += lzma.c
1303 +libdwfl_a_SOURCES += fts.c
1307 libdw = ../libdw/libdw.so