janus-gateway: make echo test plugin optional
[buildroot-gz.git] / package / elfutils / 0003-fts.patch
blob0131b750f8f3c0526e774e71087e8c0fd6bc6283
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
6 some work.
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],
36 enable_progs=yes)
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.
44 save_LIBS="$LIBS"
45 LIBS=
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
49 @@ -0,0 +1,1095 @@
50 +/*-
51 + * Copyright (c) 1990, 1993, 1994
52 + * The Regents of the University of California. All rights reserved.
53 + *
54 + * Redistribution and use in source and binary forms, with or without
55 + * modification, are permitted provided that the following conditions
56 + * are met:
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.
65 + *
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
76 + * SUCH DAMAGE.
77 + */
79 +#include <sys/param.h>
80 +#include <sys/stat.h>
81 +#include <fcntl.h>
82 +#include <dirent.h>
83 +#include <errno.h>
84 +#include "fts_.h"
85 +#include <stdlib.h>
86 +#include <string.h>
87 +#include <unistd.h>
89 +/* Largest alignment size needed, minus one.
90 + Usually long double is the worst case. */
91 +#ifndef ALIGNBYTES
92 +#define ALIGNBYTES (__alignof__ (long double) - 1)
93 +#endif
94 +/* Align P to that size. */
95 +#ifndef ALIGN
96 +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
97 +#endif
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 *);
111 +#ifndef MAX
112 +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
113 + __typeof__ (b) _b = (b); \
114 + _a > _b ? _a : _b; })
115 +#endif
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 */
130 +FTS *
131 +fts_open( char * const *argv, register int options,
132 + int (*compar) (const FTSENT **, const FTSENT **))
134 + register FTS *sp;
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) {
142 + errno = EINVAL;
143 + return (NULL);
146 + /* Allocate/initialize the stream */
147 + if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
148 + return (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))
155 + SET(FTS_NOCHDIR);
157 + /*
158 + * Start out with 1K of path space, and enough, in any case,
159 + * to hold the user's paths.
160 + */
161 +#ifndef MAXPATHLEN
162 +#define MAXPATHLEN 1024
163 +#endif
164 + size_t maxarglen = fts_maxarglen(argv);
165 + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
166 + goto mem1;
168 + /* Allocate/initialize root's parent. */
169 + if (*argv != NULL) {
170 + if ((parent = fts_alloc(sp, "", 0)) == NULL)
171 + goto mem2;
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);
179 + if (len == 0) {
180 + errno = ENOENT;
181 + goto mem3;
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;
194 + /*
195 + * If comparison routine supplied, traverse in sorted
196 + * order; otherwise traverse in the order specified.
197 + */
198 + if (compar) {
199 + p->fts_link = root;
200 + root = p;
201 + } else {
202 + p->fts_link = NULL;
203 + if (root == NULL)
204 + tmp = root = p;
205 + else {
206 + tmp->fts_link = p;
207 + tmp = p;
211 + if (compar && nitems > 1)
212 + root = fts_sort(sp, root, nitems);
214 + /*
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.
218 + */
219 + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
220 + goto mem3;
221 + sp->fts_cur->fts_link = root;
222 + sp->fts_cur->fts_info = FTS_INIT;
224 + /*
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.
230 + */
231 + if (!ISSET(FTS_NOCHDIR)
232 + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
233 + SET(FTS_NOCHDIR);
235 + return (sp);
237 +mem3: fts_lfree(root);
238 + free(parent);
239 +mem2: free(sp->fts_path);
240 +mem1: free(sp);
241 + return (NULL);
244 +static void
245 +fts_load(FTS *sp, register FTSENT *p)
247 + register int len;
248 + register char *cp;
250 + /*
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.
256 + */
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;
268 +int
269 +fts_close(FTS *sp)
271 + register FTSENT *freep, *p;
272 + int saved_errno;
274 + /*
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.
278 + */
279 + if (sp->fts_cur) {
280 + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
281 + freep = p;
282 + p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
283 + free(freep);
285 + free(p);
288 + /* Free up child linked list, sort array, path buffer. */
289 + if (sp->fts_child)
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. */
302 + free(sp);
303 + errno = saved_errno;
304 + return (-1);
308 + /* Free up the stream pointer. */
309 + free(sp);
310 + return (0);
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".
316 + */
317 +#define NAPPEND(p) \
318 + (p->fts_path[p->fts_pathlen - 1] == '/' \
319 + ? p->fts_pathlen - 1 : p->fts_pathlen)
321 +FTSENT *
322 +fts_read(register FTS *sp)
324 + register FTSENT *p, *tmp;
325 + register int instr;
326 + register char *t;
327 + int saved_errno;
329 + /* If finished or unrecoverable error, return NULL. */
330 + if (sp->fts_cur == NULL || ISSET(FTS_STOP))
331 + return (NULL);
333 + /* Set current node pointer. */
334 + p = sp->fts_cur;
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);
343 + return (p);
346 + /*
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.
351 + */
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;
359 + } else
360 + p->fts_flags |= FTS_SYMFOLLOW;
362 + return (p);
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;
377 + return (p);
380 + /* Rebuild if only read the names and now traversing. */
381 + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
382 + CLR(FTS_NAMEONLY);
383 + fts_lfree(sp->fts_child);
384 + sp->fts_child = NULL;
387 + /*
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.
398 + */
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;
404 + p = p->fts_link)
405 + p->fts_accpath =
406 + p->fts_parent->fts_accpath;
408 + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
409 + if (ISSET(FTS_STOP))
410 + return (NULL);
411 + return (p);
413 + p = sp->fts_child;
414 + sp->fts_child = NULL;
415 + sp->fts_cur = p;
416 + goto name;
419 + /* Move to the next node on this level. */
420 +next: tmp = p;
421 + if ((p = p->fts_link) != NULL) {
422 + sp->fts_cur = p;
423 + free(tmp);
425 + /*
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.
428 + */
429 + if (p->fts_level == FTS_ROOTLEVEL) {
430 + if (FCHDIR(sp, sp->fts_rfd)) {
431 + SET(FTS_STOP);
432 + return (NULL);
434 + fts_load(sp, p);
435 + return p;
438 + /*
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.
442 + */
443 + if (p->fts_instr == FTS_SKIP)
444 + goto next;
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;
452 + } else
453 + p->fts_flags |= FTS_SYMFOLLOW;
455 + p->fts_instr = FTS_NOINSTR;
458 +name: t = sp->fts_path + NAPPEND(p->fts_parent);
459 + *t++ = '/';
460 + memmove(t, p->fts_name, p->fts_namelen + 1);
461 + return p;
464 + /* Move up to the parent node. */
465 + p = tmp->fts_parent;
466 + sp->fts_cur = p;
467 + free(tmp);
469 + if (p->fts_level == FTS_ROOTPARENTLEVEL) {
470 + /*
471 + * Done; free everything up and set errno to 0 so the user
472 + * can distinguish between error and EOF.
473 + */
474 + free(p);
475 + errno = 0;
476 + return (sp->fts_cur = NULL);
479 + /* NUL terminate the pathname. */
480 + sp->fts_path[p->fts_pathlen] = '\0';
482 + /*
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
485 + * one directory.
486 + */
487 + if (p->fts_level == FTS_ROOTLEVEL) {
488 + if (FCHDIR(sp, sp->fts_rfd)) {
489 + SET(FTS_STOP);
490 + return (NULL);
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;
497 + SET(FTS_STOP);
498 + return (NULL);
500 + (void)close(p->fts_symfd);
501 + } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
502 + fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
503 + SET(FTS_STOP);
504 + return (NULL);
506 + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
507 + return p;
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
514 + * reasons.
515 + */
516 +/* ARGSUSED */
517 +int
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) {
522 + errno = EINVAL;
523 + return (1);
525 + p->fts_instr = instr;
526 + return (0);
529 +FTSENT *
530 +fts_children(register FTS *sp, int instr)
532 + register FTSENT *p;
533 + int fd;
535 + if (instr != 0 && instr != FTS_NAMEONLY) {
536 + errno = EINVAL;
537 + return (NULL);
540 + /* Set current node pointer. */
541 + p = sp->fts_cur;
543 + /*
544 + * Errno set to 0 so user can distinguish empty directory from
545 + * an error.
546 + */
547 + errno = 0;
549 + /* Fatal errors stop here. */
550 + if (ISSET(FTS_STOP))
551 + return (NULL);
553 + /* Return logical hierarchy of user's arguments. */
554 + if (p->fts_info == FTS_INIT)
555 + return (p->fts_link);
557 + /*
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.
561 + */
562 + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
563 + return (NULL);
565 + /* Free up any previous child list. */
566 + if (sp->fts_child != NULL)
567 + fts_lfree(sp->fts_child);
569 + if (instr == FTS_NAMEONLY) {
570 + SET(FTS_NAMEONLY);
571 + instr = BNAMES;
572 + } else
573 + instr = BCHILD;
575 + /*
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.
581 + */
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)
587 + return (NULL);
588 + sp->fts_child = fts_build(sp, instr);
589 + if (fchdir(fd))
590 + return (NULL);
591 + (void)close(fd);
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.
608 + */
609 +static FTSENT *
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;
616 + DIR *dirp;
617 + void *oldaddr;
618 + int cderrno, descend, len, level, nlinks, saved_errno,
619 + nostat, doadjust;
620 + size_t maxlen;
621 + char *cp;
623 + /* Set current node pointer. */
624 + cur = sp->fts_cur;
626 + /*
627 + * Open the directory for reading. If this fails, we're done.
628 + * If being called from fts_read, set the fts_info field.
629 + */
630 +#if defined FTS_WHITEOUT && 0
631 + if (ISSET(FTS_WHITEOUT))
632 + oflag = DTF_NODUP|DTF_REWIND;
633 + else
634 + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
635 +#else
636 +# define opendir2(path, flag) opendir(path)
637 +#endif
638 + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
639 + if (type == BREAD) {
640 + cur->fts_info = FTS_DNR;
641 + cur->fts_errno = errno;
643 + return (NULL);
646 + /*
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.
650 + */
651 + if (type == BNAMES) {
652 + nlinks = 0;
653 + /* Be quiet about nostat, GCC. */
654 + nostat = 0;
655 + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
656 + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
657 + nostat = 1;
658 + } else {
659 + nlinks = -1;
660 + nostat = 0;
663 +#ifdef notdef
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));
667 +#endif
668 + /*
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.
682 + */
683 + cderrno = 0;
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;
689 + descend = 0;
690 + cderrno = errno;
691 + (void)closedir(dirp);
692 + dirp = NULL;
693 + } else
694 + descend = 1;
695 + } else
696 + descend = 0;
698 + /*
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.
707 + */
708 + len = NAPPEND(cur);
709 + if (ISSET(FTS_NOCHDIR)) {
710 + cp = sp->fts_path + len;
711 + *cp++ = '/';
712 + } else {
713 + /* GCC, you're too verbose. */
714 + cp = NULL;
716 + len++;
717 + maxlen = sp->fts_pathlen - len;
719 + level = cur->fts_level + 1;
721 + /* Read the directory, attaching each entry to the `link' pointer. */
722 + doadjust = 0;
723 + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
724 + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
725 + continue;
727 + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
728 + goto mem1;
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)) {
732 + /*
733 + * No more memory for path or structures. Save
734 + * errno, free up the current structure and the
735 + * structures already allocated.
736 + */
737 +mem1: saved_errno = errno;
738 + free(p);
739 + fts_lfree(head);
740 + (void)closedir(dirp);
741 + cur->fts_info = FTS_ERR;
742 + SET(FTS_STOP);
743 + errno = saved_errno;
744 + return (NULL);
746 + /* Did realloc() change the pointer? */
747 + if (oldaddr != sp->fts_path) {
748 + doadjust = 1;
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) {
756 + /*
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.
761 + */
762 + free(p);
763 + fts_lfree(head);
764 + (void)closedir(dirp);
765 + cur->fts_info = FTS_ERR;
766 + SET(FTS_STOP);
767 + errno = ENAMETOOLONG;
768 + return (NULL);
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;
777 +#endif
779 +#if 0
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. */
783 + if (cderrno) {
784 + if (nlinks) {
785 + p->fts_info = FTS_NS;
786 + p->fts_errno = cderrno;
787 + } else
788 + p->fts_info = FTS_NSOK;
789 + p->fts_accpath = cur->fts_accpath;
790 + } else
791 +#endif
792 + if (nlinks == 0
793 +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
794 + || (nostat &&
795 + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
796 +#endif
797 + ) {
798 + p->fts_accpath =
799 + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
800 + p->fts_info = FTS_NSOK;
801 + } else {
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);
806 + } else
807 + p->fts_accpath = p->fts_name;
808 + /* Stat it. */
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))
814 + --nlinks;
817 + /* We walk in directory order so "ls -f" doesn't get upset. */
818 + p->fts_link = NULL;
819 + if (head == NULL)
820 + head = tail = p;
821 + else {
822 + tail->fts_link = p;
823 + tail = p;
825 + ++nitems;
827 + if (dirp)
828 + (void)closedir(dirp);
830 + /*
831 + * If realloc() changed the address of the path, adjust the
832 + * addresses for the rest of the tree and the dir list.
833 + */
834 + if (doadjust)
835 + fts_padjust(sp, head);
837 + /*
838 + * If not changing directories, reset the path back to original
839 + * state.
840 + */
841 + if (ISSET(FTS_NOCHDIR)) {
842 + if (len == sp->fts_pathlen || nitems == 0)
843 + --cp;
844 + *cp = '\0';
847 + /*
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.
853 + */
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;
859 + SET(FTS_STOP);
860 + fts_lfree(head);
861 + return (NULL);
864 + /* If didn't find anything, return NULL. */
865 + if (!nitems) {
866 + if (type == BREAD)
867 + cur->fts_info = FTS_DP;
868 + fts_lfree(head);
869 + return (NULL);
872 + /* Sort the entries. */
873 + if (sp->fts_compar && nitems > 1)
874 + head = fts_sort(sp, head, nitems);
875 + return (head);
878 +static u_short
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;
885 + int saved_errno;
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) {
893 + if (sbp != &sb) {
894 + memset(sbp, '\0', sizeof (*sbp));
895 + sbp->st_mode = S_IFWHT;
897 + return (FTS_W);
899 +#endif
901 + /*
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.
905 + */
906 + if (ISSET(FTS_LOGICAL) || follow) {
907 + if (stat(p->fts_accpath, sbp)) {
908 + saved_errno = errno;
909 + if (!lstat(p->fts_accpath, sbp)) {
910 + errno = 0;
911 + return (FTS_SLNONE);
913 + p->fts_errno = saved_errno;
914 + goto err;
916 + } else if (lstat(p->fts_accpath, sbp)) {
917 + p->fts_errno = errno;
918 +err: memset(sbp, 0, sizeof(struct stat));
919 + return (FTS_NS);
922 + if (S_ISDIR(sbp->st_mode)) {
923 + /*
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
928 + * is set to FTS_D.
929 + */
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))
935 + return (FTS_DOT);
937 + /*
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.
942 + */
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) {
946 + p->fts_cycle = t;
947 + return (FTS_DC);
949 + return (FTS_D);
951 + if (S_ISLNK(sbp->st_mode))
952 + return (FTS_SL);
953 + if (S_ISREG(sbp->st_mode))
954 + return (FTS_F);
955 + return (FTS_DEFAULT);
958 +static FTSENT *
959 +fts_sort(FTS *sp, FTSENT *head, register int nitems)
961 + register FTSENT **ap, *p;
963 + /*
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.
969 + */
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;
979 + return (head);
981 + sp->fts_array = a;
983 + for (ap = sp->fts_array, p = head; p; p = p->fts_link)
984 + *ap++ = p;
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;
989 + return (head);
992 +static FTSENT *
993 +fts_alloc(FTS *sp, const char *name, size_t namelen)
995 + register FTSENT *p;
996 + size_t len;
998 + /*
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.
1005 + */
1006 + len = sizeof(FTSENT) + namelen;
1007 + if (!ISSET(FTS_NOSTAT))
1008 + len += sizeof(struct stat) + ALIGNBYTES;
1009 + if ((p = malloc(len)) == NULL)
1010 + return (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;
1020 + p->fts_errno = 0;
1021 + p->fts_flags = 0;
1022 + p->fts_instr = FTS_NOINSTR;
1023 + p->fts_number = 0;
1024 + p->fts_pointer = NULL;
1025 + return (p);
1028 +static void
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;
1036 + free(p);
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.
1045 + */
1046 +static int
1047 +fts_palloc(FTS *sp, size_t more)
1049 + char *p;
1051 + sp->fts_pathlen += more + 256;
1052 + /*
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.
1056 + */
1057 + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
1058 + free(sp->fts_path);
1059 + sp->fts_path = NULL;
1060 + errno = ENAMETOOLONG;
1061 + return (1);
1063 + p = realloc(sp->fts_path, sp->fts_pathlen);
1064 + if (p == NULL) {
1065 + free(sp->fts_path);
1066 + sp->fts_path = NULL;
1067 + return 1;
1069 + sp->fts_path = p;
1070 + return 0;
1074 + * When the path is realloc'd, have to fix all of the pointers in structures
1075 + * already returned.
1076 + */
1077 +static void
1078 +fts_padjust(FTS *sp, FTSENT *head)
1080 + FTSENT *p;
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); \
1087 + } \
1088 + (p)->fts_path = addr; \
1089 +} while (0)
1090 + /* Adjust the current set of children. */
1091 + for (p = sp->fts_child; p; p = p->fts_link)
1092 + ADJUST(p);
1094 + /* Adjust the rest of the tree, including the current level. */
1095 + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1096 + ADJUST(p);
1097 + p = p->fts_link ? p->fts_link : p->fts_parent;
1101 +static size_t
1102 +fts_maxarglen(char * const *argv)
1104 + size_t len, max;
1106 + for (max = 0; *argv; ++argv)
1107 + if ((len = strlen(*argv)) > max)
1108 + max = len;
1109 + return (max + 1);
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.
1116 + */
1117 +static int
1118 +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
1120 + int ret, oerrno, newfd;
1121 + struct stat64 sb;
1123 + newfd = fd;
1124 + if (ISSET(FTS_NOCHDIR))
1125 + return (0);
1126 + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
1127 + return (-1);
1128 + if (fstat64(newfd, &sb)) {
1129 + ret = -1;
1130 + goto bail;
1132 + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
1133 + errno = ENOENT; /* disinformation */
1134 + ret = -1;
1135 + goto bail;
1137 + ret = fchdir(newfd);
1138 +bail:
1139 + oerrno = errno;
1140 + if (fd < 0)
1141 + (void)close(newfd);
1142 + errno = oerrno;
1143 + return (ret);
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
1148 @@ -0,0 +1,131 @@
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
1155 + * are met:
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
1175 + * SUCH DAMAGE.
1177 + * @(#)fts.h 8.3 (Berkeley) 8/14/94
1178 + */
1180 +#ifndef _FTS_H
1181 +#define _FTS_H 1
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"
1190 +#endif
1193 +typedef struct {
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 */
1217 +} FTS;
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 */
1268 +} FTSENT;
1270 +__BEGIN_DECLS
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;
1277 +__END_DECLS
1279 +#endif /* fts.h */
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
1283 @@ -29,7 +29,11 @@
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. */
1287 +#ifdef HAVE_FTS_H
1288 #include <fts.h>
1289 +#else
1290 +#include <fts_.h>
1291 +#endif
1293 #include <config.h>
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
1299 if LZMA
1300 libdwfl_a_SOURCES += lzma.c
1301 endif
1302 +if !HAVE_FTS
1303 +libdwfl_a_SOURCES += fts.c
1304 +endif
1306 libdwfl = $(libdw)
1307 libdw = ../libdw/libdw.so