ftw.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. /* File tree walker functions.
  2. Copyright (C) 1996-2003, 2004 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, write to the Free
  15. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  16. 02111-1307 USA. */
  17. #ifdef HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #define _GNU_SOURCE
  21. #define _XOPEN_SOURCE 500
  22. #include <features.h>
  23. #ifdef __UCLIBC__
  24. #undef _LIBC
  25. #define HAVE_DIRENT_H 1
  26. #define HAVE_SYS_PARAM_H 1
  27. #define HAVE_DECL_STPCPY 1
  28. #define HAVE_MEMPCPY 1
  29. #endif
  30. #if __GNUC__
  31. # define alloca __builtin_alloca
  32. #else
  33. # if HAVE_ALLOCA_H
  34. # include <alloca.h>
  35. # else
  36. # ifdef _AIX
  37. # pragma alloca
  38. # else
  39. char *alloca ();
  40. # endif
  41. # endif
  42. #endif
  43. #if defined _LIBC
  44. # include <dirent.h>
  45. # define NAMLEN(dirent) _D_EXACT_NAMLEN (dirent)
  46. #else
  47. # if HAVE_DIRENT_H
  48. # include <dirent.h>
  49. # define NAMLEN(dirent) strlen ((dirent)->d_name)
  50. # else
  51. # define dirent direct
  52. # define NAMLEN(dirent) (dirent)->d_namlen
  53. # if HAVE_SYS_NDIR_H
  54. # include <sys/ndir.h>
  55. # endif
  56. # if HAVE_SYS_DIR_H
  57. # include <sys/dir.h>
  58. # endif
  59. # if HAVE_NDIR_H
  60. # include <ndir.h>
  61. # endif
  62. # endif
  63. #endif
  64. #include <errno.h>
  65. #include <ftw.h>
  66. #include <limits.h>
  67. #include <search.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <unistd.h>
  71. #if HAVE_SYS_PARAM_H || defined _LIBC
  72. # include <sys/param.h>
  73. #endif
  74. #ifdef _LIBC
  75. # include <include/sys/stat.h>
  76. #else
  77. # include <sys/stat.h>
  78. #endif
  79. libc_hidden_proto(memset)
  80. libc_hidden_proto(strchr)
  81. libc_hidden_proto(strlen)
  82. libc_hidden_proto(dirfd)
  83. libc_hidden_proto(tsearch)
  84. libc_hidden_proto(tfind)
  85. libc_hidden_proto(tdestroy)
  86. libc_hidden_proto(getcwd)
  87. libc_hidden_proto(chdir)
  88. libc_hidden_proto(fchdir)
  89. libc_hidden_proto(mempcpy)
  90. libc_hidden_proto(opendir)
  91. #ifdef __UCLIBC_HAS_LFS__
  92. libc_hidden_proto(readdir64)
  93. libc_hidden_proto(lstat64)
  94. libc_hidden_proto(stat64)
  95. #endif
  96. libc_hidden_proto(closedir)
  97. libc_hidden_proto(stpcpy)
  98. libc_hidden_proto(lstat)
  99. libc_hidden_proto(stat)
  100. #if ! _LIBC && !HAVE_DECL_STPCPY && !defined stpcpy
  101. char *stpcpy ();
  102. #endif
  103. #if ! _LIBC && ! defined HAVE_MEMPCPY && ! defined mempcpy
  104. /* Be CAREFUL that there are no side effects in N. */
  105. # define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
  106. #endif
  107. /* #define NDEBUG 1 */
  108. #include <assert.h>
  109. #if !defined _LIBC
  110. # undef __chdir
  111. # define __chdir chdir
  112. # undef __closedir
  113. # define __closedir closedir
  114. # undef __fchdir
  115. # define __fchdir fchdir
  116. # undef __getcwd
  117. # ifndef __UCLIBC__
  118. # define __getcwd(P, N) xgetcwd ()
  119. extern char *xgetcwd (void);
  120. # else
  121. # define __getcwd getcwd
  122. # endif
  123. # undef __mempcpy
  124. # define __mempcpy mempcpy
  125. # undef __opendir
  126. # define __opendir opendir
  127. # undef __readdir64
  128. # ifndef __UCLIBC_HAS_LFS__
  129. # define __readdir64 readdir
  130. # else
  131. # define __readdir64 readdir64
  132. # endif
  133. # undef __stpcpy
  134. # define __stpcpy stpcpy
  135. # undef __tdestroy
  136. # define __tdestroy tdestroy
  137. # undef __tfind
  138. # define __tfind tfind
  139. # undef __tsearch
  140. # define __tsearch tsearch
  141. # undef internal_function
  142. # define internal_function /* empty */
  143. # ifndef __UCLIBC_HAS_LFS__
  144. # undef dirent64
  145. # define dirent64 dirent
  146. # endif
  147. # undef MAX
  148. # define MAX(a, b) ((a) > (b) ? (a) : (b))
  149. #endif
  150. /* Arrange to make lstat calls go through the wrapper function
  151. on systems with an lstat function that does not dereference symlinks
  152. that are specified with a trailing slash. */
  153. #if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK && !defined __UCLIBC__
  154. int rpl_lstat (const char *, struct stat *);
  155. # undef lstat
  156. # define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
  157. #endif
  158. #ifndef __set_errno
  159. # define __set_errno(Val) errno = (Val)
  160. #endif
  161. /* Support for the LFS API version. */
  162. #ifndef FTW_NAME
  163. # define FTW_NAME ftw
  164. # define NFTW_NAME nftw
  165. # define NFTW_OLD_NAME __old_nftw
  166. # define NFTW_NEW_NAME __new_nftw
  167. # define INO_T ino_t
  168. # define STAT stat
  169. # ifdef _LIBC
  170. # define LXSTAT __lxstat
  171. # define XSTAT __xstat
  172. # else
  173. # define LXSTAT(V,f,sb) lstat (f,sb)
  174. # define XSTAT(V,f,sb) stat (f,sb)
  175. # endif
  176. # define FTW_FUNC_T __ftw_func_t
  177. # define NFTW_FUNC_T __nftw_func_t
  178. #endif
  179. /* We define PATH_MAX if the system does not provide a definition.
  180. This does not artificially limit any operation. PATH_MAX is simply
  181. used as a guesstimate for the expected maximal path length.
  182. Buffers will be enlarged if necessary. */
  183. #ifndef PATH_MAX
  184. # define PATH_MAX 1024
  185. #endif
  186. struct dir_data
  187. {
  188. DIR *stream;
  189. char *content;
  190. };
  191. struct known_object
  192. {
  193. dev_t dev;
  194. INO_T ino;
  195. };
  196. struct ftw_data
  197. {
  198. /* Array with pointers to open directory streams. */
  199. struct dir_data **dirstreams;
  200. size_t actdir;
  201. size_t maxdir;
  202. /* Buffer containing name of currently processed object. */
  203. char *dirbuf;
  204. size_t dirbufsize;
  205. /* Passed as fourth argument to `nftw' callback. The `base' member
  206. tracks the content of the `dirbuf'. */
  207. struct FTW ftw;
  208. /* Flags passed to `nftw' function. 0 for `ftw'. */
  209. int flags;
  210. /* Conversion array for flag values. It is the identity mapping for
  211. `nftw' calls, otherwise it maps the values to those known by
  212. `ftw'. */
  213. const int *cvt_arr;
  214. /* Callback function. We always use the `nftw' form. */
  215. NFTW_FUNC_T func;
  216. /* Device of starting point. Needed for FTW_MOUNT. */
  217. dev_t dev;
  218. /* Data structure for keeping fingerprints of already processed
  219. object. This is needed when not using FTW_PHYS. */
  220. void *known_objects;
  221. };
  222. /* Internally we use the FTW_* constants used for `nftw'. When invoked
  223. as `ftw', map each flag to the subset of values used by `ftw'. */
  224. static const int nftw_arr[] =
  225. {
  226. FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
  227. };
  228. static const int ftw_arr[] =
  229. {
  230. FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
  231. };
  232. /* Forward declarations of local functions. */
  233. static int ftw_dir (struct ftw_data *data, struct STAT *st,
  234. struct dir_data *old_dir) internal_function;
  235. static int
  236. object_compare (const void *p1, const void *p2)
  237. {
  238. /* We don't need a sophisticated and useful comparison. We are only
  239. interested in equality. However, we must be careful not to
  240. accidentally compare `holes' in the structure. */
  241. const struct known_object *kp1 = p1, *kp2 = p2;
  242. int cmp1;
  243. cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
  244. if (cmp1 != 0)
  245. return cmp1;
  246. return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
  247. }
  248. static inline int
  249. add_object (struct ftw_data *data, struct STAT *st)
  250. {
  251. struct known_object *newp = malloc (sizeof (struct known_object));
  252. if (newp == NULL)
  253. return -1;
  254. newp->dev = st->st_dev;
  255. newp->ino = st->st_ino;
  256. return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
  257. }
  258. static inline int
  259. find_object (struct ftw_data *data, struct STAT *st)
  260. {
  261. struct known_object obj;
  262. obj.dev = st->st_dev;
  263. obj.ino = st->st_ino;
  264. return __tfind (&obj, &data->known_objects, object_compare) != NULL;
  265. }
  266. static inline int
  267. __attribute ((always_inline))
  268. open_dir_stream (struct ftw_data *data, struct dir_data *dirp)
  269. {
  270. int result = 0;
  271. if (data->dirstreams[data->actdir] != NULL)
  272. {
  273. /* Oh, oh. We must close this stream. Get all remaining
  274. entries and store them as a list in the `content' member of
  275. the `struct dir_data' variable. */
  276. size_t bufsize = 1024;
  277. char *buf = malloc (bufsize);
  278. if (buf == NULL)
  279. result = -1;
  280. else
  281. {
  282. DIR *st = data->dirstreams[data->actdir]->stream;
  283. struct dirent64 *d;
  284. size_t actsize = 0;
  285. while ((d = __readdir64 (st)) != NULL)
  286. {
  287. size_t this_len = NAMLEN (d);
  288. if (actsize + this_len + 2 >= bufsize)
  289. {
  290. char *newp;
  291. bufsize += MAX (1024, 2 * this_len);
  292. newp = (char *) realloc (buf, bufsize);
  293. if (newp == NULL)
  294. {
  295. /* No more memory. */
  296. int save_err = errno;
  297. free (buf);
  298. __set_errno (save_err);
  299. result = -1;
  300. break;
  301. }
  302. buf = newp;
  303. }
  304. *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
  305. = '\0';
  306. actsize += this_len + 1;
  307. }
  308. /* Terminate the list with an additional NUL byte. */
  309. buf[actsize++] = '\0';
  310. /* Shrink the buffer to what we actually need. */
  311. data->dirstreams[data->actdir]->content = realloc (buf, actsize);
  312. if (data->dirstreams[data->actdir]->content == NULL)
  313. {
  314. int save_err = errno;
  315. free (buf);
  316. __set_errno (save_err);
  317. result = -1;
  318. }
  319. else
  320. {
  321. __closedir (st);
  322. data->dirstreams[data->actdir]->stream = NULL;
  323. data->dirstreams[data->actdir] = NULL;
  324. }
  325. }
  326. }
  327. /* Open the new stream. */
  328. if (result == 0)
  329. {
  330. const char *name = ((data->flags & FTW_CHDIR)
  331. ? data->dirbuf + data->ftw.base: data->dirbuf);
  332. assert (data->dirstreams[data->actdir] == NULL);
  333. dirp->stream = __opendir (name);
  334. if (dirp->stream == NULL)
  335. result = -1;
  336. else
  337. {
  338. dirp->content = NULL;
  339. data->dirstreams[data->actdir] = dirp;
  340. if (++data->actdir == data->maxdir)
  341. data->actdir = 0;
  342. }
  343. }
  344. return result;
  345. }
  346. static int
  347. internal_function
  348. process_entry (struct ftw_data *data, struct dir_data *dir, const char *name,
  349. size_t namlen)
  350. {
  351. struct STAT st;
  352. int result = 0;
  353. int flag = 0;
  354. size_t new_buflen;
  355. if (name[0] == '.' && (name[1] == '\0'
  356. || (name[1] == '.' && name[2] == '\0')))
  357. /* Don't process the "." and ".." entries. */
  358. return 0;
  359. new_buflen = data->ftw.base + namlen + 2;
  360. if (data->dirbufsize < new_buflen)
  361. {
  362. /* Enlarge the buffer. */
  363. char *newp;
  364. data->dirbufsize = 2 * new_buflen;
  365. newp = (char *) realloc (data->dirbuf, data->dirbufsize);
  366. if (newp == NULL)
  367. return -1;
  368. data->dirbuf = newp;
  369. }
  370. *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';
  371. if ((data->flags & FTW_CHDIR) == 0)
  372. name = data->dirbuf;
  373. if (((data->flags & FTW_PHYS)
  374. ? LXSTAT (_STAT_VER, name, &st)
  375. : XSTAT (_STAT_VER, name, &st)) < 0)
  376. {
  377. if (errno != EACCES && errno != ENOENT)
  378. result = -1;
  379. else if (!(data->flags & FTW_PHYS)
  380. && LXSTAT (_STAT_VER, name, &st) == 0
  381. && S_ISLNK (st.st_mode))
  382. flag = FTW_SLN;
  383. else
  384. flag = FTW_NS;
  385. }
  386. else
  387. {
  388. if (S_ISDIR (st.st_mode))
  389. flag = FTW_D;
  390. else if (S_ISLNK (st.st_mode))
  391. flag = FTW_SL;
  392. else
  393. flag = FTW_F;
  394. }
  395. if (result == 0
  396. && (flag == FTW_NS
  397. || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
  398. {
  399. if (flag == FTW_D)
  400. {
  401. if ((data->flags & FTW_PHYS)
  402. || (!find_object (data, &st)
  403. /* Remember the object. */
  404. && (result = add_object (data, &st)) == 0))
  405. result = ftw_dir (data, &st, dir);
  406. }
  407. else
  408. result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
  409. &data->ftw);
  410. }
  411. if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
  412. result = 0;
  413. return result;
  414. }
  415. static int
  416. __attribute ((noinline))
  417. internal_function
  418. ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
  419. {
  420. struct dir_data dir;
  421. struct dirent64 *d;
  422. int previous_base = data->ftw.base;
  423. int result;
  424. char *startp;
  425. /* Open the stream for this directory. This might require that
  426. another stream has to be closed. */
  427. result = open_dir_stream (data, &dir);
  428. if (result != 0)
  429. {
  430. if (errno == EACCES)
  431. /* We cannot read the directory. Signal this with a special flag. */
  432. result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);
  433. return result;
  434. }
  435. /* First, report the directory (if not depth-first). */
  436. if (!(data->flags & FTW_DEPTH))
  437. {
  438. result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
  439. if (result != 0)
  440. {
  441. int save_err;
  442. fail:
  443. save_err = errno;
  444. __closedir (dir.stream);
  445. __set_errno (save_err);
  446. if (data->actdir-- == 0)
  447. data->actdir = data->maxdir - 1;
  448. data->dirstreams[data->actdir] = NULL;
  449. return result;
  450. }
  451. }
  452. /* If necessary, change to this directory. */
  453. if (data->flags & FTW_CHDIR)
  454. {
  455. if (__fchdir (dirfd (dir.stream)) < 0)
  456. {
  457. result = -1;
  458. goto fail;
  459. }
  460. }
  461. /* Next, update the `struct FTW' information. */
  462. ++data->ftw.level;
  463. startp = strchr (data->dirbuf, '\0');
  464. /* There always must be a directory name. */
  465. assert (startp != data->dirbuf);
  466. if (startp[-1] != '/')
  467. *startp++ = '/';
  468. data->ftw.base = startp - data->dirbuf;
  469. while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
  470. {
  471. result = process_entry (data, &dir, d->d_name, NAMLEN (d));
  472. if (result != 0)
  473. break;
  474. }
  475. if (dir.stream != NULL)
  476. {
  477. /* The stream is still open. I.e., we did not need more
  478. descriptors. Simply close the stream now. */
  479. int save_err = errno;
  480. assert (dir.content == NULL);
  481. __closedir (dir.stream);
  482. __set_errno (save_err);
  483. if (data->actdir-- == 0)
  484. data->actdir = data->maxdir - 1;
  485. data->dirstreams[data->actdir] = NULL;
  486. }
  487. else
  488. {
  489. int save_err;
  490. char *runp = dir.content;
  491. while (result == 0 && *runp != '\0')
  492. {
  493. char *endp = strchr (runp, '\0');
  494. result = process_entry (data, &dir, runp, endp - runp);
  495. runp = endp + 1;
  496. }
  497. save_err = errno;
  498. free (dir.content);
  499. __set_errno (save_err);
  500. }
  501. if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
  502. result = 0;
  503. /* Prepare the return, revert the `struct FTW' information. */
  504. data->dirbuf[data->ftw.base - 1] = '\0';
  505. --data->ftw.level;
  506. data->ftw.base = previous_base;
  507. /* Finally, if we process depth-first report the directory. */
  508. if (result == 0 && (data->flags & FTW_DEPTH))
  509. result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
  510. if (old_dir
  511. && (data->flags & FTW_CHDIR)
  512. && (result == 0
  513. || ((data->flags & FTW_ACTIONRETVAL)
  514. && (result != -1 && result != FTW_STOP))))
  515. {
  516. /* Change back to the parent directory. */
  517. int done = 0;
  518. if (old_dir->stream != NULL)
  519. if (__fchdir (dirfd (old_dir->stream)) == 0)
  520. done = 1;
  521. if (!done)
  522. {
  523. if (data->ftw.base == 1)
  524. {
  525. if (__chdir ("/") < 0)
  526. result = -1;
  527. }
  528. else
  529. if (__chdir ("..") < 0)
  530. result = -1;
  531. }
  532. }
  533. return result;
  534. }
  535. static int
  536. __attribute ((noinline))
  537. internal_function
  538. ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
  539. int flags)
  540. {
  541. struct ftw_data data;
  542. struct STAT st;
  543. int result = 0;
  544. int save_err;
  545. char *cwd = NULL;
  546. char *cp;
  547. /* First make sure the parameters are reasonable. */
  548. if (dir[0] == '\0')
  549. {
  550. __set_errno (ENOENT);
  551. return -1;
  552. }
  553. data.maxdir = descriptors < 1 ? 1 : descriptors;
  554. data.actdir = 0;
  555. data.dirstreams = (struct dir_data **) alloca (data.maxdir
  556. * sizeof (struct dir_data *));
  557. memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
  558. /* PATH_MAX is always defined when we get here. */
  559. data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
  560. data.dirbuf = (char *) malloc (data.dirbufsize);
  561. if (data.dirbuf == NULL)
  562. return -1;
  563. cp = __stpcpy (data.dirbuf, dir);
  564. /* Strip trailing slashes. */
  565. while (cp > data.dirbuf + 1 && cp[-1] == '/')
  566. --cp;
  567. *cp = '\0';
  568. data.ftw.level = 0;
  569. /* Find basename. */
  570. while (cp > data.dirbuf && cp[-1] != '/')
  571. --cp;
  572. data.ftw.base = cp - data.dirbuf;
  573. data.flags = flags;
  574. /* This assignment might seem to be strange but it is what we want.
  575. The trick is that the first three arguments to the `ftw' and
  576. `nftw' callback functions are equal. Therefore we can call in
  577. every case the callback using the format of the `nftw' version
  578. and get the correct result since the stack layout for a function
  579. call in C allows this. */
  580. data.func = (NFTW_FUNC_T) func;
  581. /* Since we internally use the complete set of FTW_* values we need
  582. to reduce the value range before calling a `ftw' callback. */
  583. data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
  584. /* No object known so far. */
  585. data.known_objects = NULL;
  586. /* Now go to the directory containing the initial file/directory. */
  587. if (flags & FTW_CHDIR)
  588. {
  589. /* GNU extension ahead. */
  590. cwd = __getcwd (NULL, 0);
  591. if (cwd == NULL)
  592. result = -1;
  593. else if (data.ftw.base > 0)
  594. {
  595. /* Change to the directory the file is in. In data.dirbuf
  596. we have a writable copy of the file name. Just NUL
  597. terminate it for now and change the directory. */
  598. if (data.ftw.base == 1)
  599. /* I.e., the file is in the root directory. */
  600. result = __chdir ("/");
  601. else
  602. {
  603. char ch = data.dirbuf[data.ftw.base - 1];
  604. data.dirbuf[data.ftw.base - 1] = '\0';
  605. result = __chdir (data.dirbuf);
  606. data.dirbuf[data.ftw.base - 1] = ch;
  607. }
  608. }
  609. }
  610. /* Get stat info for start directory. */
  611. if (result == 0)
  612. {
  613. const char *name = ((data.flags & FTW_CHDIR)
  614. ? data.dirbuf + data.ftw.base
  615. : data.dirbuf);
  616. if (((flags & FTW_PHYS)
  617. ? LXSTAT (_STAT_VER, name, &st)
  618. : XSTAT (_STAT_VER, name, &st)) < 0)
  619. {
  620. if (!(flags & FTW_PHYS)
  621. && errno == ENOENT
  622. && LXSTAT (_STAT_VER, name, &st) == 0
  623. && S_ISLNK (st.st_mode))
  624. result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN],
  625. &data.ftw);
  626. else
  627. /* No need to call the callback since we cannot say anything
  628. about the object. */
  629. result = -1;
  630. }
  631. else
  632. {
  633. if (S_ISDIR (st.st_mode))
  634. {
  635. /* Remember the device of the initial directory in case
  636. FTW_MOUNT is given. */
  637. data.dev = st.st_dev;
  638. /* We know this directory now. */
  639. if (!(flags & FTW_PHYS))
  640. result = add_object (&data, &st);
  641. if (result == 0)
  642. result = ftw_dir (&data, &st, NULL);
  643. }
  644. else
  645. {
  646. int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F;
  647. result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag],
  648. &data.ftw);
  649. }
  650. }
  651. if ((flags & FTW_ACTIONRETVAL)
  652. && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
  653. result = 0;
  654. }
  655. /* Return to the start directory (if necessary). */
  656. if (cwd != NULL)
  657. {
  658. int save_err = errno;
  659. __chdir (cwd);
  660. free (cwd);
  661. __set_errno (save_err);
  662. }
  663. /* Free all memory. */
  664. save_err = errno;
  665. __tdestroy (data.known_objects, free);
  666. free (data.dirbuf);
  667. __set_errno (save_err);
  668. return result;
  669. }
  670. /* Entry points. */
  671. int
  672. FTW_NAME (path, func, descriptors)
  673. const char *path;
  674. FTW_FUNC_T func;
  675. int descriptors;
  676. {
  677. return ftw_startup (path, 0, func, descriptors, 0);
  678. }
  679. #ifndef _LIBC
  680. int
  681. NFTW_NAME (path, func, descriptors, flags)
  682. const char *path;
  683. NFTW_FUNC_T func;
  684. int descriptors;
  685. int flags;
  686. {
  687. return ftw_startup (path, 1, func, descriptors, flags);
  688. }
  689. #else
  690. #include <shlib-compat.h>
  691. int NFTW_NEW_NAME (const char *, NFTW_FUNC_T, int, int);
  692. int
  693. NFTW_NEW_NAME (path, func, descriptors, flags)
  694. const char *path;
  695. NFTW_FUNC_T func;
  696. int descriptors;
  697. int flags;
  698. {
  699. if (flags
  700. & ~(FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH | FTW_ACTIONRETVAL))
  701. {
  702. __set_errno (EINVAL);
  703. return -1;
  704. }
  705. return ftw_startup (path, 1, func, descriptors, flags);
  706. }
  707. versioned_symbol (libc, NFTW_NEW_NAME, NFTW_NAME, GLIBC_2_3_3);
  708. #if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)
  709. /* Older nftw* version just ignored all unknown flags. */
  710. int NFTW_OLD_NAME (const char *, NFTW_FUNC_T, int, int);
  711. int
  712. attribute_compat_text_section
  713. NFTW_OLD_NAME (path, func, descriptors, flags)
  714. const char *path;
  715. NFTW_FUNC_T func;
  716. int descriptors;
  717. int flags;
  718. {
  719. flags &= (FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH);
  720. return ftw_startup (path, 1, func, descriptors, flags);
  721. }
  722. compat_symbol (libc, NFTW_OLD_NAME, NFTW_NAME, GLIBC_2_1);
  723. #endif
  724. #endif