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 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
28 Signed-off-by: Vicente Olivert Riera <Vincent.Riera@imgtec.com>
30 diff -Nrup a/configure.ac b/configure.ac
31 --- a/configure.ac 2015-01-06 11:37:38.397891424 +0000
32 +++ b/configure.ac 2015-01-06 11:40:53.568258759 +0000
33 @@ -266,6 +266,10 @@ AC_ARG_ENABLE([progs],
35 AM_CONDITIONAL(ENABLE_PROGS, test "$enable_progs" = yes)
37 +AC_CHECK_HEADER([fts.h],
38 + AC_DEFINE([HAVE_FTS_H], [], [Define if <fts.h> is available in C library]))
39 +AM_CONDITIONAL(HAVE_FTS, test "$ac_cv_header_fts_h" = yes)
41 dnl Test for zlib and bzlib, gives ZLIB/BZLIB .am
42 dnl conditional and config.h USE_ZLIB/USE_BZLIB #define.
44 diff -Nrup a/libdwfl/fts.c b/libdwfl/fts.c
45 --- a/libdwfl/fts.c 1970-01-01 01:00:00.000000000 +0100
46 +++ b/libdwfl/fts.c 2015-01-06 11:42:13.481640322 +0000
49 + * Copyright (c) 1990, 1993, 1994
50 + * The Regents of the University of California. All rights reserved.
52 + * Redistribution and use in source and binary forms, with or without
53 + * modification, are permitted provided that the following conditions
55 + * 1. Redistributions of source code must retain the above copyright
56 + * notice, this list of conditions and the following disclaimer.
57 + * 2. Redistributions in binary form must reproduce the above copyright
58 + * notice, this list of conditions and the following disclaimer in the
59 + * documentation and/or other materials provided with the distribution.
60 + * 4. Neither the name of the University nor the names of its contributors
61 + * may be used to endorse or promote products derived from this software
62 + * without specific prior written permission.
64 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
77 +#include <sys/param.h>
78 +#include <sys/stat.h>
87 +/* Largest alignment size needed, minus one.
88 + Usually long double is the worst case. */
90 +#define ALIGNBYTES (__alignof__ (long double) - 1)
92 +/* Align P to that size. */
94 +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
98 +static FTSENT *fts_alloc (FTS *, const char *, size_t);
99 +static FTSENT *fts_build (FTS *, int);
100 +static void fts_lfree (FTSENT *);
101 +static void fts_load (FTS *, FTSENT *);
102 +static size_t fts_maxarglen (char * const *);
103 +static void fts_padjust (FTS *, FTSENT *);
104 +static int fts_palloc (FTS *, size_t);
105 +static FTSENT *fts_sort (FTS *, FTSENT *, int);
106 +static u_short fts_stat (FTS *, FTSENT *, int);
107 +static int fts_safe_changedir (FTS *, FTSENT *, int, const char *);
110 +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
111 + __typeof__ (b) _b = (b); \
112 + _a > _b ? _a : _b; })
115 +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
117 +#define CLR(opt) (sp->fts_options &= ~(opt))
118 +#define ISSET(opt) (sp->fts_options & (opt))
119 +#define SET(opt) (sp->fts_options |= (opt))
121 +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
123 +/* fts_build flags */
124 +#define BCHILD 1 /* fts_children */
125 +#define BNAMES 2 /* fts_children, names only */
126 +#define BREAD 3 /* fts_read */
129 +fts_open( char * const *argv, register int options,
130 + int (*compar) (const FTSENT **, const FTSENT **))
133 + register FTSENT *p, *root;
134 + register int nitems;
135 + FTSENT *parent = NULL;
136 + FTSENT *tmp = NULL;
138 + /* Options check. */
139 + if (options & ~FTS_OPTIONMASK) {
144 + /* Allocate/initialize the stream */
145 + if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
147 + memset(sp, 0, sizeof(FTS));
148 + sp->fts_compar = (int (*) (const void *, const void *)) compar;
149 + sp->fts_options = options;
151 + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
152 + if (ISSET(FTS_LOGICAL))
156 + * Start out with 1K of path space, and enough, in any case,
157 + * to hold the user's paths.
160 +#define MAXPATHLEN 1024
162 + size_t maxarglen = fts_maxarglen(argv);
163 + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
166 + /* Allocate/initialize root's parent. */
167 + if (*argv != NULL) {
168 + if ((parent = fts_alloc(sp, "", 0)) == NULL)
170 + parent->fts_level = FTS_ROOTPARENTLEVEL;
173 + /* Allocate/initialize root(s). */
174 + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
175 + /* Don't allow zero-length paths. */
176 + size_t len = strlen(*argv);
182 + p = fts_alloc(sp, *argv, len);
183 + p->fts_level = FTS_ROOTLEVEL;
184 + p->fts_parent = parent;
185 + p->fts_accpath = p->fts_name;
186 + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
188 + /* Command-line "." and ".." are real directories. */
189 + if (p->fts_info == FTS_DOT)
190 + p->fts_info = FTS_D;
193 + * If comparison routine supplied, traverse in sorted
194 + * order; otherwise traverse in the order specified.
197 + p->fts_link = root;
200 + p->fts_link = NULL;
209 + if (compar && nitems > 1)
210 + root = fts_sort(sp, root, nitems);
213 + * Allocate a dummy pointer and make fts_read think that we've just
214 + * finished the node before the root(s); set p->fts_info to FTS_INIT
215 + * so that everything about the "current" node is ignored.
217 + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
219 + sp->fts_cur->fts_link = root;
220 + sp->fts_cur->fts_info = FTS_INIT;
223 + * If using chdir(2), grab a file descriptor pointing to dot to ensure
224 + * that we can get back here; this could be avoided for some paths,
225 + * but almost certainly not worth the effort. Slashes, symbolic links,
226 + * and ".." are all fairly nasty problems. Note, if we can't get the
227 + * descriptor we run anyway, just more slowly.
229 + if (!ISSET(FTS_NOCHDIR)
230 + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
235 +mem3: fts_lfree(root);
237 +mem2: free(sp->fts_path);
243 +fts_load(FTS *sp, register FTSENT *p)
249 + * Load the stream structure for the next traversal. Since we don't
250 + * actually enter the directory until after the preorder visit, set
251 + * the fts_accpath field specially so the chdir gets done to the right
252 + * place and the user can access the first node. From fts_open it's
253 + * known that the path will fit.
255 + len = p->fts_pathlen = p->fts_namelen;
256 + memmove(sp->fts_path, p->fts_name, len + 1);
257 + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
258 + len = strlen(++cp);
259 + memmove(p->fts_name, cp, len + 1);
260 + p->fts_namelen = len;
262 + p->fts_accpath = p->fts_path = sp->fts_path;
263 + sp->fts_dev = p->fts_dev;
269 + register FTSENT *freep, *p;
273 + * This still works if we haven't read anything -- the dummy structure
274 + * points to the root list, so we step through to the end of the root
275 + * list which has a valid parent pointer.
278 + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
280 + p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
286 + /* Free up child linked list, sort array, path buffer. */
288 + fts_lfree(sp->fts_child);
289 + free(sp->fts_array);
290 + free(sp->fts_path);
292 + /* Return to original directory, save errno if necessary. */
293 + if (!ISSET(FTS_NOCHDIR)) {
294 + saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
295 + (void)close(sp->fts_rfd);
297 + /* Set errno and return. */
298 + if (saved_errno != 0) {
299 + /* Free up the stream pointer. */
301 + errno = saved_errno;
306 + /* Free up the stream pointer. */
312 + * Special case of "/" at the end of the path so that slashes aren't
313 + * appended which would cause paths to be written as "....//foo".
315 +#define NAPPEND(p) \
316 + (p->fts_path[p->fts_pathlen - 1] == '/' \
317 + ? p->fts_pathlen - 1 : p->fts_pathlen)
320 +fts_read(register FTS *sp)
322 + register FTSENT *p, *tmp;
323 + register int instr;
327 + /* If finished or unrecoverable error, return NULL. */
328 + if (sp->fts_cur == NULL || ISSET(FTS_STOP))
331 + /* Set current node pointer. */
334 + /* Save and zero out user instructions. */
335 + instr = p->fts_instr;
336 + p->fts_instr = FTS_NOINSTR;
338 + /* Any type of file may be re-visited; re-stat and re-turn. */
339 + if (instr == FTS_AGAIN) {
340 + p->fts_info = fts_stat(sp, p, 0);
345 + * Following a symlink -- SLNONE test allows application to see
346 + * SLNONE and recover. If indirecting through a symlink, have
347 + * keep a pointer to current location. If unable to get that
348 + * pointer, follow fails.
350 + if (instr == FTS_FOLLOW &&
351 + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
352 + p->fts_info = fts_stat(sp, p, 1);
353 + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
354 + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
355 + p->fts_errno = errno;
356 + p->fts_info = FTS_ERR;
358 + p->fts_flags |= FTS_SYMFOLLOW;
363 + /* Directory in pre-order. */
364 + if (p->fts_info == FTS_D) {
365 + /* If skipped or crossed mount point, do post-order visit. */
366 + if (instr == FTS_SKIP ||
367 + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
368 + if (p->fts_flags & FTS_SYMFOLLOW)
369 + (void)close(p->fts_symfd);
370 + if (sp->fts_child) {
371 + fts_lfree(sp->fts_child);
372 + sp->fts_child = NULL;
374 + p->fts_info = FTS_DP;
378 + /* Rebuild if only read the names and now traversing. */
379 + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
381 + fts_lfree(sp->fts_child);
382 + sp->fts_child = NULL;
386 + * Cd to the subdirectory.
388 + * If have already read and now fail to chdir, whack the list
389 + * to make the names come out right, and set the parent errno
390 + * so the application will eventually get an error condition.
391 + * Set the FTS_DONTCHDIR flag so that when we logically change
392 + * directories back to the parent we don't do a chdir.
394 + * If haven't read do so. If the read fails, fts_build sets
395 + * FTS_STOP or the fts_info field of the node.
397 + if (sp->fts_child != NULL) {
398 + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
399 + p->fts_errno = errno;
400 + p->fts_flags |= FTS_DONTCHDIR;
401 + for (p = sp->fts_child; p != NULL;
404 + p->fts_parent->fts_accpath;
406 + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
407 + if (ISSET(FTS_STOP))
412 + sp->fts_child = NULL;
417 + /* Move to the next node on this level. */
419 + if ((p = p->fts_link) != NULL) {
424 + * If reached the top, return to the original directory (or
425 + * the root of the tree), and load the paths for the next root.
427 + if (p->fts_level == FTS_ROOTLEVEL) {
428 + if (FCHDIR(sp, sp->fts_rfd)) {
437 + * User may have called fts_set on the node. If skipped,
438 + * ignore. If followed, get a file descriptor so we can
439 + * get back if necessary.
441 + if (p->fts_instr == FTS_SKIP)
443 + if (p->fts_instr == FTS_FOLLOW) {
444 + p->fts_info = fts_stat(sp, p, 1);
445 + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
446 + if ((p->fts_symfd =
447 + open(".", O_RDONLY, 0)) < 0) {
448 + p->fts_errno = errno;
449 + p->fts_info = FTS_ERR;
451 + p->fts_flags |= FTS_SYMFOLLOW;
453 + p->fts_instr = FTS_NOINSTR;
456 +name: t = sp->fts_path + NAPPEND(p->fts_parent);
458 + memmove(t, p->fts_name, p->fts_namelen + 1);
462 + /* Move up to the parent node. */
463 + p = tmp->fts_parent;
467 + if (p->fts_level == FTS_ROOTPARENTLEVEL) {
469 + * Done; free everything up and set errno to 0 so the user
470 + * can distinguish between error and EOF.
474 + return (sp->fts_cur = NULL);
477 + /* NUL terminate the pathname. */
478 + sp->fts_path[p->fts_pathlen] = '\0';
481 + * Return to the parent directory. If at a root node or came through
482 + * a symlink, go back through the file descriptor. Otherwise, cd up
485 + if (p->fts_level == FTS_ROOTLEVEL) {
486 + if (FCHDIR(sp, sp->fts_rfd)) {
490 + } else if (p->fts_flags & FTS_SYMFOLLOW) {
491 + if (FCHDIR(sp, p->fts_symfd)) {
492 + saved_errno = errno;
493 + (void)close(p->fts_symfd);
494 + errno = saved_errno;
498 + (void)close(p->fts_symfd);
499 + } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
500 + fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
504 + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
509 + * Fts_set takes the stream as an argument although it's not used in this
510 + * implementation; it would be necessary if anyone wanted to add global
511 + * semantics to fts using fts_set. An error return is allowed for similar
516 +fts_set(FTS *sp, FTSENT *p, int instr)
518 + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
519 + instr != FTS_NOINSTR && instr != FTS_SKIP) {
523 + p->fts_instr = instr;
528 +fts_children(register FTS *sp, int instr)
530 + register FTSENT *p;
533 + if (instr != 0 && instr != FTS_NAMEONLY) {
538 + /* Set current node pointer. */
542 + * Errno set to 0 so user can distinguish empty directory from
547 + /* Fatal errors stop here. */
548 + if (ISSET(FTS_STOP))
551 + /* Return logical hierarchy of user's arguments. */
552 + if (p->fts_info == FTS_INIT)
553 + return (p->fts_link);
556 + * If not a directory being visited in pre-order, stop here. Could
557 + * allow FTS_DNR, assuming the user has fixed the problem, but the
558 + * same effect is available with FTS_AGAIN.
560 + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
563 + /* Free up any previous child list. */
564 + if (sp->fts_child != NULL)
565 + fts_lfree(sp->fts_child);
567 + if (instr == FTS_NAMEONLY) {
574 + * If using chdir on a relative path and called BEFORE fts_read does
575 + * its chdir to the root of a traversal, we can lose -- we need to
576 + * chdir into the subdirectory, and we don't know where the current
577 + * directory is, so we can't get back so that the upcoming chdir by
578 + * fts_read will work.
580 + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
581 + ISSET(FTS_NOCHDIR))
582 + return (sp->fts_child = fts_build(sp, instr));
584 + if ((fd = open(".", O_RDONLY, 0)) < 0)
586 + sp->fts_child = fts_build(sp, instr);
590 + return (sp->fts_child);
594 + * This is the tricky part -- do not casually change *anything* in here. The
595 + * idea is to build the linked list of entries that are used by fts_children
596 + * and fts_read. There are lots of special cases.
598 + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
599 + * set and it's a physical walk (so that symbolic links can't be directories),
600 + * we can do things quickly. First, if it's a 4.4BSD file system, the type
601 + * of the file is in the directory entry. Otherwise, we assume that the number
602 + * of subdirectories in a node is equal to the number of links to the parent.
603 + * The former skips all stat calls. The latter skips stat calls in any leaf
604 + * directories and for any files after the subdirectories in the directory have
605 + * been found, cutting the stat calls by about 2/3.
608 +fts_build(register FTS *sp, int type)
610 + register struct dirent *dp;
611 + register FTSENT *p, *head;
612 + register int nitems;
613 + FTSENT *cur, *tail;
616 + int cderrno, descend, len, level, nlinks, saved_errno,
621 + /* Set current node pointer. */
625 + * Open the directory for reading. If this fails, we're done.
626 + * If being called from fts_read, set the fts_info field.
628 +#if defined FTS_WHITEOUT && 0
629 + if (ISSET(FTS_WHITEOUT))
630 + oflag = DTF_NODUP|DTF_REWIND;
632 + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
634 +# define opendir2(path, flag) opendir(path)
636 + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
637 + if (type == BREAD) {
638 + cur->fts_info = FTS_DNR;
639 + cur->fts_errno = errno;
645 + * Nlinks is the number of possible entries of type directory in the
646 + * directory if we're cheating on stat calls, 0 if we're not doing
647 + * any stat calls at all, -1 if we're doing stats on everything.
649 + if (type == BNAMES) {
651 + /* Be quiet about nostat, GCC. */
653 + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
654 + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
662 + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
663 + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
664 + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
667 + * If we're going to need to stat anything or we want to descend
668 + * and stay in the directory, chdir. If this fails we keep going,
669 + * but set a flag so we don't chdir after the post-order visit.
670 + * We won't be able to stat anything, but we can still return the
671 + * names themselves. Note, that since fts_read won't be able to
672 + * chdir into the directory, it will have to return different path
673 + * names than before, i.e. "a/b" instead of "b". Since the node
674 + * has already been visited in pre-order, have to wait until the
675 + * post-order visit to return the error. There is a special case
676 + * here, if there was nothing to stat then it's not an error to
677 + * not be able to stat. This is all fairly nasty. If a program
678 + * needed sorted entries or stat information, they had better be
679 + * checking FTS_NS on the returned nodes.
682 + if (nlinks || type == BREAD) {
683 + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
684 + if (nlinks && type == BREAD)
685 + cur->fts_errno = errno;
686 + cur->fts_flags |= FTS_DONTCHDIR;
689 + (void)closedir(dirp);
697 + * Figure out the max file name length that can be stored in the
698 + * current path -- the inner loop allocates more path as necessary.
699 + * We really wouldn't have to do the maxlen calculations here, we
700 + * could do them in fts_read before returning the path, but it's a
701 + * lot easier here since the length is part of the dirent structure.
703 + * If not changing directories set a pointer so that can just append
704 + * each new name into the path.
706 + len = NAPPEND(cur);
707 + if (ISSET(FTS_NOCHDIR)) {
708 + cp = sp->fts_path + len;
711 + /* GCC, you're too verbose. */
715 + maxlen = sp->fts_pathlen - len;
717 + level = cur->fts_level + 1;
719 + /* Read the directory, attaching each entry to the `link' pointer. */
721 + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
722 + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
725 + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
727 + if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
728 + oldaddr = sp->fts_path;
729 + if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
731 + * No more memory for path or structures. Save
732 + * errno, free up the current structure and the
733 + * structures already allocated.
735 +mem1: saved_errno = errno;
738 + (void)closedir(dirp);
739 + cur->fts_info = FTS_ERR;
741 + errno = saved_errno;
744 + /* Did realloc() change the pointer? */
745 + if (oldaddr != sp->fts_path) {
747 + if (ISSET(FTS_NOCHDIR))
748 + cp = sp->fts_path + len;
750 + maxlen = sp->fts_pathlen - len;
753 + if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
755 + * In an FTSENT, fts_pathlen is a u_short so it is
756 + * possible to wraparound here. If we do, free up
757 + * the current structure and the structures already
758 + * allocated, then error out with ENAMETOOLONG.
762 + (void)closedir(dirp);
763 + cur->fts_info = FTS_ERR;
765 + errno = ENAMETOOLONG;
768 + p->fts_level = level;
769 + p->fts_parent = sp->fts_cur;
770 + p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
772 +#if defined FTS_WHITEOUT && 0
773 + if (dp->d_type == DT_WHT)
774 + p->fts_flags |= FTS_ISW;
778 + /* Unreachable code. cderrno is only ever set to a nonnull
779 + value if dirp is closed at the same time. But then we
780 + cannot enter this loop. */
783 + p->fts_info = FTS_NS;
784 + p->fts_errno = cderrno;
786 + p->fts_info = FTS_NSOK;
787 + p->fts_accpath = cur->fts_accpath;
791 +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
793 + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
797 + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
798 + p->fts_info = FTS_NSOK;
800 + /* Build a file name for fts_stat to stat. */
801 + if (ISSET(FTS_NOCHDIR)) {
802 + p->fts_accpath = p->fts_path;
803 + memmove(cp, p->fts_name, p->fts_namelen + 1);
805 + p->fts_accpath = p->fts_name;
807 + p->fts_info = fts_stat(sp, p, 0);
809 + /* Decrement link count if applicable. */
810 + if (nlinks > 0 && (p->fts_info == FTS_D ||
811 + p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
815 + /* We walk in directory order so "ls -f" doesn't get upset. */
816 + p->fts_link = NULL;
820 + tail->fts_link = p;
826 + (void)closedir(dirp);
829 + * If realloc() changed the address of the path, adjust the
830 + * addresses for the rest of the tree and the dir list.
833 + fts_padjust(sp, head);
836 + * If not changing directories, reset the path back to original
839 + if (ISSET(FTS_NOCHDIR)) {
840 + if (len == sp->fts_pathlen || nitems == 0)
846 + * If descended after called from fts_children or after called from
847 + * fts_read and nothing found, get back. At the root level we use
848 + * the saved fd; if one of fts_open()'s arguments is a relative path
849 + * to an empty directory, we wind up here with no other way back. If
850 + * can't get back, we're done.
852 + if (descend && (type == BCHILD || !nitems) &&
853 + (cur->fts_level == FTS_ROOTLEVEL ?
854 + FCHDIR(sp, sp->fts_rfd) :
855 + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
856 + cur->fts_info = FTS_ERR;
862 + /* If didn't find anything, return NULL. */
865 + cur->fts_info = FTS_DP;
870 + /* Sort the entries. */
871 + if (sp->fts_compar && nitems > 1)
872 + head = fts_sort(sp, head, nitems);
877 +fts_stat(FTS *sp, register FTSENT *p, int follow)
879 + register FTSENT *t;
880 + register dev_t dev;
881 + register ino_t ino;
882 + struct stat *sbp, sb;
885 + /* If user needs stat info, stat buffer already allocated. */
886 + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
888 +#if defined FTS_WHITEOUT && 0
889 + /* check for whiteout */
890 + if (p->fts_flags & FTS_ISW) {
892 + memset(sbp, '\0', sizeof (*sbp));
893 + sbp->st_mode = S_IFWHT;
900 + * If doing a logical walk, or application requested FTS_FOLLOW, do
901 + * a stat(2). If that fails, check for a non-existent symlink. If
902 + * fail, set the errno from the stat call.
904 + if (ISSET(FTS_LOGICAL) || follow) {
905 + if (stat(p->fts_accpath, sbp)) {
906 + saved_errno = errno;
907 + if (!lstat(p->fts_accpath, sbp)) {
909 + return (FTS_SLNONE);
911 + p->fts_errno = saved_errno;
914 + } else if (lstat(p->fts_accpath, sbp)) {
915 + p->fts_errno = errno;
916 +err: memset(sbp, 0, sizeof(struct stat));
920 + if (S_ISDIR(sbp->st_mode)) {
922 + * Set the device/inode. Used to find cycles and check for
923 + * crossing mount points. Also remember the link count, used
924 + * in fts_build to limit the number of stat calls. It is
925 + * understood that these fields are only referenced if fts_info
928 + dev = p->fts_dev = sbp->st_dev;
929 + ino = p->fts_ino = sbp->st_ino;
930 + p->fts_nlink = sbp->st_nlink;
932 + if (ISDOT(p->fts_name))
936 + * Cycle detection is done by brute force when the directory
937 + * is first encountered. If the tree gets deep enough or the
938 + * number of symbolic links to directories is high enough,
939 + * something faster might be worthwhile.
941 + for (t = p->fts_parent;
942 + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
943 + if (ino == t->fts_ino && dev == t->fts_dev) {
949 + if (S_ISLNK(sbp->st_mode))
951 + if (S_ISREG(sbp->st_mode))
953 + return (FTS_DEFAULT);
957 +fts_sort(FTS *sp, FTSENT *head, register int nitems)
959 + register FTSENT **ap, *p;
962 + * Construct an array of pointers to the structures and call qsort(3).
963 + * Reassemble the array in the order returned by qsort. If unable to
964 + * sort for memory reasons, return the directory entries in their
965 + * current order. Allocate enough space for the current needs plus
966 + * 40 so don't realloc one entry at a time.
968 + if (nitems > sp->fts_nitems) {
969 + struct _ftsent **a;
971 + sp->fts_nitems = nitems + 40;
972 + if ((a = realloc(sp->fts_array,
973 + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
974 + free(sp->fts_array);
975 + sp->fts_array = NULL;
976 + sp->fts_nitems = 0;
981 + for (ap = sp->fts_array, p = head; p; p = p->fts_link)
983 + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
984 + for (head = *(ap = sp->fts_array); --nitems; ++ap)
985 + ap[0]->fts_link = ap[1];
986 + ap[0]->fts_link = NULL;
991 +fts_alloc(FTS *sp, const char *name, size_t namelen)
993 + register FTSENT *p;
997 + * The file name is a variable length array and no stat structure is
998 + * necessary if the user has set the nostat bit. Allocate the FTSENT
999 + * structure, the file name and the stat structure in one chunk, but
1000 + * be careful that the stat structure is reasonably aligned. Since the
1001 + * fts_name field is declared to be of size 1, the fts_name pointer is
1002 + * namelen + 2 before the first possible address of the stat structure.
1004 + len = sizeof(FTSENT) + namelen;
1005 + if (!ISSET(FTS_NOSTAT))
1006 + len += sizeof(struct stat) + ALIGNBYTES;
1007 + if ((p = malloc(len)) == NULL)
1010 + /* Copy the name and guarantee NUL termination. */
1011 + memmove(p->fts_name, name, namelen);
1012 + p->fts_name[namelen] = '\0';
1014 + if (!ISSET(FTS_NOSTAT))
1015 + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
1016 + p->fts_namelen = namelen;
1017 + p->fts_path = sp->fts_path;
1020 + p->fts_instr = FTS_NOINSTR;
1021 + p->fts_number = 0;
1022 + p->fts_pointer = NULL;
1027 +fts_lfree(register FTSENT *head)
1029 + register FTSENT *p;
1031 + /* Free a linked list of structures. */
1032 + while ((p = head)) {
1033 + head = head->fts_link;
1039 + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
1040 + * Most systems will allow creation of paths much longer than MAXPATHLEN, even
1041 + * though the kernel won't resolve them. Add the size (not just what's needed)
1042 + * plus 256 bytes so don't realloc the path 2 bytes at a time.
1045 +fts_palloc(FTS *sp, size_t more)
1049 + sp->fts_pathlen += more + 256;
1051 + * Check for possible wraparound. In an FTS, fts_pathlen is
1052 + * a signed int but in an FTSENT it is an unsigned short.
1053 + * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
1055 + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
1056 + free(sp->fts_path);
1057 + sp->fts_path = NULL;
1058 + errno = ENAMETOOLONG;
1061 + p = realloc(sp->fts_path, sp->fts_pathlen);
1063 + free(sp->fts_path);
1064 + sp->fts_path = NULL;
1072 + * When the path is realloc'd, have to fix all of the pointers in structures
1073 + * already returned.
1076 +fts_padjust(FTS *sp, FTSENT *head)
1079 + char *addr = sp->fts_path;
1081 +#define ADJUST(p) do { \
1082 + if ((p)->fts_accpath != (p)->fts_name) { \
1083 + (p)->fts_accpath = \
1084 + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
1086 + (p)->fts_path = addr; \
1088 + /* Adjust the current set of children. */
1089 + for (p = sp->fts_child; p; p = p->fts_link)
1092 + /* Adjust the rest of the tree, including the current level. */
1093 + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1095 + p = p->fts_link ? p->fts_link : p->fts_parent;
1100 +fts_maxarglen(char * const *argv)
1104 + for (max = 0; *argv; ++argv)
1105 + if ((len = strlen(*argv)) > max)
1111 + * Change to dir specified by fd or p->fts_accpath without getting
1112 + * tricked by someone changing the world out from underneath us.
1113 + * Assumes p->fts_dev and p->fts_ino are filled in.
1116 +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
1118 + int ret, oerrno, newfd;
1122 + if (ISSET(FTS_NOCHDIR))
1124 + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
1126 + if (fstat64(newfd, &sb)) {
1130 + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
1131 + errno = ENOENT; /* disinformation */
1135 + ret = fchdir(newfd);
1139 + (void)close(newfd);
1143 diff -Nrup a/libdwfl/fts_.h b/libdwfl/fts_.h
1144 --- a/libdwfl/fts_.h 1970-01-01 01:00:00.000000000 +0100
1145 +++ b/libdwfl/fts_.h 2015-01-06 11:42:13.481640322 +0000
1148 + * Copyright (c) 1989, 1993
1149 + * The Regents of the University of California. All rights reserved.
1151 + * Redistribution and use in source and binary forms, with or without
1152 + * modification, are permitted provided that the following conditions
1154 + * 1. Redistributions of source code must retain the above copyright
1155 + * notice, this list of conditions and the following disclaimer.
1156 + * 2. Redistributions in binary form must reproduce the above copyright
1157 + * notice, this list of conditions and the following disclaimer in the
1158 + * documentation and/or other materials provided with the distribution.
1159 + * 4. Neither the name of the University nor the names of its contributors
1160 + * may be used to endorse or promote products derived from this software
1161 + * without specific prior written permission.
1163 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1164 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1165 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1166 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1167 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1168 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1169 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1170 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1171 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1172 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1175 + * @(#)fts.h 8.3 (Berkeley) 8/14/94
1181 +#include <features.h>
1182 +#include <sys/types.h>
1184 +/* The fts interface is incompatible with the LFS interface which
1185 + transparently uses the 64-bit file access functions. */
1186 +#ifdef __USE_FILE_OFFSET64
1187 +# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
1192 + struct _ftsent *fts_cur; /* current node */
1193 + struct _ftsent *fts_child; /* linked list of children */
1194 + struct _ftsent **fts_array; /* sort array */
1195 + dev_t fts_dev; /* starting device # */
1196 + char *fts_path; /* path for this descent */
1197 + int fts_rfd; /* fd for root */
1198 + int fts_pathlen; /* sizeof(path) */
1199 + int fts_nitems; /* elements in the sort array */
1200 + int (*fts_compar) (const void *, const void *); /* compare fn */
1202 +#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
1203 +#define FTS_LOGICAL 0x0002 /* logical walk */
1204 +#define FTS_NOCHDIR 0x0004 /* don't change directories */
1205 +#define FTS_NOSTAT 0x0008 /* don't get stat info */
1206 +#define FTS_PHYSICAL 0x0010 /* physical walk */
1207 +#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
1208 +#define FTS_XDEV 0x0040 /* don't cross devices */
1209 +#define FTS_WHITEOUT 0x0080 /* return whiteout information */
1210 +#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
1212 +#define FTS_NAMEONLY 0x0100 /* (private) child names only */
1213 +#define FTS_STOP 0x0200 /* (private) unrecoverable error */
1214 + int fts_options; /* fts_open options, global flags */
1217 +typedef struct _ftsent {
1218 + struct _ftsent *fts_cycle; /* cycle node */
1219 + struct _ftsent *fts_parent; /* parent directory */
1220 + struct _ftsent *fts_link; /* next file in directory */
1221 + long fts_number; /* local numeric value */
1222 + void *fts_pointer; /* local address value */
1223 + char *fts_accpath; /* access path */
1224 + char *fts_path; /* root path */
1225 + int fts_errno; /* errno for this node */
1226 + int fts_symfd; /* fd for symlink */
1227 + u_short fts_pathlen; /* strlen(fts_path) */
1228 + u_short fts_namelen; /* strlen(fts_name) */
1230 + ino_t fts_ino; /* inode */
1231 + dev_t fts_dev; /* device */
1232 + nlink_t fts_nlink; /* link count */
1234 +#define FTS_ROOTPARENTLEVEL -1
1235 +#define FTS_ROOTLEVEL 0
1236 + short fts_level; /* depth (-1 to N) */
1238 +#define FTS_D 1 /* preorder directory */
1239 +#define FTS_DC 2 /* directory that causes cycles */
1240 +#define FTS_DEFAULT 3 /* none of the above */
1241 +#define FTS_DNR 4 /* unreadable directory */
1242 +#define FTS_DOT 5 /* dot or dot-dot */
1243 +#define FTS_DP 6 /* postorder directory */
1244 +#define FTS_ERR 7 /* error; errno is set */
1245 +#define FTS_F 8 /* regular file */
1246 +#define FTS_INIT 9 /* initialized only */
1247 +#define FTS_NS 10 /* stat(2) failed */
1248 +#define FTS_NSOK 11 /* no stat(2) requested */
1249 +#define FTS_SL 12 /* symbolic link */
1250 +#define FTS_SLNONE 13 /* symbolic link without target */
1251 +#define FTS_W 14 /* whiteout object */
1252 + u_short fts_info; /* user flags for FTSENT structure */
1254 +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
1255 +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
1256 + u_short fts_flags; /* private flags for FTSENT structure */
1258 +#define FTS_AGAIN 1 /* read node again */
1259 +#define FTS_FOLLOW 2 /* follow symbolic link */
1260 +#define FTS_NOINSTR 3 /* no instructions */
1261 +#define FTS_SKIP 4 /* discard node */
1262 + u_short fts_instr; /* fts_set() instructions */
1264 + struct stat *fts_statp; /* stat(2) information */
1265 + char fts_name[1]; /* file name */
1269 +FTSENT *fts_children (FTS *, int);
1270 +int fts_close (FTS *);
1271 +FTS *fts_open (char * const *, int,
1272 + int (*)(const FTSENT **, const FTSENT **));
1273 +FTSENT *fts_read (FTS *);
1274 +int fts_set (FTS *, FTSENT *, int) __THROW;
1278 diff -Nrup a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
1279 --- a/libdwfl/linux-kernel-modules.c 2014-11-22 22:43:52.000000000 +0000
1280 +++ b/libdwfl/linux-kernel-modules.c 2015-01-06 11:44:25.610924805 +0000
1282 /* We include this before config.h because it can't handle _FILE_OFFSET_BITS.
1283 Everything we need here is fine if its declarations just come first. */
1293 diff -Nrup a/libdwfl/Makefile.am b/libdwfl/Makefile.am
1294 --- a/libdwfl/Makefile.am 2014-06-17 19:51:09.000000000 +0100
1295 +++ b/libdwfl/Makefile.am 2015-01-06 11:45:25.442959369 +0000
1296 @@ -79,6 +79,9 @@ endif
1298 libdwfl_a_SOURCES += lzma.c
1301 +libdwfl_a_SOURCES += fts.c
1305 libdw = ../libdw/libdw.so