0002-Add-an-implementation-of-the-fts_-functions.patch 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. From 098760f7eac1fb86b3f6871d5bb10f9f44468f2d Mon Sep 17 00:00:00 2001
  2. From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  3. Date: Mon, 29 May 2017 23:08:05 +0300
  4. Subject: [PATCH] Add an implementation of the fts_*() functions
  5. The fts_*() functions are optional in uClibc, and not compiled in our
  6. default configuration. The best option would be to migrate this
  7. elfutils code to the nftw family of functions, but it requires quite
  8. some work.
  9. 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).
  14. *) Use gnulib, but it is quite heavy to setup, requires modifications
  15. to configure.ac, and other things.
  16. *) Copy the fts function from uClibc into elfutils source code. This
  17. is the solution used below. uClibc is LGPL, and elfutils is
  18. LGPL/GPL, so there should not be any licensing issue.
  19. Of course, the fts_*() functions are only built if they are not
  20. already provided by the C library.
  21. Based on the former patch by Thomas Petazzoni.
  22. [Vincent: tweak patch for 0.166]
  23. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  24. Signed-off-by: Vicente Olivert Riera <Vincent.Riera@imgtec.com>
  25. ---
  26. configure.ac | 4 +
  27. libdwfl/Makefile.am | 3 +
  28. libdwfl/fts.c | 1095 ++++++++++++++++++++++++++++++++++++++++
  29. libdwfl/fts_.h | 131 +++++
  30. libdwfl/linux-kernel-modules.c | 4 +
  31. 5 files changed, 1237 insertions(+)
  32. create mode 100644 libdwfl/fts.c
  33. create mode 100644 libdwfl/fts_.h
  34. diff --git a/configure.ac b/configure.ac
  35. index 7b4c38381cca..bcebb05fa532 100644
  36. --- a/configure.ac
  37. +++ b/configure.ac
  38. @@ -265,6 +265,10 @@ AC_ARG_ENABLE([progs],
  39. enable_progs=yes)
  40. AM_CONDITIONAL(ENABLE_PROGS, test "$enable_progs" = yes)
  41. +AC_CHECK_HEADER([fts.h],
  42. + AC_DEFINE([HAVE_FTS_H], [], [Define if <fts.h> is available in C library]))
  43. +AM_CONDITIONAL(HAVE_FTS, test "$ac_cv_header_fts_h" = yes)
  44. +
  45. dnl zlib is mandatory.
  46. save_LIBS="$LIBS"
  47. LIBS=
  48. diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
  49. index 89ca92ed8110..a5a5615c5f94 100644
  50. --- a/libdwfl/Makefile.am
  51. +++ b/libdwfl/Makefile.am
  52. @@ -77,6 +77,9 @@ endif
  53. if LZMA
  54. libdwfl_a_SOURCES += lzma.c
  55. endif
  56. +if !HAVE_FTS
  57. +libdwfl_a_SOURCES += fts.c
  58. +endif
  59. libdwfl = $(libdw)
  60. libdw = ../libdw/libdw.so
  61. diff --git a/libdwfl/fts.c b/libdwfl/fts.c
  62. new file mode 100644
  63. index 000000000000..f34cc03bd963
  64. --- /dev/null
  65. +++ b/libdwfl/fts.c
  66. @@ -0,0 +1,1095 @@
  67. +/*-
  68. + * Copyright (c) 1990, 1993, 1994
  69. + * The Regents of the University of California. All rights reserved.
  70. + *
  71. + * Redistribution and use in source and binary forms, with or without
  72. + * modification, are permitted provided that the following conditions
  73. + * are met:
  74. + * 1. Redistributions of source code must retain the above copyright
  75. + * notice, this list of conditions and the following disclaimer.
  76. + * 2. Redistributions in binary form must reproduce the above copyright
  77. + * notice, this list of conditions and the following disclaimer in the
  78. + * documentation and/or other materials provided with the distribution.
  79. + * 4. Neither the name of the University nor the names of its contributors
  80. + * may be used to endorse or promote products derived from this software
  81. + * without specific prior written permission.
  82. + *
  83. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  84. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  85. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  86. + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  87. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  88. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  89. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  90. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  91. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  92. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  93. + * SUCH DAMAGE.
  94. + */
  95. +
  96. +#include <sys/param.h>
  97. +#include <sys/stat.h>
  98. +#include <fcntl.h>
  99. +#include <dirent.h>
  100. +#include <errno.h>
  101. +#include "fts_.h"
  102. +#include <stdlib.h>
  103. +#include <string.h>
  104. +#include <unistd.h>
  105. +
  106. +/* Largest alignment size needed, minus one.
  107. + Usually long double is the worst case. */
  108. +#ifndef ALIGNBYTES
  109. +#define ALIGNBYTES (__alignof__ (long double) - 1)
  110. +#endif
  111. +/* Align P to that size. */
  112. +#ifndef ALIGN
  113. +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
  114. +#endif
  115. +
  116. +
  117. +static FTSENT *fts_alloc (FTS *, const char *, size_t);
  118. +static FTSENT *fts_build (FTS *, int);
  119. +static void fts_lfree (FTSENT *);
  120. +static void fts_load (FTS *, FTSENT *);
  121. +static size_t fts_maxarglen (char * const *);
  122. +static void fts_padjust (FTS *, FTSENT *);
  123. +static int fts_palloc (FTS *, size_t);
  124. +static FTSENT *fts_sort (FTS *, FTSENT *, int);
  125. +static u_short fts_stat (FTS *, FTSENT *, int);
  126. +static int fts_safe_changedir (FTS *, FTSENT *, int, const char *);
  127. +
  128. +#ifndef MAX
  129. +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
  130. + __typeof__ (b) _b = (b); \
  131. + _a > _b ? _a : _b; })
  132. +#endif
  133. +
  134. +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
  135. +
  136. +#define CLR(opt) (sp->fts_options &= ~(opt))
  137. +#define ISSET(opt) (sp->fts_options & (opt))
  138. +#define SET(opt) (sp->fts_options |= (opt))
  139. +
  140. +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
  141. +
  142. +/* fts_build flags */
  143. +#define BCHILD 1 /* fts_children */
  144. +#define BNAMES 2 /* fts_children, names only */
  145. +#define BREAD 3 /* fts_read */
  146. +
  147. +FTS *
  148. +fts_open( char * const *argv, register int options,
  149. + int (*compar) (const FTSENT **, const FTSENT **))
  150. +{
  151. + register FTS *sp;
  152. + register FTSENT *p, *root;
  153. + register int nitems;
  154. + FTSENT *parent = NULL;
  155. + FTSENT *tmp = NULL;
  156. +
  157. + /* Options check. */
  158. + if (options & ~FTS_OPTIONMASK) {
  159. + errno = EINVAL;
  160. + return (NULL);
  161. + }
  162. +
  163. + /* Allocate/initialize the stream */
  164. + if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
  165. + return (NULL);
  166. + memset(sp, 0, sizeof(FTS));
  167. + sp->fts_compar = (int (*) (const void *, const void *)) compar;
  168. + sp->fts_options = options;
  169. +
  170. + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
  171. + if (ISSET(FTS_LOGICAL))
  172. + SET(FTS_NOCHDIR);
  173. +
  174. + /*
  175. + * Start out with 1K of path space, and enough, in any case,
  176. + * to hold the user's paths.
  177. + */
  178. +#ifndef MAXPATHLEN
  179. +#define MAXPATHLEN 1024
  180. +#endif
  181. + size_t maxarglen = fts_maxarglen(argv);
  182. + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
  183. + goto mem1;
  184. +
  185. + /* Allocate/initialize root's parent. */
  186. + if (*argv != NULL) {
  187. + if ((parent = fts_alloc(sp, "", 0)) == NULL)
  188. + goto mem2;
  189. + parent->fts_level = FTS_ROOTPARENTLEVEL;
  190. + }
  191. +
  192. + /* Allocate/initialize root(s). */
  193. + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
  194. + /* Don't allow zero-length paths. */
  195. + size_t len = strlen(*argv);
  196. + if (len == 0) {
  197. + errno = ENOENT;
  198. + goto mem3;
  199. + }
  200. +
  201. + p = fts_alloc(sp, *argv, len);
  202. + p->fts_level = FTS_ROOTLEVEL;
  203. + p->fts_parent = parent;
  204. + p->fts_accpath = p->fts_name;
  205. + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
  206. +
  207. + /* Command-line "." and ".." are real directories. */
  208. + if (p->fts_info == FTS_DOT)
  209. + p->fts_info = FTS_D;
  210. +
  211. + /*
  212. + * If comparison routine supplied, traverse in sorted
  213. + * order; otherwise traverse in the order specified.
  214. + */
  215. + if (compar) {
  216. + p->fts_link = root;
  217. + root = p;
  218. + } else {
  219. + p->fts_link = NULL;
  220. + if (root == NULL)
  221. + tmp = root = p;
  222. + else {
  223. + tmp->fts_link = p;
  224. + tmp = p;
  225. + }
  226. + }
  227. + }
  228. + if (compar && nitems > 1)
  229. + root = fts_sort(sp, root, nitems);
  230. +
  231. + /*
  232. + * Allocate a dummy pointer and make fts_read think that we've just
  233. + * finished the node before the root(s); set p->fts_info to FTS_INIT
  234. + * so that everything about the "current" node is ignored.
  235. + */
  236. + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
  237. + goto mem3;
  238. + sp->fts_cur->fts_link = root;
  239. + sp->fts_cur->fts_info = FTS_INIT;
  240. +
  241. + /*
  242. + * If using chdir(2), grab a file descriptor pointing to dot to ensure
  243. + * that we can get back here; this could be avoided for some paths,
  244. + * but almost certainly not worth the effort. Slashes, symbolic links,
  245. + * and ".." are all fairly nasty problems. Note, if we can't get the
  246. + * descriptor we run anyway, just more slowly.
  247. + */
  248. + if (!ISSET(FTS_NOCHDIR)
  249. + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
  250. + SET(FTS_NOCHDIR);
  251. +
  252. + return (sp);
  253. +
  254. +mem3: fts_lfree(root);
  255. + free(parent);
  256. +mem2: free(sp->fts_path);
  257. +mem1: free(sp);
  258. + return (NULL);
  259. +}
  260. +
  261. +static void
  262. +fts_load(FTS *sp, register FTSENT *p)
  263. +{
  264. + register int len;
  265. + register char *cp;
  266. +
  267. + /*
  268. + * Load the stream structure for the next traversal. Since we don't
  269. + * actually enter the directory until after the preorder visit, set
  270. + * the fts_accpath field specially so the chdir gets done to the right
  271. + * place and the user can access the first node. From fts_open it's
  272. + * known that the path will fit.
  273. + */
  274. + len = p->fts_pathlen = p->fts_namelen;
  275. + memmove(sp->fts_path, p->fts_name, len + 1);
  276. + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
  277. + len = strlen(++cp);
  278. + memmove(p->fts_name, cp, len + 1);
  279. + p->fts_namelen = len;
  280. + }
  281. + p->fts_accpath = p->fts_path = sp->fts_path;
  282. + sp->fts_dev = p->fts_dev;
  283. +}
  284. +
  285. +int
  286. +fts_close(FTS *sp)
  287. +{
  288. + register FTSENT *freep, *p;
  289. + int saved_errno;
  290. +
  291. + /*
  292. + * This still works if we haven't read anything -- the dummy structure
  293. + * points to the root list, so we step through to the end of the root
  294. + * list which has a valid parent pointer.
  295. + */
  296. + if (sp->fts_cur) {
  297. + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
  298. + freep = p;
  299. + p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
  300. + free(freep);
  301. + }
  302. + free(p);
  303. + }
  304. +
  305. + /* Free up child linked list, sort array, path buffer. */
  306. + if (sp->fts_child)
  307. + fts_lfree(sp->fts_child);
  308. + free(sp->fts_array);
  309. + free(sp->fts_path);
  310. +
  311. + /* Return to original directory, save errno if necessary. */
  312. + if (!ISSET(FTS_NOCHDIR)) {
  313. + saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
  314. + (void)close(sp->fts_rfd);
  315. +
  316. + /* Set errno and return. */
  317. + if (saved_errno != 0) {
  318. + /* Free up the stream pointer. */
  319. + free(sp);
  320. + errno = saved_errno;
  321. + return (-1);
  322. + }
  323. + }
  324. +
  325. + /* Free up the stream pointer. */
  326. + free(sp);
  327. + return (0);
  328. +}
  329. +
  330. +/*
  331. + * Special case of "/" at the end of the path so that slashes aren't
  332. + * appended which would cause paths to be written as "....//foo".
  333. + */
  334. +#define NAPPEND(p) \
  335. + (p->fts_path[p->fts_pathlen - 1] == '/' \
  336. + ? p->fts_pathlen - 1 : p->fts_pathlen)
  337. +
  338. +FTSENT *
  339. +fts_read(register FTS *sp)
  340. +{
  341. + register FTSENT *p, *tmp;
  342. + register int instr;
  343. + register char *t;
  344. + int saved_errno;
  345. +
  346. + /* If finished or unrecoverable error, return NULL. */
  347. + if (sp->fts_cur == NULL || ISSET(FTS_STOP))
  348. + return (NULL);
  349. +
  350. + /* Set current node pointer. */
  351. + p = sp->fts_cur;
  352. +
  353. + /* Save and zero out user instructions. */
  354. + instr = p->fts_instr;
  355. + p->fts_instr = FTS_NOINSTR;
  356. +
  357. + /* Any type of file may be re-visited; re-stat and re-turn. */
  358. + if (instr == FTS_AGAIN) {
  359. + p->fts_info = fts_stat(sp, p, 0);
  360. + return (p);
  361. + }
  362. +
  363. + /*
  364. + * Following a symlink -- SLNONE test allows application to see
  365. + * SLNONE and recover. If indirecting through a symlink, have
  366. + * keep a pointer to current location. If unable to get that
  367. + * pointer, follow fails.
  368. + */
  369. + if (instr == FTS_FOLLOW &&
  370. + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
  371. + p->fts_info = fts_stat(sp, p, 1);
  372. + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
  373. + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
  374. + p->fts_errno = errno;
  375. + p->fts_info = FTS_ERR;
  376. + } else
  377. + p->fts_flags |= FTS_SYMFOLLOW;
  378. + }
  379. + return (p);
  380. + }
  381. +
  382. + /* Directory in pre-order. */
  383. + if (p->fts_info == FTS_D) {
  384. + /* If skipped or crossed mount point, do post-order visit. */
  385. + if (instr == FTS_SKIP ||
  386. + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
  387. + if (p->fts_flags & FTS_SYMFOLLOW)
  388. + (void)close(p->fts_symfd);
  389. + if (sp->fts_child) {
  390. + fts_lfree(sp->fts_child);
  391. + sp->fts_child = NULL;
  392. + }
  393. + p->fts_info = FTS_DP;
  394. + return (p);
  395. + }
  396. +
  397. + /* Rebuild if only read the names and now traversing. */
  398. + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
  399. + CLR(FTS_NAMEONLY);
  400. + fts_lfree(sp->fts_child);
  401. + sp->fts_child = NULL;
  402. + }
  403. +
  404. + /*
  405. + * Cd to the subdirectory.
  406. + *
  407. + * If have already read and now fail to chdir, whack the list
  408. + * to make the names come out right, and set the parent errno
  409. + * so the application will eventually get an error condition.
  410. + * Set the FTS_DONTCHDIR flag so that when we logically change
  411. + * directories back to the parent we don't do a chdir.
  412. + *
  413. + * If haven't read do so. If the read fails, fts_build sets
  414. + * FTS_STOP or the fts_info field of the node.
  415. + */
  416. + if (sp->fts_child != NULL) {
  417. + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
  418. + p->fts_errno = errno;
  419. + p->fts_flags |= FTS_DONTCHDIR;
  420. + for (p = sp->fts_child; p != NULL;
  421. + p = p->fts_link)
  422. + p->fts_accpath =
  423. + p->fts_parent->fts_accpath;
  424. + }
  425. + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
  426. + if (ISSET(FTS_STOP))
  427. + return (NULL);
  428. + return (p);
  429. + }
  430. + p = sp->fts_child;
  431. + sp->fts_child = NULL;
  432. + sp->fts_cur = p;
  433. + goto name;
  434. + }
  435. +
  436. + /* Move to the next node on this level. */
  437. +next: tmp = p;
  438. + if ((p = p->fts_link) != NULL) {
  439. + sp->fts_cur = p;
  440. + free(tmp);
  441. +
  442. + /*
  443. + * If reached the top, return to the original directory (or
  444. + * the root of the tree), and load the paths for the next root.
  445. + */
  446. + if (p->fts_level == FTS_ROOTLEVEL) {
  447. + if (FCHDIR(sp, sp->fts_rfd)) {
  448. + SET(FTS_STOP);
  449. + return (NULL);
  450. + }
  451. + fts_load(sp, p);
  452. + return p;
  453. + }
  454. +
  455. + /*
  456. + * User may have called fts_set on the node. If skipped,
  457. + * ignore. If followed, get a file descriptor so we can
  458. + * get back if necessary.
  459. + */
  460. + if (p->fts_instr == FTS_SKIP)
  461. + goto next;
  462. + if (p->fts_instr == FTS_FOLLOW) {
  463. + p->fts_info = fts_stat(sp, p, 1);
  464. + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
  465. + if ((p->fts_symfd =
  466. + open(".", O_RDONLY, 0)) < 0) {
  467. + p->fts_errno = errno;
  468. + p->fts_info = FTS_ERR;
  469. + } else
  470. + p->fts_flags |= FTS_SYMFOLLOW;
  471. + }
  472. + p->fts_instr = FTS_NOINSTR;
  473. + }
  474. +
  475. +name: t = sp->fts_path + NAPPEND(p->fts_parent);
  476. + *t++ = '/';
  477. + memmove(t, p->fts_name, p->fts_namelen + 1);
  478. + return p;
  479. + }
  480. +
  481. + /* Move up to the parent node. */
  482. + p = tmp->fts_parent;
  483. + sp->fts_cur = p;
  484. + free(tmp);
  485. +
  486. + if (p->fts_level == FTS_ROOTPARENTLEVEL) {
  487. + /*
  488. + * Done; free everything up and set errno to 0 so the user
  489. + * can distinguish between error and EOF.
  490. + */
  491. + free(p);
  492. + errno = 0;
  493. + return (sp->fts_cur = NULL);
  494. + }
  495. +
  496. + /* NUL terminate the pathname. */
  497. + sp->fts_path[p->fts_pathlen] = '\0';
  498. +
  499. + /*
  500. + * Return to the parent directory. If at a root node or came through
  501. + * a symlink, go back through the file descriptor. Otherwise, cd up
  502. + * one directory.
  503. + */
  504. + if (p->fts_level == FTS_ROOTLEVEL) {
  505. + if (FCHDIR(sp, sp->fts_rfd)) {
  506. + SET(FTS_STOP);
  507. + return (NULL);
  508. + }
  509. + } else if (p->fts_flags & FTS_SYMFOLLOW) {
  510. + if (FCHDIR(sp, p->fts_symfd)) {
  511. + saved_errno = errno;
  512. + (void)close(p->fts_symfd);
  513. + errno = saved_errno;
  514. + SET(FTS_STOP);
  515. + return (NULL);
  516. + }
  517. + (void)close(p->fts_symfd);
  518. + } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
  519. + fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
  520. + SET(FTS_STOP);
  521. + return (NULL);
  522. + }
  523. + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
  524. + return p;
  525. +}
  526. +
  527. +/*
  528. + * Fts_set takes the stream as an argument although it's not used in this
  529. + * implementation; it would be necessary if anyone wanted to add global
  530. + * semantics to fts using fts_set. An error return is allowed for similar
  531. + * reasons.
  532. + */
  533. +/* ARGSUSED */
  534. +int
  535. +fts_set(FTS *sp, FTSENT *p, int instr)
  536. +{
  537. + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
  538. + instr != FTS_NOINSTR && instr != FTS_SKIP) {
  539. + errno = EINVAL;
  540. + return (1);
  541. + }
  542. + p->fts_instr = instr;
  543. + return (0);
  544. +}
  545. +
  546. +FTSENT *
  547. +fts_children(register FTS *sp, int instr)
  548. +{
  549. + register FTSENT *p;
  550. + int fd;
  551. +
  552. + if (instr != 0 && instr != FTS_NAMEONLY) {
  553. + errno = EINVAL;
  554. + return (NULL);
  555. + }
  556. +
  557. + /* Set current node pointer. */
  558. + p = sp->fts_cur;
  559. +
  560. + /*
  561. + * Errno set to 0 so user can distinguish empty directory from
  562. + * an error.
  563. + */
  564. + errno = 0;
  565. +
  566. + /* Fatal errors stop here. */
  567. + if (ISSET(FTS_STOP))
  568. + return (NULL);
  569. +
  570. + /* Return logical hierarchy of user's arguments. */
  571. + if (p->fts_info == FTS_INIT)
  572. + return (p->fts_link);
  573. +
  574. + /*
  575. + * If not a directory being visited in pre-order, stop here. Could
  576. + * allow FTS_DNR, assuming the user has fixed the problem, but the
  577. + * same effect is available with FTS_AGAIN.
  578. + */
  579. + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
  580. + return (NULL);
  581. +
  582. + /* Free up any previous child list. */
  583. + if (sp->fts_child != NULL)
  584. + fts_lfree(sp->fts_child);
  585. +
  586. + if (instr == FTS_NAMEONLY) {
  587. + SET(FTS_NAMEONLY);
  588. + instr = BNAMES;
  589. + } else
  590. + instr = BCHILD;
  591. +
  592. + /*
  593. + * If using chdir on a relative path and called BEFORE fts_read does
  594. + * its chdir to the root of a traversal, we can lose -- we need to
  595. + * chdir into the subdirectory, and we don't know where the current
  596. + * directory is, so we can't get back so that the upcoming chdir by
  597. + * fts_read will work.
  598. + */
  599. + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
  600. + ISSET(FTS_NOCHDIR))
  601. + return (sp->fts_child = fts_build(sp, instr));
  602. +
  603. + if ((fd = open(".", O_RDONLY, 0)) < 0)
  604. + return (NULL);
  605. + sp->fts_child = fts_build(sp, instr);
  606. + if (fchdir(fd))
  607. + return (NULL);
  608. + (void)close(fd);
  609. + return (sp->fts_child);
  610. +}
  611. +
  612. +/*
  613. + * This is the tricky part -- do not casually change *anything* in here. The
  614. + * idea is to build the linked list of entries that are used by fts_children
  615. + * and fts_read. There are lots of special cases.
  616. + *
  617. + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
  618. + * set and it's a physical walk (so that symbolic links can't be directories),
  619. + * we can do things quickly. First, if it's a 4.4BSD file system, the type
  620. + * of the file is in the directory entry. Otherwise, we assume that the number
  621. + * of subdirectories in a node is equal to the number of links to the parent.
  622. + * The former skips all stat calls. The latter skips stat calls in any leaf
  623. + * directories and for any files after the subdirectories in the directory have
  624. + * been found, cutting the stat calls by about 2/3.
  625. + */
  626. +static FTSENT *
  627. +fts_build(register FTS *sp, int type)
  628. +{
  629. + register struct dirent *dp;
  630. + register FTSENT *p, *head;
  631. + register int nitems;
  632. + FTSENT *cur, *tail;
  633. + DIR *dirp;
  634. + void *oldaddr;
  635. + int cderrno, descend, len, level, nlinks, saved_errno,
  636. + nostat, doadjust;
  637. + size_t maxlen;
  638. + char *cp;
  639. +
  640. + /* Set current node pointer. */
  641. + cur = sp->fts_cur;
  642. +
  643. + /*
  644. + * Open the directory for reading. If this fails, we're done.
  645. + * If being called from fts_read, set the fts_info field.
  646. + */
  647. +#if defined FTS_WHITEOUT && 0
  648. + if (ISSET(FTS_WHITEOUT))
  649. + oflag = DTF_NODUP|DTF_REWIND;
  650. + else
  651. + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
  652. +#else
  653. +# define opendir2(path, flag) opendir(path)
  654. +#endif
  655. + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
  656. + if (type == BREAD) {
  657. + cur->fts_info = FTS_DNR;
  658. + cur->fts_errno = errno;
  659. + }
  660. + return (NULL);
  661. + }
  662. +
  663. + /*
  664. + * Nlinks is the number of possible entries of type directory in the
  665. + * directory if we're cheating on stat calls, 0 if we're not doing
  666. + * any stat calls at all, -1 if we're doing stats on everything.
  667. + */
  668. + if (type == BNAMES) {
  669. + nlinks = 0;
  670. + /* Be quiet about nostat, GCC. */
  671. + nostat = 0;
  672. + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
  673. + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
  674. + nostat = 1;
  675. + } else {
  676. + nlinks = -1;
  677. + nostat = 0;
  678. + }
  679. +
  680. +#ifdef notdef
  681. + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
  682. + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
  683. + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
  684. +#endif
  685. + /*
  686. + * If we're going to need to stat anything or we want to descend
  687. + * and stay in the directory, chdir. If this fails we keep going,
  688. + * but set a flag so we don't chdir after the post-order visit.
  689. + * We won't be able to stat anything, but we can still return the
  690. + * names themselves. Note, that since fts_read won't be able to
  691. + * chdir into the directory, it will have to return different path
  692. + * names than before, i.e. "a/b" instead of "b". Since the node
  693. + * has already been visited in pre-order, have to wait until the
  694. + * post-order visit to return the error. There is a special case
  695. + * here, if there was nothing to stat then it's not an error to
  696. + * not be able to stat. This is all fairly nasty. If a program
  697. + * needed sorted entries or stat information, they had better be
  698. + * checking FTS_NS on the returned nodes.
  699. + */
  700. + cderrno = 0;
  701. + if (nlinks || type == BREAD) {
  702. + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
  703. + if (nlinks && type == BREAD)
  704. + cur->fts_errno = errno;
  705. + cur->fts_flags |= FTS_DONTCHDIR;
  706. + descend = 0;
  707. + cderrno = errno;
  708. + (void)closedir(dirp);
  709. + dirp = NULL;
  710. + } else
  711. + descend = 1;
  712. + } else
  713. + descend = 0;
  714. +
  715. + /*
  716. + * Figure out the max file name length that can be stored in the
  717. + * current path -- the inner loop allocates more path as necessary.
  718. + * We really wouldn't have to do the maxlen calculations here, we
  719. + * could do them in fts_read before returning the path, but it's a
  720. + * lot easier here since the length is part of the dirent structure.
  721. + *
  722. + * If not changing directories set a pointer so that can just append
  723. + * each new name into the path.
  724. + */
  725. + len = NAPPEND(cur);
  726. + if (ISSET(FTS_NOCHDIR)) {
  727. + cp = sp->fts_path + len;
  728. + *cp++ = '/';
  729. + } else {
  730. + /* GCC, you're too verbose. */
  731. + cp = NULL;
  732. + }
  733. + len++;
  734. + maxlen = sp->fts_pathlen - len;
  735. +
  736. + level = cur->fts_level + 1;
  737. +
  738. + /* Read the directory, attaching each entry to the `link' pointer. */
  739. + doadjust = 0;
  740. + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
  741. + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
  742. + continue;
  743. +
  744. + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
  745. + goto mem1;
  746. + if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
  747. + oldaddr = sp->fts_path;
  748. + if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
  749. + /*
  750. + * No more memory for path or structures. Save
  751. + * errno, free up the current structure and the
  752. + * structures already allocated.
  753. + */
  754. +mem1: saved_errno = errno;
  755. + free(p);
  756. + fts_lfree(head);
  757. + (void)closedir(dirp);
  758. + cur->fts_info = FTS_ERR;
  759. + SET(FTS_STOP);
  760. + errno = saved_errno;
  761. + return (NULL);
  762. + }
  763. + /* Did realloc() change the pointer? */
  764. + if (oldaddr != sp->fts_path) {
  765. + doadjust = 1;
  766. + if (ISSET(FTS_NOCHDIR))
  767. + cp = sp->fts_path + len;
  768. + }
  769. + maxlen = sp->fts_pathlen - len;
  770. + }
  771. +
  772. + if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
  773. + /*
  774. + * In an FTSENT, fts_pathlen is a u_short so it is
  775. + * possible to wraparound here. If we do, free up
  776. + * the current structure and the structures already
  777. + * allocated, then error out with ENAMETOOLONG.
  778. + */
  779. + free(p);
  780. + fts_lfree(head);
  781. + (void)closedir(dirp);
  782. + cur->fts_info = FTS_ERR;
  783. + SET(FTS_STOP);
  784. + errno = ENAMETOOLONG;
  785. + return (NULL);
  786. + }
  787. + p->fts_level = level;
  788. + p->fts_parent = sp->fts_cur;
  789. + p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
  790. +
  791. +#if defined FTS_WHITEOUT && 0
  792. + if (dp->d_type == DT_WHT)
  793. + p->fts_flags |= FTS_ISW;
  794. +#endif
  795. +
  796. +#if 0
  797. + /* Unreachable code. cderrno is only ever set to a nonnull
  798. + value if dirp is closed at the same time. But then we
  799. + cannot enter this loop. */
  800. + if (cderrno) {
  801. + if (nlinks) {
  802. + p->fts_info = FTS_NS;
  803. + p->fts_errno = cderrno;
  804. + } else
  805. + p->fts_info = FTS_NSOK;
  806. + p->fts_accpath = cur->fts_accpath;
  807. + } else
  808. +#endif
  809. + if (nlinks == 0
  810. +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
  811. + || (nostat &&
  812. + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
  813. +#endif
  814. + ) {
  815. + p->fts_accpath =
  816. + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
  817. + p->fts_info = FTS_NSOK;
  818. + } else {
  819. + /* Build a file name for fts_stat to stat. */
  820. + if (ISSET(FTS_NOCHDIR)) {
  821. + p->fts_accpath = p->fts_path;
  822. + memmove(cp, p->fts_name, p->fts_namelen + 1);
  823. + } else
  824. + p->fts_accpath = p->fts_name;
  825. + /* Stat it. */
  826. + p->fts_info = fts_stat(sp, p, 0);
  827. +
  828. + /* Decrement link count if applicable. */
  829. + if (nlinks > 0 && (p->fts_info == FTS_D ||
  830. + p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
  831. + --nlinks;
  832. + }
  833. +
  834. + /* We walk in directory order so "ls -f" doesn't get upset. */
  835. + p->fts_link = NULL;
  836. + if (head == NULL)
  837. + head = tail = p;
  838. + else {
  839. + tail->fts_link = p;
  840. + tail = p;
  841. + }
  842. + ++nitems;
  843. + }
  844. + if (dirp)
  845. + (void)closedir(dirp);
  846. +
  847. + /*
  848. + * If realloc() changed the address of the path, adjust the
  849. + * addresses for the rest of the tree and the dir list.
  850. + */
  851. + if (doadjust)
  852. + fts_padjust(sp, head);
  853. +
  854. + /*
  855. + * If not changing directories, reset the path back to original
  856. + * state.
  857. + */
  858. + if (ISSET(FTS_NOCHDIR)) {
  859. + if (len == sp->fts_pathlen || nitems == 0)
  860. + --cp;
  861. + *cp = '\0';
  862. + }
  863. +
  864. + /*
  865. + * If descended after called from fts_children or after called from
  866. + * fts_read and nothing found, get back. At the root level we use
  867. + * the saved fd; if one of fts_open()'s arguments is a relative path
  868. + * to an empty directory, we wind up here with no other way back. If
  869. + * can't get back, we're done.
  870. + */
  871. + if (descend && (type == BCHILD || !nitems) &&
  872. + (cur->fts_level == FTS_ROOTLEVEL ?
  873. + FCHDIR(sp, sp->fts_rfd) :
  874. + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
  875. + cur->fts_info = FTS_ERR;
  876. + SET(FTS_STOP);
  877. + fts_lfree(head);
  878. + return (NULL);
  879. + }
  880. +
  881. + /* If didn't find anything, return NULL. */
  882. + if (!nitems) {
  883. + if (type == BREAD)
  884. + cur->fts_info = FTS_DP;
  885. + fts_lfree(head);
  886. + return (NULL);
  887. + }
  888. +
  889. + /* Sort the entries. */
  890. + if (sp->fts_compar && nitems > 1)
  891. + head = fts_sort(sp, head, nitems);
  892. + return (head);
  893. +}
  894. +
  895. +static u_short
  896. +fts_stat(FTS *sp, register FTSENT *p, int follow)
  897. +{
  898. + register FTSENT *t;
  899. + register dev_t dev;
  900. + register ino_t ino;
  901. + struct stat *sbp, sb;
  902. + int saved_errno;
  903. +
  904. + /* If user needs stat info, stat buffer already allocated. */
  905. + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
  906. +
  907. +#if defined FTS_WHITEOUT && 0
  908. + /* check for whiteout */
  909. + if (p->fts_flags & FTS_ISW) {
  910. + if (sbp != &sb) {
  911. + memset(sbp, '\0', sizeof (*sbp));
  912. + sbp->st_mode = S_IFWHT;
  913. + }
  914. + return (FTS_W);
  915. + }
  916. +#endif
  917. +
  918. + /*
  919. + * If doing a logical walk, or application requested FTS_FOLLOW, do
  920. + * a stat(2). If that fails, check for a non-existent symlink. If
  921. + * fail, set the errno from the stat call.
  922. + */
  923. + if (ISSET(FTS_LOGICAL) || follow) {
  924. + if (stat(p->fts_accpath, sbp)) {
  925. + saved_errno = errno;
  926. + if (!lstat(p->fts_accpath, sbp)) {
  927. + errno = 0;
  928. + return (FTS_SLNONE);
  929. + }
  930. + p->fts_errno = saved_errno;
  931. + goto err;
  932. + }
  933. + } else if (lstat(p->fts_accpath, sbp)) {
  934. + p->fts_errno = errno;
  935. +err: memset(sbp, 0, sizeof(struct stat));
  936. + return (FTS_NS);
  937. + }
  938. +
  939. + if (S_ISDIR(sbp->st_mode)) {
  940. + /*
  941. + * Set the device/inode. Used to find cycles and check for
  942. + * crossing mount points. Also remember the link count, used
  943. + * in fts_build to limit the number of stat calls. It is
  944. + * understood that these fields are only referenced if fts_info
  945. + * is set to FTS_D.
  946. + */
  947. + dev = p->fts_dev = sbp->st_dev;
  948. + ino = p->fts_ino = sbp->st_ino;
  949. + p->fts_nlink = sbp->st_nlink;
  950. +
  951. + if (ISDOT(p->fts_name))
  952. + return (FTS_DOT);
  953. +
  954. + /*
  955. + * Cycle detection is done by brute force when the directory
  956. + * is first encountered. If the tree gets deep enough or the
  957. + * number of symbolic links to directories is high enough,
  958. + * something faster might be worthwhile.
  959. + */
  960. + for (t = p->fts_parent;
  961. + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
  962. + if (ino == t->fts_ino && dev == t->fts_dev) {
  963. + p->fts_cycle = t;
  964. + return (FTS_DC);
  965. + }
  966. + return (FTS_D);
  967. + }
  968. + if (S_ISLNK(sbp->st_mode))
  969. + return (FTS_SL);
  970. + if (S_ISREG(sbp->st_mode))
  971. + return (FTS_F);
  972. + return (FTS_DEFAULT);
  973. +}
  974. +
  975. +static FTSENT *
  976. +fts_sort(FTS *sp, FTSENT *head, register int nitems)
  977. +{
  978. + register FTSENT **ap, *p;
  979. +
  980. + /*
  981. + * Construct an array of pointers to the structures and call qsort(3).
  982. + * Reassemble the array in the order returned by qsort. If unable to
  983. + * sort for memory reasons, return the directory entries in their
  984. + * current order. Allocate enough space for the current needs plus
  985. + * 40 so don't realloc one entry at a time.
  986. + */
  987. + if (nitems > sp->fts_nitems) {
  988. + struct _ftsent **a;
  989. +
  990. + sp->fts_nitems = nitems + 40;
  991. + if ((a = realloc(sp->fts_array,
  992. + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
  993. + free(sp->fts_array);
  994. + sp->fts_array = NULL;
  995. + sp->fts_nitems = 0;
  996. + return (head);
  997. + }
  998. + sp->fts_array = a;
  999. + }
  1000. + for (ap = sp->fts_array, p = head; p; p = p->fts_link)
  1001. + *ap++ = p;
  1002. + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
  1003. + for (head = *(ap = sp->fts_array); --nitems; ++ap)
  1004. + ap[0]->fts_link = ap[1];
  1005. + ap[0]->fts_link = NULL;
  1006. + return (head);
  1007. +}
  1008. +
  1009. +static FTSENT *
  1010. +fts_alloc(FTS *sp, const char *name, size_t namelen)
  1011. +{
  1012. + register FTSENT *p;
  1013. + size_t len;
  1014. +
  1015. + /*
  1016. + * The file name is a variable length array and no stat structure is
  1017. + * necessary if the user has set the nostat bit. Allocate the FTSENT
  1018. + * structure, the file name and the stat structure in one chunk, but
  1019. + * be careful that the stat structure is reasonably aligned. Since the
  1020. + * fts_name field is declared to be of size 1, the fts_name pointer is
  1021. + * namelen + 2 before the first possible address of the stat structure.
  1022. + */
  1023. + len = sizeof(FTSENT) + namelen;
  1024. + if (!ISSET(FTS_NOSTAT))
  1025. + len += sizeof(struct stat) + ALIGNBYTES;
  1026. + if ((p = malloc(len)) == NULL)
  1027. + return (NULL);
  1028. +
  1029. + /* Copy the name and guarantee NUL termination. */
  1030. + memmove(p->fts_name, name, namelen);
  1031. + p->fts_name[namelen] = '\0';
  1032. +
  1033. + if (!ISSET(FTS_NOSTAT))
  1034. + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
  1035. + p->fts_namelen = namelen;
  1036. + p->fts_path = sp->fts_path;
  1037. + p->fts_errno = 0;
  1038. + p->fts_flags = 0;
  1039. + p->fts_instr = FTS_NOINSTR;
  1040. + p->fts_number = 0;
  1041. + p->fts_pointer = NULL;
  1042. + return (p);
  1043. +}
  1044. +
  1045. +static void
  1046. +fts_lfree(register FTSENT *head)
  1047. +{
  1048. + register FTSENT *p;
  1049. +
  1050. + /* Free a linked list of structures. */
  1051. + while ((p = head)) {
  1052. + head = head->fts_link;
  1053. + free(p);
  1054. + }
  1055. +}
  1056. +
  1057. +/*
  1058. + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
  1059. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even
  1060. + * though the kernel won't resolve them. Add the size (not just what's needed)
  1061. + * plus 256 bytes so don't realloc the path 2 bytes at a time.
  1062. + */
  1063. +static int
  1064. +fts_palloc(FTS *sp, size_t more)
  1065. +{
  1066. + char *p;
  1067. +
  1068. + sp->fts_pathlen += more + 256;
  1069. + /*
  1070. + * Check for possible wraparound. In an FTS, fts_pathlen is
  1071. + * a signed int but in an FTSENT it is an unsigned short.
  1072. + * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
  1073. + */
  1074. + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
  1075. + free(sp->fts_path);
  1076. + sp->fts_path = NULL;
  1077. + errno = ENAMETOOLONG;
  1078. + return (1);
  1079. + }
  1080. + p = realloc(sp->fts_path, sp->fts_pathlen);
  1081. + if (p == NULL) {
  1082. + free(sp->fts_path);
  1083. + sp->fts_path = NULL;
  1084. + return 1;
  1085. + }
  1086. + sp->fts_path = p;
  1087. + return 0;
  1088. +}
  1089. +
  1090. +/*
  1091. + * When the path is realloc'd, have to fix all of the pointers in structures
  1092. + * already returned.
  1093. + */
  1094. +static void
  1095. +fts_padjust(FTS *sp, FTSENT *head)
  1096. +{
  1097. + FTSENT *p;
  1098. + char *addr = sp->fts_path;
  1099. +
  1100. +#define ADJUST(p) do { \
  1101. + if ((p)->fts_accpath != (p)->fts_name) { \
  1102. + (p)->fts_accpath = \
  1103. + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
  1104. + } \
  1105. + (p)->fts_path = addr; \
  1106. +} while (0)
  1107. + /* Adjust the current set of children. */
  1108. + for (p = sp->fts_child; p; p = p->fts_link)
  1109. + ADJUST(p);
  1110. +
  1111. + /* Adjust the rest of the tree, including the current level. */
  1112. + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
  1113. + ADJUST(p);
  1114. + p = p->fts_link ? p->fts_link : p->fts_parent;
  1115. + }
  1116. +}
  1117. +
  1118. +static size_t
  1119. +fts_maxarglen(char * const *argv)
  1120. +{
  1121. + size_t len, max;
  1122. +
  1123. + for (max = 0; *argv; ++argv)
  1124. + if ((len = strlen(*argv)) > max)
  1125. + max = len;
  1126. + return (max + 1);
  1127. +}
  1128. +
  1129. +/*
  1130. + * Change to dir specified by fd or p->fts_accpath without getting
  1131. + * tricked by someone changing the world out from underneath us.
  1132. + * Assumes p->fts_dev and p->fts_ino are filled in.
  1133. + */
  1134. +static int
  1135. +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
  1136. +{
  1137. + int ret, oerrno, newfd;
  1138. + struct stat64 sb;
  1139. +
  1140. + newfd = fd;
  1141. + if (ISSET(FTS_NOCHDIR))
  1142. + return (0);
  1143. + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
  1144. + return (-1);
  1145. + if (fstat64(newfd, &sb)) {
  1146. + ret = -1;
  1147. + goto bail;
  1148. + }
  1149. + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
  1150. + errno = ENOENT; /* disinformation */
  1151. + ret = -1;
  1152. + goto bail;
  1153. + }
  1154. + ret = fchdir(newfd);
  1155. +bail:
  1156. + oerrno = errno;
  1157. + if (fd < 0)
  1158. + (void)close(newfd);
  1159. + errno = oerrno;
  1160. + return (ret);
  1161. +}
  1162. diff --git a/libdwfl/fts_.h b/libdwfl/fts_.h
  1163. new file mode 100644
  1164. index 000000000000..0a070ba8dce5
  1165. --- /dev/null
  1166. +++ b/libdwfl/fts_.h
  1167. @@ -0,0 +1,131 @@
  1168. +/*
  1169. + * Copyright (c) 1989, 1993
  1170. + * The Regents of the University of California. All rights reserved.
  1171. + *
  1172. + * Redistribution and use in source and binary forms, with or without
  1173. + * modification, are permitted provided that the following conditions
  1174. + * are met:
  1175. + * 1. Redistributions of source code must retain the above copyright
  1176. + * notice, this list of conditions and the following disclaimer.
  1177. + * 2. Redistributions in binary form must reproduce the above copyright
  1178. + * notice, this list of conditions and the following disclaimer in the
  1179. + * documentation and/or other materials provided with the distribution.
  1180. + * 4. Neither the name of the University nor the names of its contributors
  1181. + * may be used to endorse or promote products derived from this software
  1182. + * without specific prior written permission.
  1183. + *
  1184. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1185. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1186. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1187. + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1188. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1189. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1190. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1191. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1192. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1193. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1194. + * SUCH DAMAGE.
  1195. + *
  1196. + * @(#)fts.h 8.3 (Berkeley) 8/14/94
  1197. + */
  1198. +
  1199. +#ifndef _FTS_H
  1200. +#define _FTS_H 1
  1201. +
  1202. +#include <features.h>
  1203. +#include <sys/types.h>
  1204. +
  1205. +/* The fts interface is incompatible with the LFS interface which
  1206. + transparently uses the 64-bit file access functions. */
  1207. +#ifdef __USE_FILE_OFFSET64
  1208. +# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
  1209. +#endif
  1210. +
  1211. +
  1212. +typedef struct {
  1213. + struct _ftsent *fts_cur; /* current node */
  1214. + struct _ftsent *fts_child; /* linked list of children */
  1215. + struct _ftsent **fts_array; /* sort array */
  1216. + dev_t fts_dev; /* starting device # */
  1217. + char *fts_path; /* path for this descent */
  1218. + int fts_rfd; /* fd for root */
  1219. + int fts_pathlen; /* sizeof(path) */
  1220. + int fts_nitems; /* elements in the sort array */
  1221. + int (*fts_compar) (const void *, const void *); /* compare fn */
  1222. +
  1223. +#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
  1224. +#define FTS_LOGICAL 0x0002 /* logical walk */
  1225. +#define FTS_NOCHDIR 0x0004 /* don't change directories */
  1226. +#define FTS_NOSTAT 0x0008 /* don't get stat info */
  1227. +#define FTS_PHYSICAL 0x0010 /* physical walk */
  1228. +#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */
  1229. +#define FTS_XDEV 0x0040 /* don't cross devices */
  1230. +#define FTS_WHITEOUT 0x0080 /* return whiteout information */
  1231. +#define FTS_OPTIONMASK 0x00ff /* valid user option mask */
  1232. +
  1233. +#define FTS_NAMEONLY 0x0100 /* (private) child names only */
  1234. +#define FTS_STOP 0x0200 /* (private) unrecoverable error */
  1235. + int fts_options; /* fts_open options, global flags */
  1236. +} FTS;
  1237. +
  1238. +typedef struct _ftsent {
  1239. + struct _ftsent *fts_cycle; /* cycle node */
  1240. + struct _ftsent *fts_parent; /* parent directory */
  1241. + struct _ftsent *fts_link; /* next file in directory */
  1242. + long fts_number; /* local numeric value */
  1243. + void *fts_pointer; /* local address value */
  1244. + char *fts_accpath; /* access path */
  1245. + char *fts_path; /* root path */
  1246. + int fts_errno; /* errno for this node */
  1247. + int fts_symfd; /* fd for symlink */
  1248. + u_short fts_pathlen; /* strlen(fts_path) */
  1249. + u_short fts_namelen; /* strlen(fts_name) */
  1250. +
  1251. + ino_t fts_ino; /* inode */
  1252. + dev_t fts_dev; /* device */
  1253. + nlink_t fts_nlink; /* link count */
  1254. +
  1255. +#define FTS_ROOTPARENTLEVEL -1
  1256. +#define FTS_ROOTLEVEL 0
  1257. + short fts_level; /* depth (-1 to N) */
  1258. +
  1259. +#define FTS_D 1 /* preorder directory */
  1260. +#define FTS_DC 2 /* directory that causes cycles */
  1261. +#define FTS_DEFAULT 3 /* none of the above */
  1262. +#define FTS_DNR 4 /* unreadable directory */
  1263. +#define FTS_DOT 5 /* dot or dot-dot */
  1264. +#define FTS_DP 6 /* postorder directory */
  1265. +#define FTS_ERR 7 /* error; errno is set */
  1266. +#define FTS_F 8 /* regular file */
  1267. +#define FTS_INIT 9 /* initialized only */
  1268. +#define FTS_NS 10 /* stat(2) failed */
  1269. +#define FTS_NSOK 11 /* no stat(2) requested */
  1270. +#define FTS_SL 12 /* symbolic link */
  1271. +#define FTS_SLNONE 13 /* symbolic link without target */
  1272. +#define FTS_W 14 /* whiteout object */
  1273. + u_short fts_info; /* user flags for FTSENT structure */
  1274. +
  1275. +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
  1276. +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
  1277. + u_short fts_flags; /* private flags for FTSENT structure */
  1278. +
  1279. +#define FTS_AGAIN 1 /* read node again */
  1280. +#define FTS_FOLLOW 2 /* follow symbolic link */
  1281. +#define FTS_NOINSTR 3 /* no instructions */
  1282. +#define FTS_SKIP 4 /* discard node */
  1283. + u_short fts_instr; /* fts_set() instructions */
  1284. +
  1285. + struct stat *fts_statp; /* stat(2) information */
  1286. + char fts_name[1]; /* file name */
  1287. +} FTSENT;
  1288. +
  1289. +__BEGIN_DECLS
  1290. +FTSENT *fts_children (FTS *, int);
  1291. +int fts_close (FTS *);
  1292. +FTS *fts_open (char * const *, int,
  1293. + int (*)(const FTSENT **, const FTSENT **));
  1294. +FTSENT *fts_read (FTS *);
  1295. +int fts_set (FTS *, FTSENT *, int) __THROW;
  1296. +__END_DECLS
  1297. +
  1298. +#endif /* fts.h */
  1299. diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
  1300. index 9d0fef2cf260..47f0e3892294 100644
  1301. --- a/libdwfl/linux-kernel-modules.c
  1302. +++ b/libdwfl/linux-kernel-modules.c
  1303. @@ -31,10 +31,14 @@
  1304. Everything we need here is fine if its declarations just come first.
  1305. Also, include sys/types.h before fts. On some systems fts.h is not self
  1306. contained. */
  1307. +#ifdef HAVE_FTS_H
  1308. #ifdef BAD_FTS
  1309. #include <sys/types.h>
  1310. #include <fts.h>
  1311. #endif
  1312. +#else
  1313. +#include <fts_.h>
  1314. +#endif
  1315. #include <config.h>
  1316. #include <system.h>
  1317. --
  1318. 2.11.0