123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332 |
- From 098760f7eac1fb86b3f6871d5bb10f9f44468f2d Mon Sep 17 00:00:00 2001
- From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
- Date: Mon, 29 May 2017 23:08:05 +0300
- Subject: [PATCH] Add an implementation of the fts_*() functions
- The fts_*() functions are optional in uClibc, and not compiled in our
- default configuration. The best option would be to migrate this
- elfutils code to the nftw family of functions, but it requires quite
- some work.
- So we have several options here:
- *) Enable fts_*() functions in our default uClibc configuration. Not
- nice since only one package needs them (the help text of uClibc
- for fts_*() functions explicitly mention that they have been added
- to be able to build elfutils).
- *) Use gnulib, but it is quite heavy to setup, requires modifications
- to configure.ac, and other things.
- *) Copy the fts function from uClibc into elfutils source code. This
- is the solution used below. uClibc is LGPL, and elfutils is
- LGPL/GPL, so there should not be any licensing issue.
- Of course, the fts_*() functions are only built if they are not
- already provided by the C library.
- Based on the former patch by Thomas Petazzoni.
- [Vincent: tweak patch for 0.166]
- Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
- Signed-off-by: Vicente Olivert Riera <Vincent.Riera@imgtec.com>
- ---
- configure.ac | 4 +
- libdwfl/Makefile.am | 3 +
- libdwfl/fts.c | 1095 ++++++++++++++++++++++++++++++++++++++++
- libdwfl/fts_.h | 131 +++++
- libdwfl/linux-kernel-modules.c | 4 +
- 5 files changed, 1237 insertions(+)
- create mode 100644 libdwfl/fts.c
- create mode 100644 libdwfl/fts_.h
- diff --git a/configure.ac b/configure.ac
- index 7b4c38381cca..bcebb05fa532 100644
- --- a/configure.ac
- +++ b/configure.ac
- @@ -265,6 +265,10 @@ AC_ARG_ENABLE([progs],
- enable_progs=yes)
- AM_CONDITIONAL(ENABLE_PROGS, test "$enable_progs" = yes)
-
- +AC_CHECK_HEADER([fts.h],
- + AC_DEFINE([HAVE_FTS_H], [], [Define if <fts.h> is available in C library]))
- +AM_CONDITIONAL(HAVE_FTS, test "$ac_cv_header_fts_h" = yes)
- +
- dnl zlib is mandatory.
- save_LIBS="$LIBS"
- LIBS=
- diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
- index 89ca92ed8110..a5a5615c5f94 100644
- --- a/libdwfl/Makefile.am
- +++ b/libdwfl/Makefile.am
- @@ -77,6 +77,9 @@ endif
- if LZMA
- libdwfl_a_SOURCES += lzma.c
- endif
- +if !HAVE_FTS
- +libdwfl_a_SOURCES += fts.c
- +endif
-
- libdwfl = $(libdw)
- libdw = ../libdw/libdw.so
- diff --git a/libdwfl/fts.c b/libdwfl/fts.c
- new file mode 100644
- index 000000000000..f34cc03bd963
- --- /dev/null
- +++ b/libdwfl/fts.c
- @@ -0,0 +1,1095 @@
- +/*-
- + * Copyright (c) 1990, 1993, 1994
- + * The Regents of the University of California. All rights reserved.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions
- + * are met:
- + * 1. Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * 2. Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * 4. Neither the name of the University nor the names of its contributors
- + * may be used to endorse or promote products derived from this software
- + * without specific prior written permission.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- + * SUCH DAMAGE.
- + */
- +
- +#include <sys/param.h>
- +#include <sys/stat.h>
- +#include <fcntl.h>
- +#include <dirent.h>
- +#include <errno.h>
- +#include "fts_.h"
- +#include <stdlib.h>
- +#include <string.h>
- +#include <unistd.h>
- +
- +/* Largest alignment size needed, minus one.
- + Usually long double is the worst case. */
- +#ifndef ALIGNBYTES
- +#define ALIGNBYTES (__alignof__ (long double) - 1)
- +#endif
- +/* Align P to that size. */
- +#ifndef ALIGN
- +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
- +#endif
- +
- +
- +static FTSENT *fts_alloc (FTS *, const char *, size_t);
- +static FTSENT *fts_build (FTS *, int);
- +static void fts_lfree (FTSENT *);
- +static void fts_load (FTS *, FTSENT *);
- +static size_t fts_maxarglen (char * const *);
- +static void fts_padjust (FTS *, FTSENT *);
- +static int fts_palloc (FTS *, size_t);
- +static FTSENT *fts_sort (FTS *, FTSENT *, int);
- +static u_short fts_stat (FTS *, FTSENT *, int);
- +static int fts_safe_changedir (FTS *, FTSENT *, int, const char *);
- +
- +#ifndef MAX
- +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
- + __typeof__ (b) _b = (b); \
- + _a > _b ? _a : _b; })
- +#endif
- +
- +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
- +
- +#define CLR(opt) (sp->fts_options &= ~(opt))
- +#define ISSET(opt) (sp->fts_options & (opt))
- +#define SET(opt) (sp->fts_options |= (opt))
- +
- +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
- +
- +/* fts_build flags */
- +#define BCHILD 1 /* fts_children */
- +#define BNAMES 2 /* fts_children, names only */
- +#define BREAD 3 /* fts_read */
- +
- +FTS *
- +fts_open( char * const *argv, register int options,
- + int (*compar) (const FTSENT **, const FTSENT **))
- +{
- + register FTS *sp;
- + register FTSENT *p, *root;
- + register int nitems;
- + FTSENT *parent = NULL;
- + FTSENT *tmp = NULL;
- +
- + /* Options check. */
- + if (options & ~FTS_OPTIONMASK) {
- + errno = EINVAL;
- + return (NULL);
- + }
- +
- + /* Allocate/initialize the stream */
- + if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
- + return (NULL);
- + memset(sp, 0, sizeof(FTS));
- + sp->fts_compar = (int (*) (const void *, const void *)) compar;
- + sp->fts_options = options;
- +
- + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
- + if (ISSET(FTS_LOGICAL))
- + SET(FTS_NOCHDIR);
- +
- + /*
- + * Start out with 1K of path space, and enough, in any case,
- + * to hold the user's paths.
- + */
- +#ifndef MAXPATHLEN
- +#define MAXPATHLEN 1024
- +#endif
- + size_t maxarglen = fts_maxarglen(argv);
- + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
- + goto mem1;
- +
- + /* Allocate/initialize root's parent. */
- + if (*argv != NULL) {
- + if ((parent = fts_alloc(sp, "", 0)) == NULL)
- + goto mem2;
- + parent->fts_level = FTS_ROOTPARENTLEVEL;
- + }
- +
- + /* Allocate/initialize root(s). */
- + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
- + /* Don't allow zero-length paths. */
- + size_t len = strlen(*argv);
- + if (len == 0) {
- + errno = ENOENT;
- + goto mem3;
- + }
- +
- + p = fts_alloc(sp, *argv, len);
- + p->fts_level = FTS_ROOTLEVEL;
- + p->fts_parent = parent;
- + p->fts_accpath = p->fts_name;
- + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
- +
- + /* Command-line "." and ".." are real directories. */
- + if (p->fts_info == FTS_DOT)
- + p->fts_info = FTS_D;
- +
- + /*
- + * If comparison routine supplied, traverse in sorted
- + * order; otherwise traverse in the order specified.
- + */
- + if (compar) {
- + p->fts_link = root;
- + root = p;
- + } else {
- + p->fts_link = NULL;
- + if (root == NULL)
- + tmp = root = p;
- + else {
- + tmp->fts_link = p;
- + tmp = p;
- + }
- + }
- + }
- + if (compar && nitems > 1)
- + root = fts_sort(sp, root, nitems);
- +
- + /*
- + * Allocate a dummy pointer and make fts_read think that we've just
- + * finished the node before the root(s); set p->fts_info to FTS_INIT
- + * so that everything about the "current" node is ignored.
- + */
- + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
- + goto mem3;
- + sp->fts_cur->fts_link = root;
- + sp->fts_cur->fts_info = FTS_INIT;
- +
- + /*
- + * If using chdir(2), grab a file descriptor pointing to dot to ensure
- + * that we can get back here; this could be avoided for some paths,
- + * but almost certainly not worth the effort. Slashes, symbolic links,
- + * and ".." are all fairly nasty problems. Note, if we can't get the
- + * descriptor we run anyway, just more slowly.
- + */
- + if (!ISSET(FTS_NOCHDIR)
- + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
- + SET(FTS_NOCHDIR);
- +
- + return (sp);
- +
- +mem3: fts_lfree(root);
- + free(parent);
- +mem2: free(sp->fts_path);
- +mem1: free(sp);
- + return (NULL);
- +}
- +
- +static void
- +fts_load(FTS *sp, register FTSENT *p)
- +{
- + register int len;
- + register char *cp;
- +
- + /*
- + * Load the stream structure for the next traversal. Since we don't
- + * actually enter the directory until after the preorder visit, set
- + * the fts_accpath field specially so the chdir gets done to the right
- + * place and the user can access the first node. From fts_open it's
- + * known that the path will fit.
- + */
- + len = p->fts_pathlen = p->fts_namelen;
- + memmove(sp->fts_path, p->fts_name, len + 1);
- + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
- + len = strlen(++cp);
- + memmove(p->fts_name, cp, len + 1);
- + p->fts_namelen = len;
- + }
- + p->fts_accpath = p->fts_path = sp->fts_path;
- + sp->fts_dev = p->fts_dev;
- +}
- +
- +int
- +fts_close(FTS *sp)
- +{
- + register FTSENT *freep, *p;
- + int saved_errno;
- +
- + /*
- + * This still works if we haven't read anything -- the dummy structure
- + * points to the root list, so we step through to the end of the root
- + * list which has a valid parent pointer.
- + */
- + if (sp->fts_cur) {
- + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
- + freep = p;
- + p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
- + free(freep);
- + }
- + free(p);
- + }
- +
- + /* Free up child linked list, sort array, path buffer. */
- + if (sp->fts_child)
- + fts_lfree(sp->fts_child);
- + free(sp->fts_array);
- + free(sp->fts_path);
- +
- + /* Return to original directory, save errno if necessary. */
- + if (!ISSET(FTS_NOCHDIR)) {
- + saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
- + (void)close(sp->fts_rfd);
- +
- + /* Set errno and return. */
- + if (saved_errno != 0) {
- + /* Free up the stream pointer. */
- + free(sp);
- + errno = saved_errno;
- + return (-1);
- + }
- + }
- +
- + /* Free up the stream pointer. */
- + free(sp);
- + return (0);
- +}
- +
- +/*
- + * Special case of "/" at the end of the path so that slashes aren't
- + * appended which would cause paths to be written as "....//foo".
- + */
- +#define NAPPEND(p) \
- + (p->fts_path[p->fts_pathlen - 1] == '/' \
- + ? p->fts_pathlen - 1 : p->fts_pathlen)
- +
- +FTSENT *
- +fts_read(register FTS *sp)
- +{
- + register FTSENT *p, *tmp;
- + register int instr;
- + register char *t;
- + int saved_errno;
- +
- + /* If finished or unrecoverable error, return NULL. */
- + if (sp->fts_cur == NULL || ISSET(FTS_STOP))
- + return (NULL);
- +
- + /* Set current node pointer. */
- + p = sp->fts_cur;
- +
- + /* Save and zero out user instructions. */
- + instr = p->fts_instr;
- + p->fts_instr = FTS_NOINSTR;
- +
- + /* Any type of file may be re-visited; re-stat and re-turn. */
- + if (instr == FTS_AGAIN) {
- + p->fts_info = fts_stat(sp, p, 0);
- + return (p);
- + }
- +
- + /*
- + * Following a symlink -- SLNONE test allows application to see
- + * SLNONE and recover. If indirecting through a symlink, have
- + * keep a pointer to current location. If unable to get that
- + * pointer, follow fails.
- + */
- + if (instr == FTS_FOLLOW &&
- + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
- + p->fts_info = fts_stat(sp, p, 1);
- + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
- + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
- + p->fts_errno = errno;
- + p->fts_info = FTS_ERR;
- + } else
- + p->fts_flags |= FTS_SYMFOLLOW;
- + }
- + return (p);
- + }
- +
- + /* Directory in pre-order. */
- + if (p->fts_info == FTS_D) {
- + /* If skipped or crossed mount point, do post-order visit. */
- + if (instr == FTS_SKIP ||
- + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
- + if (p->fts_flags & FTS_SYMFOLLOW)
- + (void)close(p->fts_symfd);
- + if (sp->fts_child) {
- + fts_lfree(sp->fts_child);
- + sp->fts_child = NULL;
- + }
- + p->fts_info = FTS_DP;
- + return (p);
- + }
- +
- + /* Rebuild if only read the names and now traversing. */
- + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
- + CLR(FTS_NAMEONLY);
- + fts_lfree(sp->fts_child);
- + sp->fts_child = NULL;
- + }
- +
- + /*
- + * Cd to the subdirectory.
- + *
- + * If have already read and now fail to chdir, whack the list
- + * to make the names come out right, and set the parent errno
- + * so the application will eventually get an error condition.
- + * Set the FTS_DONTCHDIR flag so that when we logically change
- + * directories back to the parent we don't do a chdir.
- + *
- + * If haven't read do so. If the read fails, fts_build sets
- + * FTS_STOP or the fts_info field of the node.
- + */
- + if (sp->fts_child != NULL) {
- + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
- + p->fts_errno = errno;
- + p->fts_flags |= FTS_DONTCHDIR;
- + for (p = sp->fts_child; p != NULL;
- + p = p->fts_link)
- + p->fts_accpath =
- + p->fts_parent->fts_accpath;
- + }
- + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
- + if (ISSET(FTS_STOP))
- + return (NULL);
- + return (p);
- + }
- + p = sp->fts_child;
- + sp->fts_child = NULL;
- + sp->fts_cur = p;
- + goto name;
- + }
- +
- + /* Move to the next node on this level. */
- +next: tmp = p;
- + if ((p = p->fts_link) != NULL) {
- + sp->fts_cur = p;
- + free(tmp);
- +
- + /*
- + * If reached the top, return to the original directory (or
- + * the root of the tree), and load the paths for the next root.
- + */
- + if (p->fts_level == FTS_ROOTLEVEL) {
- + if (FCHDIR(sp, sp->fts_rfd)) {
- + SET(FTS_STOP);
- + return (NULL);
- + }
- + fts_load(sp, p);
- + return p;
- + }
- +
- + /*
- + * User may have called fts_set on the node. If skipped,
- + * ignore. If followed, get a file descriptor so we can
- + * get back if necessary.
- + */
- + if (p->fts_instr == FTS_SKIP)
- + goto next;
- + if (p->fts_instr == FTS_FOLLOW) {
- + p->fts_info = fts_stat(sp, p, 1);
- + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
- + if ((p->fts_symfd =
- + open(".", O_RDONLY, 0)) < 0) {
- + p->fts_errno = errno;
- + p->fts_info = FTS_ERR;
- + } else
- + p->fts_flags |= FTS_SYMFOLLOW;
- + }
- + p->fts_instr = FTS_NOINSTR;
- + }
- +
- +name: t = sp->fts_path + NAPPEND(p->fts_parent);
- + *t++ = '/';
- + memmove(t, p->fts_name, p->fts_namelen + 1);
- + return p;
- + }
- +
- + /* Move up to the parent node. */
- + p = tmp->fts_parent;
- + sp->fts_cur = p;
- + free(tmp);
- +
- + if (p->fts_level == FTS_ROOTPARENTLEVEL) {
- + /*
- + * Done; free everything up and set errno to 0 so the user
- + * can distinguish between error and EOF.
- + */
- + free(p);
- + errno = 0;
- + return (sp->fts_cur = NULL);
- + }
- +
- + /* NUL terminate the pathname. */
- + sp->fts_path[p->fts_pathlen] = '\0';
- +
- + /*
- + * Return to the parent directory. If at a root node or came through
- + * a symlink, go back through the file descriptor. Otherwise, cd up
- + * one directory.
- + */
- + if (p->fts_level == FTS_ROOTLEVEL) {
- + if (FCHDIR(sp, sp->fts_rfd)) {
- + SET(FTS_STOP);
- + return (NULL);
- + }
- + } else if (p->fts_flags & FTS_SYMFOLLOW) {
- + if (FCHDIR(sp, p->fts_symfd)) {
- + saved_errno = errno;
- + (void)close(p->fts_symfd);
- + errno = saved_errno;
- + SET(FTS_STOP);
- + return (NULL);
- + }
- + (void)close(p->fts_symfd);
- + } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
- + fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
- + SET(FTS_STOP);
- + return (NULL);
- + }
- + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
- + return p;
- +}
- +
- +/*
- + * Fts_set takes the stream as an argument although it's not used in this
- + * implementation; it would be necessary if anyone wanted to add global
- + * semantics to fts using fts_set. An error return is allowed for similar
- + * reasons.
- + */
- +/* ARGSUSED */
- +int
- +fts_set(FTS *sp, FTSENT *p, int instr)
- +{
- + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
- + instr != FTS_NOINSTR && instr != FTS_SKIP) {
- + errno = EINVAL;
- + return (1);
- + }
- + p->fts_instr = instr;
- + return (0);
- +}
- +
- +FTSENT *
- +fts_children(register FTS *sp, int instr)
- +{
- + register FTSENT *p;
- + int fd;
- +
- + if (instr != 0 && instr != FTS_NAMEONLY) {
- + errno = EINVAL;
- + return (NULL);
- + }
- +
- + /* Set current node pointer. */
- + p = sp->fts_cur;
- +
- + /*
- + * Errno set to 0 so user can distinguish empty directory from
- + * an error.
- + */
- + errno = 0;
- +
- + /* Fatal errors stop here. */
- + if (ISSET(FTS_STOP))
- + return (NULL);
- +
- + /* Return logical hierarchy of user's arguments. */
- + if (p->fts_info == FTS_INIT)
- + return (p->fts_link);
- +
- + /*
- + * If not a directory being visited in pre-order, stop here. Could
- + * allow FTS_DNR, assuming the user has fixed the problem, but the
- + * same effect is available with FTS_AGAIN.
- + */
- + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
- + return (NULL);
- +
- + /* Free up any previous child list. */
- + if (sp->fts_child != NULL)
- + fts_lfree(sp->fts_child);
- +
- + if (instr == FTS_NAMEONLY) {
- + SET(FTS_NAMEONLY);
- + instr = BNAMES;
- + } else
- + instr = BCHILD;
- +
- + /*
- + * If using chdir on a relative path and called BEFORE fts_read does
- + * its chdir to the root of a traversal, we can lose -- we need to
- + * chdir into the subdirectory, and we don't know where the current
- + * directory is, so we can't get back so that the upcoming chdir by
- + * fts_read will work.
- + */
- + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
- + ISSET(FTS_NOCHDIR))
- + return (sp->fts_child = fts_build(sp, instr));
- +
- + if ((fd = open(".", O_RDONLY, 0)) < 0)
- + return (NULL);
- + sp->fts_child = fts_build(sp, instr);
- + if (fchdir(fd))
- + return (NULL);
- + (void)close(fd);
- + return (sp->fts_child);
- +}
- +
- +/*
- + * This is the tricky part -- do not casually change *anything* in here. The
- + * idea is to build the linked list of entries that are used by fts_children
- + * and fts_read. There are lots of special cases.
- + *
- + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
- + * set and it's a physical walk (so that symbolic links can't be directories),
- + * we can do things quickly. First, if it's a 4.4BSD file system, the type
- + * of the file is in the directory entry. Otherwise, we assume that the number
- + * of subdirectories in a node is equal to the number of links to the parent.
- + * The former skips all stat calls. The latter skips stat calls in any leaf
- + * directories and for any files after the subdirectories in the directory have
- + * been found, cutting the stat calls by about 2/3.
- + */
- +static FTSENT *
- +fts_build(register FTS *sp, int type)
- +{
- + register struct dirent *dp;
- + register FTSENT *p, *head;
- + register int nitems;
- + FTSENT *cur, *tail;
- + DIR *dirp;
- + void *oldaddr;
- + int cderrno, descend, len, level, nlinks, saved_errno,
- + nostat, doadjust;
- + size_t maxlen;
- + char *cp;
- +
- + /* Set current node pointer. */
- + cur = sp->fts_cur;
- +
- + /*
- + * Open the directory for reading. If this fails, we're done.
- + * If being called from fts_read, set the fts_info field.
- + */
- +#if defined FTS_WHITEOUT && 0
- + if (ISSET(FTS_WHITEOUT))
- + oflag = DTF_NODUP|DTF_REWIND;
- + else
- + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
- +#else
- +# define opendir2(path, flag) opendir(path)
- +#endif
- + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
- + if (type == BREAD) {
- + cur->fts_info = FTS_DNR;
- + cur->fts_errno = errno;
- + }
- + return (NULL);
- + }
- +
- + /*
- + * Nlinks is the number of possible entries of type directory in the
- + * directory if we're cheating on stat calls, 0 if we're not doing
- + * any stat calls at all, -1 if we're doing stats on everything.
- + */
- + if (type == BNAMES) {
- + nlinks = 0;
- + /* Be quiet about nostat, GCC. */
- + nostat = 0;
- + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
- + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
- + nostat = 1;
- + } else {
- + nlinks = -1;
- + nostat = 0;
- + }
- +
- +#ifdef notdef
- + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
- + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
- + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
- +#endif
- + /*
- + * If we're going to need to stat anything or we want to descend
- + * and stay in the directory, chdir. If this fails we keep going,
- + * but set a flag so we don't chdir after the post-order visit.
- + * We won't be able to stat anything, but we can still return the
- + * names themselves. Note, that since fts_read won't be able to
- + * chdir into the directory, it will have to return different path
- + * names than before, i.e. "a/b" instead of "b". Since the node
- + * has already been visited in pre-order, have to wait until the
- + * post-order visit to return the error. There is a special case
- + * here, if there was nothing to stat then it's not an error to
- + * not be able to stat. This is all fairly nasty. If a program
- + * needed sorted entries or stat information, they had better be
- + * checking FTS_NS on the returned nodes.
- + */
- + cderrno = 0;
- + if (nlinks || type == BREAD) {
- + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
- + if (nlinks && type == BREAD)
- + cur->fts_errno = errno;
- + cur->fts_flags |= FTS_DONTCHDIR;
- + descend = 0;
- + cderrno = errno;
- + (void)closedir(dirp);
- + dirp = NULL;
- + } else
- + descend = 1;
- + } else
- + descend = 0;
- +
- + /*
- + * Figure out the max file name length that can be stored in the
- + * current path -- the inner loop allocates more path as necessary.
- + * We really wouldn't have to do the maxlen calculations here, we
- + * could do them in fts_read before returning the path, but it's a
- + * lot easier here since the length is part of the dirent structure.
- + *
- + * If not changing directories set a pointer so that can just append
- + * each new name into the path.
- + */
- + len = NAPPEND(cur);
- + if (ISSET(FTS_NOCHDIR)) {
- + cp = sp->fts_path + len;
- + *cp++ = '/';
- + } else {
- + /* GCC, you're too verbose. */
- + cp = NULL;
- + }
- + len++;
- + maxlen = sp->fts_pathlen - len;
- +
- + level = cur->fts_level + 1;
- +
- + /* Read the directory, attaching each entry to the `link' pointer. */
- + doadjust = 0;
- + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
- + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
- + continue;
- +
- + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
- + goto mem1;
- + if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
- + oldaddr = sp->fts_path;
- + if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
- + /*
- + * No more memory for path or structures. Save
- + * errno, free up the current structure and the
- + * structures already allocated.
- + */
- +mem1: saved_errno = errno;
- + free(p);
- + fts_lfree(head);
- + (void)closedir(dirp);
- + cur->fts_info = FTS_ERR;
- + SET(FTS_STOP);
- + errno = saved_errno;
- + return (NULL);
- + }
- + /* Did realloc() change the pointer? */
- + if (oldaddr != sp->fts_path) {
- + doadjust = 1;
- + if (ISSET(FTS_NOCHDIR))
- + cp = sp->fts_path + len;
- + }
- + maxlen = sp->fts_pathlen - len;
- + }
- +
- + if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
- + /*
- + * In an FTSENT, fts_pathlen is a u_short so it is
- + * possible to wraparound here. If we do, free up
- + * the current structure and the structures already
- + * allocated, then error out with ENAMETOOLONG.
- + */
- + free(p);
- + fts_lfree(head);
- + (void)closedir(dirp);
- + cur->fts_info = FTS_ERR;
- + SET(FTS_STOP);
- + errno = ENAMETOOLONG;
- + return (NULL);
- + }
- + p->fts_level = level;
- + p->fts_parent = sp->fts_cur;
- + p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
- +
- +#if defined FTS_WHITEOUT && 0
- + if (dp->d_type == DT_WHT)
- + p->fts_flags |= FTS_ISW;
- +#endif
- +
- +#if 0
- + /* Unreachable code. cderrno is only ever set to a nonnull
- + value if dirp is closed at the same time. But then we
- + cannot enter this loop. */
- + if (cderrno) {
- + if (nlinks) {
- + p->fts_info = FTS_NS;
- + p->fts_errno = cderrno;
- + } else
- + p->fts_info = FTS_NSOK;
- + p->fts_accpath = cur->fts_accpath;
- + } else
- +#endif
- + if (nlinks == 0
- +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
- + || (nostat &&
- + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
- +#endif
- + ) {
- + p->fts_accpath =
- + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
- + p->fts_info = FTS_NSOK;
- + } else {
- + /* Build a file name for fts_stat to stat. */
- + if (ISSET(FTS_NOCHDIR)) {
- + p->fts_accpath = p->fts_path;
- + memmove(cp, p->fts_name, p->fts_namelen + 1);
- + } else
- + p->fts_accpath = p->fts_name;
- + /* Stat it. */
- + p->fts_info = fts_stat(sp, p, 0);
- +
- + /* Decrement link count if applicable. */
- + if (nlinks > 0 && (p->fts_info == FTS_D ||
- + p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
- + --nlinks;
- + }
- +
- + /* We walk in directory order so "ls -f" doesn't get upset. */
- + p->fts_link = NULL;
- + if (head == NULL)
- + head = tail = p;
- + else {
- + tail->fts_link = p;
- + tail = p;
- + }
- + ++nitems;
- + }
- + if (dirp)
- + (void)closedir(dirp);
- +
- + /*
- + * If realloc() changed the address of the path, adjust the
- + * addresses for the rest of the tree and the dir list.
- + */
- + if (doadjust)
- + fts_padjust(sp, head);
- +
- + /*
- + * If not changing directories, reset the path back to original
- + * state.
- + */
- + if (ISSET(FTS_NOCHDIR)) {
- + if (len == sp->fts_pathlen || nitems == 0)
- + --cp;
- + *cp = '\0';
- + }
- +
- + /*
- + * If descended after called from fts_children or after called from
- + * fts_read and nothing found, get back. At the root level we use
- + * the saved fd; if one of fts_open()'s arguments is a relative path
- + * to an empty directory, we wind up here with no other way back. If
- + * can't get back, we're done.
- + */
- + if (descend && (type == BCHILD || !nitems) &&
- + (cur->fts_level == FTS_ROOTLEVEL ?
- + FCHDIR(sp, sp->fts_rfd) :
- + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
- + cur->fts_info = FTS_ERR;
- + SET(FTS_STOP);
- + fts_lfree(head);
- + return (NULL);
- + }
- +
- + /* If didn't find anything, return NULL. */
- + if (!nitems) {
- + if (type == BREAD)
- + cur->fts_info = FTS_DP;
- + fts_lfree(head);
- + return (NULL);
- + }
- +
- + /* Sort the entries. */
- + if (sp->fts_compar && nitems > 1)
- + head = fts_sort(sp, head, nitems);
- + return (head);
- +}
- +
- +static u_short
- +fts_stat(FTS *sp, register FTSENT *p, int follow)
- +{
- + register FTSENT *t;
- + register dev_t dev;
- + register ino_t ino;
- + struct stat *sbp, sb;
- + int saved_errno;
- +
- + /* If user needs stat info, stat buffer already allocated. */
- + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
- +
- +#if defined FTS_WHITEOUT && 0
- + /* check for whiteout */
- + if (p->fts_flags & FTS_ISW) {
- + if (sbp != &sb) {
- + memset(sbp, '\0', sizeof (*sbp));
- + sbp->st_mode = S_IFWHT;
- + }
- + return (FTS_W);
- + }
- +#endif
- +
- + /*
- + * If doing a logical walk, or application requested FTS_FOLLOW, do
- + * a stat(2). If that fails, check for a non-existent symlink. If
- + * fail, set the errno from the stat call.
- + */
- + if (ISSET(FTS_LOGICAL) || follow) {
- + if (stat(p->fts_accpath, sbp)) {
- + saved_errno = errno;
- + if (!lstat(p->fts_accpath, sbp)) {
- + errno = 0;
- + return (FTS_SLNONE);
- + }
- + p->fts_errno = saved_errno;
- + goto err;
- + }
- + } else if (lstat(p->fts_accpath, sbp)) {
- + p->fts_errno = errno;
- +err: memset(sbp, 0, sizeof(struct stat));
- + return (FTS_NS);
- + }
- +
- + if (S_ISDIR(sbp->st_mode)) {
- + /*
- + * Set the device/inode. Used to find cycles and check for
- + * crossing mount points. Also remember the link count, used
- + * in fts_build to limit the number of stat calls. It is
- + * understood that these fields are only referenced if fts_info
- + * is set to FTS_D.
- + */
- + dev = p->fts_dev = sbp->st_dev;
- + ino = p->fts_ino = sbp->st_ino;
- + p->fts_nlink = sbp->st_nlink;
- +
- + if (ISDOT(p->fts_name))
- + return (FTS_DOT);
- +
- + /*
- + * Cycle detection is done by brute force when the directory
- + * is first encountered. If the tree gets deep enough or the
- + * number of symbolic links to directories is high enough,
- + * something faster might be worthwhile.
- + */
- + for (t = p->fts_parent;
- + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
- + if (ino == t->fts_ino && dev == t->fts_dev) {
- + p->fts_cycle = t;
- + return (FTS_DC);
- + }
- + return (FTS_D);
- + }
- + if (S_ISLNK(sbp->st_mode))
- + return (FTS_SL);
- + if (S_ISREG(sbp->st_mode))
- + return (FTS_F);
- + return (FTS_DEFAULT);
- +}
- +
- +static FTSENT *
- +fts_sort(FTS *sp, FTSENT *head, register int nitems)
- +{
- + register FTSENT **ap, *p;
- +
- + /*
- + * Construct an array of pointers to the structures and call qsort(3).
- + * Reassemble the array in the order returned by qsort. If unable to
- + * sort for memory reasons, return the directory entries in their
- + * current order. Allocate enough space for the current needs plus
- + * 40 so don't realloc one entry at a time.
- + */
- + if (nitems > sp->fts_nitems) {
- + struct _ftsent **a;
- +
- + sp->fts_nitems = nitems + 40;
- + if ((a = realloc(sp->fts_array,
- + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
- + free(sp->fts_array);
- + sp->fts_array = NULL;
- + sp->fts_nitems = 0;
- + return (head);
- + }
- + sp->fts_array = a;
- + }
- + for (ap = sp->fts_array, p = head; p; p = p->fts_link)
- + *ap++ = p;
- + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
- + for (head = *(ap = sp->fts_array); --nitems; ++ap)
- + ap[0]->fts_link = ap[1];
- + ap[0]->fts_link = NULL;
- + return (head);
- +}
- +
- +static FTSENT *
- +fts_alloc(FTS *sp, const char *name, size_t namelen)
- +{
- + register FTSENT *p;
- + size_t len;
- +
- + /*
- + * The file name is a variable length array and no stat structure is
- + * necessary if the user has set the nostat bit. Allocate the FTSENT
- + * structure, the file name and the stat structure in one chunk, but
- + * be careful that the stat structure is reasonably aligned. Since the
- + * fts_name field is declared to be of size 1, the fts_name pointer is
- + * namelen + 2 before the first possible address of the stat structure.
- + */
- + len = sizeof(FTSENT) + namelen;
- + if (!ISSET(FTS_NOSTAT))
- + len += sizeof(struct stat) + ALIGNBYTES;
- + if ((p = malloc(len)) == NULL)
- + return (NULL);
- +
- + /* Copy the name and guarantee NUL termination. */
- + memmove(p->fts_name, name, namelen);
- + p->fts_name[namelen] = '\0';
- +
- + if (!ISSET(FTS_NOSTAT))
- + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
- + p->fts_namelen = namelen;
- + p->fts_path = sp->fts_path;
- + p->fts_errno = 0;
- + p->fts_flags = 0;
- + p->fts_instr = FTS_NOINSTR;
- + p->fts_number = 0;
- + p->fts_pointer = NULL;
- + return (p);
- +}
- +
- +static void
- +fts_lfree(register FTSENT *head)
- +{
- + register FTSENT *p;
- +
- + /* Free a linked list of structures. */
- + while ((p = head)) {
- + head = head->fts_link;
- + free(p);
- + }
- +}
- +
- +/*
- + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
- + * Most systems will allow creation of paths much longer than MAXPATHLEN, even
- + * though the kernel won't resolve them. Add the size (not just what's needed)
- + * plus 256 bytes so don't realloc the path 2 bytes at a time.
- + */
- +static int
- +fts_palloc(FTS *sp, size_t more)
- +{
- + char *p;
- +
- + sp->fts_pathlen += more + 256;
- + /*
- + * Check for possible wraparound. In an FTS, fts_pathlen is
- + * a signed int but in an FTSENT it is an unsigned short.
- + * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
- + */
- + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
- + free(sp->fts_path);
- + sp->fts_path = NULL;
- + errno = ENAMETOOLONG;
- + return (1);
- + }
- + p = realloc(sp->fts_path, sp->fts_pathlen);
- + if (p == NULL) {
- + free(sp->fts_path);
- + sp->fts_path = NULL;
- + return 1;
- + }
- + sp->fts_path = p;
- + return 0;
- +}
- +
- +/*
- + * When the path is realloc'd, have to fix all of the pointers in structures
- + * already returned.
- + */
- +static void
- +fts_padjust(FTS *sp, FTSENT *head)
- +{
- + FTSENT *p;
- + char *addr = sp->fts_path;
- +
- +#define ADJUST(p) do { \
- + if ((p)->fts_accpath != (p)->fts_name) { \
- + (p)->fts_accpath = \
- + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
- + } \
- + (p)->fts_path = addr; \
- +} while (0)
- + /* Adjust the current set of children. */
- + for (p = sp->fts_child; p; p = p->fts_link)
- + ADJUST(p);
- +
- + /* Adjust the rest of the tree, including the current level. */
- + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
- + ADJUST(p);
- + p = p->fts_link ? p->fts_link : p->fts_parent;
- + }
- +}
- +
- +static size_t
- +fts_maxarglen(char * const *argv)
- +{
- + size_t len, max;
- +
- + for (max = 0; *argv; ++argv)
- + if ((len = strlen(*argv)) > max)
- + max = len;
- + return (max + 1);
- +}
- +
- +/*
- + * Change to dir specified by fd or p->fts_accpath without getting
- + * tricked by someone changing the world out from underneath us.
- + * Assumes p->fts_dev and p->fts_ino are filled in.
- + */
- +static int
- +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
- +{
- + int ret, oerrno, newfd;
- + struct stat64 sb;
- +
- + newfd = fd;
- + if (ISSET(FTS_NOCHDIR))
- + return (0);
- + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
- + return (-1);
- + if (fstat64(newfd, &sb)) {
- + ret = -1;
- + goto bail;
- + }
- + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
- + errno = ENOENT; /* disinformation */
- + ret = -1;
- + goto bail;
- + }
- + ret = fchdir(newfd);
- +bail:
- + oerrno = errno;
- + if (fd < 0)
- + (void)close(newfd);
- + errno = oerrno;
- + return (ret);
- +}
- diff --git a/libdwfl/fts_.h b/libdwfl/fts_.h
- new file mode 100644
- index 000000000000..0a070ba8dce5
- --- /dev/null
- +++ b/libdwfl/fts_.h
- @@ -0,0 +1,131 @@
- +/*
- + * Copyright (c) 1989, 1993
- + * The Regents of the University of California. All rights reserved.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions
- + * are met:
- + * 1. Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * 2. Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * 4. Neither the name of the University nor the names of its contributors
- + * may be used to endorse or promote products derived from this software
- + * without specific prior written permission.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- + * SUCH DAMAGE.
- + *
- + * @(#)fts.h 8.3 (Berkeley) 8/14/94
- + */
- +
- +#ifndef _FTS_H
- +#define _FTS_H 1
- +
- +#include <features.h>
- +#include <sys/types.h>
- +
- +/* The fts interface is incompatible with the LFS interface which
- + transparently uses the 64-bit file access functions. */
- +#ifdef __USE_FILE_OFFSET64
- +# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
- +#endif
- +
- +
- +typedef struct {
- + struct _ftsent *fts_cur; /* current node */
- + struct _ftsent *fts_child; /* linked list of children */
- + struct _ftsent **fts_array; /* sort array */
- + dev_t fts_dev; /* starting device # */
- + char *fts_path; /* path for this descent */
- + int fts_rfd; /* fd for root */
- + int fts_pathlen; /* sizeof(path) */
- + int fts_nitems; /* elements in the sort array */
- + int (*fts_compar) (const void *, const void *); /* compare fn */
- +
- +#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
- +#define FTS_LOGICAL 0x0002 /* logical walk */
- +#define FTS_NOCHDIR 0x0004 /* don't change directories */
- +#define FTS_NOSTAT 0x0008 /* don't get stat info */
- +#define FTS_PHYSICAL 0x0010 /* physical walk */
- +#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
- +#define FTS_XDEV 0x0040 /* don't cross devices */
- +#define FTS_WHITEOUT 0x0080 /* return whiteout information */
- +#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
- +
- +#define FTS_NAMEONLY 0x0100 /* (private) child names only */
- +#define FTS_STOP 0x0200 /* (private) unrecoverable error */
- + int fts_options; /* fts_open options, global flags */
- +} FTS;
- +
- +typedef struct _ftsent {
- + struct _ftsent *fts_cycle; /* cycle node */
- + struct _ftsent *fts_parent; /* parent directory */
- + struct _ftsent *fts_link; /* next file in directory */
- + long fts_number; /* local numeric value */
- + void *fts_pointer; /* local address value */
- + char *fts_accpath; /* access path */
- + char *fts_path; /* root path */
- + int fts_errno; /* errno for this node */
- + int fts_symfd; /* fd for symlink */
- + u_short fts_pathlen; /* strlen(fts_path) */
- + u_short fts_namelen; /* strlen(fts_name) */
- +
- + ino_t fts_ino; /* inode */
- + dev_t fts_dev; /* device */
- + nlink_t fts_nlink; /* link count */
- +
- +#define FTS_ROOTPARENTLEVEL -1
- +#define FTS_ROOTLEVEL 0
- + short fts_level; /* depth (-1 to N) */
- +
- +#define FTS_D 1 /* preorder directory */
- +#define FTS_DC 2 /* directory that causes cycles */
- +#define FTS_DEFAULT 3 /* none of the above */
- +#define FTS_DNR 4 /* unreadable directory */
- +#define FTS_DOT 5 /* dot or dot-dot */
- +#define FTS_DP 6 /* postorder directory */
- +#define FTS_ERR 7 /* error; errno is set */
- +#define FTS_F 8 /* regular file */
- +#define FTS_INIT 9 /* initialized only */
- +#define FTS_NS 10 /* stat(2) failed */
- +#define FTS_NSOK 11 /* no stat(2) requested */
- +#define FTS_SL 12 /* symbolic link */
- +#define FTS_SLNONE 13 /* symbolic link without target */
- +#define FTS_W 14 /* whiteout object */
- + u_short fts_info; /* user flags for FTSENT structure */
- +
- +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
- +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
- + u_short fts_flags; /* private flags for FTSENT structure */
- +
- +#define FTS_AGAIN 1 /* read node again */
- +#define FTS_FOLLOW 2 /* follow symbolic link */
- +#define FTS_NOINSTR 3 /* no instructions */
- +#define FTS_SKIP 4 /* discard node */
- + u_short fts_instr; /* fts_set() instructions */
- +
- + struct stat *fts_statp; /* stat(2) information */
- + char fts_name[1]; /* file name */
- +} FTSENT;
- +
- +__BEGIN_DECLS
- +FTSENT *fts_children (FTS *, int);
- +int fts_close (FTS *);
- +FTS *fts_open (char * const *, int,
- + int (*)(const FTSENT **, const FTSENT **));
- +FTSENT *fts_read (FTS *);
- +int fts_set (FTS *, FTSENT *, int) __THROW;
- +__END_DECLS
- +
- +#endif /* fts.h */
- diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
- index 9d0fef2cf260..47f0e3892294 100644
- --- a/libdwfl/linux-kernel-modules.c
- +++ b/libdwfl/linux-kernel-modules.c
- @@ -31,10 +31,14 @@
- Everything we need here is fine if its declarations just come first.
- Also, include sys/types.h before fts. On some systems fts.h is not self
- contained. */
- +#ifdef HAVE_FTS_H
- #ifdef BAD_FTS
- #include <sys/types.h>
- #include <fts.h>
- #endif
- +#else
- +#include <fts_.h>
- +#endif
-
- #include <config.h>
- #include <system.h>
- --
- 2.11.0
|