tree.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /*-
  2. * Copyright 2006-2008 Colin Percival
  3. * All rights reserved.
  4. *
  5. * Portions of the file below are covered by the following license:
  6. *
  7. * Copyright (c) 2003-2007 Tim Kientzle
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /*-
  31. * This is a new directory-walking system that addresses a number
  32. * of problems I've had with fts(3). In particular, it has no
  33. * pathname-length limits (other than the size of 'int'), handles
  34. * deep logical traversals, uses considerably less memory, and has
  35. * an opaque interface (easier to modify in the future).
  36. *
  37. * Internally, it keeps a single list of "tree_entry" items that
  38. * represent filesystem objects that require further attention.
  39. * Non-directories are not kept in memory: they are pulled from
  40. * readdir(), returned to the client, then freed as soon as possible.
  41. * Any directory entry to be traversed gets pushed onto the stack.
  42. *
  43. * There is surprisingly little information that needs to be kept for
  44. * each item on the stack. Just the name, depth (represented here as the
  45. * string length of the parent directory's pathname), and some markers
  46. * indicating how to get back to the parent (via chdir("..") for a
  47. * regular dir or via fchdir(2) for a symlink).
  48. */
  49. #include "bsdtar_platform.h"
  50. __FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.9 2008/11/27 05:49:52 kientzle Exp $");
  51. #ifdef HAVE_SYS_STAT_H
  52. #include <sys/stat.h>
  53. #endif
  54. #ifdef HAVE_DIRENT_H
  55. #include <dirent.h>
  56. #endif
  57. #ifdef HAVE_ERRNO_H
  58. #include <errno.h>
  59. #endif
  60. #ifdef HAVE_FCNTL_H
  61. #include <fcntl.h>
  62. #endif
  63. #ifdef HAVE_LIMITS_H
  64. #include <limits.h>
  65. #endif
  66. #ifdef HAVE_STDLIB_H
  67. #include <stdlib.h>
  68. #endif
  69. #ifdef HAVE_STRING_H
  70. #include <string.h>
  71. #endif
  72. #ifdef HAVE_UNISTD_H
  73. #include <unistd.h>
  74. #endif
  75. #include "tree.h"
  76. /*
  77. * TODO:
  78. * 1) Loop checking.
  79. * 3) Arbitrary logical traversals by closing/reopening intermediate fds.
  80. */
  81. struct tree_entry {
  82. struct tree_entry *next;
  83. struct tree_entry *parent;
  84. char *name;
  85. size_t dirname_length;
  86. dev_t dev;
  87. ino_t ino;
  88. #ifdef HAVE_FCHDIR
  89. int fd;
  90. #elif defined(_WIN32) && !defined(__CYGWIN__)
  91. char *fullpath;
  92. #else
  93. #error fchdir function required.
  94. #endif
  95. int flags;
  96. };
  97. /* Definitions for tree_entry.flags bitmap. */
  98. #define isDir 1 /* This entry is a regular directory. */
  99. #define isDirLink 2 /* This entry is a symbolic link to a directory. */
  100. #define needsPreVisit 4 /* This entry needs to be previsited. */
  101. #define needsPostVisit 8 /* This entry needs to be postvisited. */
  102. /*
  103. * Local data for this package.
  104. */
  105. struct tree {
  106. struct tree_entry *stack;
  107. struct tree_entry *current;
  108. DIR *d;
  109. #ifdef HAVE_FCHDIR
  110. int initialDirFd;
  111. #elif defined(_WIN32) && !defined(__CYGWIN__)
  112. char *initialDir;
  113. #endif
  114. int flags;
  115. int visit_type;
  116. int tree_errno; /* Error code from last failed operation. */
  117. char *buff;
  118. const char *basename;
  119. size_t buff_length;
  120. size_t path_length;
  121. size_t dirname_length;
  122. char realpath[PATH_MAX + 1];
  123. size_t realpath_dirname_length;
  124. int realpath_valid;
  125. char realpath_symlink[PATH_MAX + 1];
  126. int depth;
  127. int openCount;
  128. int maxOpenCount;
  129. struct stat lst;
  130. struct stat st;
  131. };
  132. /* Definitions for tree.flags bitmap. */
  133. #define needsReturn 8 /* Marks first entry as not having been returned yet. */
  134. #define hasStat 16 /* The st entry is set. */
  135. #define hasLstat 32 /* The lst entry is set. */
  136. #ifdef HAVE_DIRENT_D_NAMLEN
  137. /* BSD extension; avoids need for a strlen() call. */
  138. #define D_NAMELEN(dp) (dp)->d_namlen
  139. #else
  140. #define D_NAMELEN(dp) (strlen((dp)->d_name))
  141. #endif
  142. static void
  143. errmsg(const char *m)
  144. {
  145. size_t s = strlen(m);
  146. ssize_t written;
  147. while (s > 0) {
  148. written = write(2, m, strlen(m));
  149. if (written <= 0)
  150. return;
  151. m += written;
  152. s -= written;
  153. }
  154. }
  155. #if 0
  156. #include <stdio.h>
  157. void
  158. tree_dump(struct tree *t, FILE *out)
  159. {
  160. struct tree_entry *te;
  161. fprintf(out, "\tdepth: %d\n", t->depth);
  162. fprintf(out, "\tbuff: %s\n", t->buff);
  163. fprintf(out, "\tpwd: "); fflush(stdout); system("pwd");
  164. fprintf(out, "\taccess: %s\n", t->basename);
  165. fprintf(out, "\tstack:\n");
  166. for (te = t->stack; te != NULL; te = te->next) {
  167. fprintf(out, "\t\tte->name: %s%s%s\n", te->name,
  168. te->flags & needsPreVisit ? "" : " *",
  169. t->current == te ? " (current)" : "");
  170. }
  171. }
  172. #endif
  173. /*
  174. * Add a directory path to the current stack.
  175. */
  176. static void
  177. tree_push(struct tree *t, const char *path)
  178. {
  179. struct tree_entry *te;
  180. te = malloc(sizeof(*te));
  181. if (te == NULL)
  182. abort();
  183. memset(te, 0, sizeof(*te));
  184. te->next = t->stack;
  185. t->stack = te;
  186. #ifdef HAVE_FCHDIR
  187. te->fd = -1;
  188. #elif defined(_WIN32) && !defined(__CYGWIN__)
  189. te->fullpath = NULL;
  190. #endif
  191. te->name = strdup(path);
  192. te->flags = needsPreVisit | needsPostVisit;
  193. te->dirname_length = t->dirname_length;
  194. }
  195. /*
  196. * Append a name to the current path.
  197. */
  198. static void
  199. tree_append(struct tree *t, const char *name, size_t name_length)
  200. {
  201. char *p;
  202. size_t size_needed;
  203. if (t->buff != NULL)
  204. t->buff[t->dirname_length] = '\0';
  205. /* Strip trailing '/' from name, unless entire name is "/". */
  206. while (name_length > 1 && name[name_length - 1] == '/')
  207. name_length--;
  208. /* Resize pathname buffer as needed. */
  209. size_needed = name_length + 1 + t->dirname_length + 1;
  210. if (t->buff_length < size_needed) {
  211. if (t->buff_length < 1024)
  212. t->buff_length = 1024;
  213. while (t->buff_length < size_needed)
  214. t->buff_length *= 2;
  215. t->buff = realloc(t->buff, t->buff_length);
  216. }
  217. if (t->buff == NULL)
  218. abort();
  219. p = t->buff + t->dirname_length;
  220. t->path_length = t->dirname_length + name_length;
  221. /* Add a separating '/' if it's needed. */
  222. if (t->dirname_length > 0 && p[-1] != '/') {
  223. *p++ = '/';
  224. t->path_length ++;
  225. }
  226. strncpy(p, name, name_length);
  227. p[name_length] = '\0';
  228. t->basename = p;
  229. /* Adjust canonical name. */
  230. if ((t->realpath_valid) &&
  231. (t->realpath_dirname_length + name_length + 1 <= PATH_MAX)) {
  232. t->realpath[t->realpath_dirname_length] = '/';
  233. memcpy(t->realpath + t->realpath_dirname_length + 1,
  234. name, name_length);
  235. t->realpath[t->realpath_dirname_length + name_length + 1] = 0;
  236. } else {
  237. t->realpath_valid = 0;
  238. }
  239. }
  240. /*
  241. * Open a directory tree for traversal.
  242. */
  243. struct tree *
  244. tree_open(const char *path)
  245. {
  246. struct tree *t;
  247. t = malloc(sizeof(*t));
  248. if (t == NULL)
  249. abort();
  250. memset(t, 0, sizeof(*t));
  251. tree_append(t, path, strlen(path));
  252. #ifdef HAVE_FCHDIR
  253. t->initialDirFd = open(".", O_RDONLY);
  254. #elif defined(_WIN32) && !defined(__CYGWIN__)
  255. t->initialDir = getcwd(NULL, 0);
  256. #endif
  257. /*
  258. * During most of the traversal, items are set up and then
  259. * returned immediately from tree_next(). That doesn't work
  260. * for the very first entry, so we set a flag for this special
  261. * case.
  262. */
  263. t->flags = needsReturn;
  264. return (t);
  265. }
  266. /*
  267. * We've finished a directory; ascend back to the parent.
  268. */
  269. static int
  270. tree_ascend(struct tree *t)
  271. {
  272. struct tree_entry *te;
  273. int r = 0;
  274. te = t->stack;
  275. t->depth--;
  276. if (te->flags & isDirLink) {
  277. #ifdef HAVE_FCHDIR
  278. if (fchdir(te->fd) != 0) {
  279. t->tree_errno = errno;
  280. r = TREE_ERROR_FATAL;
  281. }
  282. close(te->fd);
  283. #elif defined(_WIN32) && !defined(__CYGWIN__)
  284. if (chdir(te->fullpath) != 0) {
  285. t->tree_errno = errno;
  286. r = TREE_ERROR_FATAL;
  287. }
  288. free(te->fullpath);
  289. te->fullpath = NULL;
  290. #endif
  291. t->openCount--;
  292. } else {
  293. if (chdir("..") != 0) {
  294. t->tree_errno = errno;
  295. r = TREE_ERROR_FATAL;
  296. }
  297. }
  298. /* Figure out where we are. */
  299. if (getcwd(t->realpath, PATH_MAX) != NULL) {
  300. t->realpath_dirname_length = strlen(t->realpath);
  301. if (t->realpath[0] == '/' && t->realpath[1] == '\0')
  302. t->realpath_dirname_length = 0;
  303. t->realpath_valid = 1;
  304. } else {
  305. t->realpath_valid = 0;
  306. }
  307. return (r);
  308. }
  309. /*
  310. * Pop the working stack.
  311. */
  312. static void
  313. tree_pop(struct tree *t)
  314. {
  315. struct tree_entry *te;
  316. t->buff[t->dirname_length] = '\0';
  317. if (t->stack == t->current && t->current != NULL)
  318. t->current = t->current->parent;
  319. te = t->stack;
  320. t->stack = te->next;
  321. t->dirname_length = te->dirname_length;
  322. t->basename = t->buff + t->dirname_length;
  323. /* Special case: starting dir doesn't skip leading '/'. */
  324. if (t->dirname_length > 0)
  325. t->basename++;
  326. free(te->name);
  327. free(te);
  328. }
  329. /*
  330. * Get the next item in the tree traversal.
  331. */
  332. int
  333. tree_next(struct tree *t)
  334. {
  335. struct dirent *de = NULL;
  336. int r;
  337. /* If we're called again after a fatal error, that's an API
  338. * violation. Just crash now. */
  339. if (t->visit_type == TREE_ERROR_FATAL) {
  340. const char *msg = "Unable to continue traversing"
  341. " directory hierarchy after a fatal error.\n";
  342. errmsg(msg);
  343. *(volatile int *)0 = 1; /* Deliberate SEGV; NULL pointer dereference. */
  344. exit(1); /* In case the SEGV didn't work. */
  345. }
  346. /* Handle the startup case by returning the initial entry. */
  347. if (t->flags & needsReturn) {
  348. t->flags &= ~needsReturn;
  349. return (t->visit_type = TREE_REGULAR);
  350. }
  351. while (t->stack != NULL) {
  352. /* If there's an open dir, get the next entry from there. */
  353. while (t->d != NULL) {
  354. errno = 0;
  355. de = readdir(t->d);
  356. if (de == NULL) {
  357. if (errno) {
  358. /* If readdir fails, we're screwed. */
  359. t->tree_errno = errno;
  360. closedir(t->d);
  361. t->d = NULL;
  362. t->visit_type = TREE_ERROR_FATAL;
  363. return (t->visit_type);
  364. }
  365. /* Reached end of directory. */
  366. closedir(t->d);
  367. t->d = NULL;
  368. } else if (de->d_name[0] == '.'
  369. && de->d_name[1] == '\0') {
  370. /* Skip '.' */
  371. } else if (de->d_name[0] == '.'
  372. && de->d_name[1] == '.'
  373. && de->d_name[2] == '\0') {
  374. /* Skip '..' */
  375. } else {
  376. /*
  377. * Append the path to the current path
  378. * and return it.
  379. */
  380. tree_append(t, de->d_name, D_NAMELEN(de));
  381. t->flags &= ~hasLstat;
  382. t->flags &= ~hasStat;
  383. return (t->visit_type = TREE_REGULAR);
  384. }
  385. }
  386. /* If the current dir needs to be visited, set it up. */
  387. if (t->stack->flags & needsPreVisit) {
  388. t->current = t->stack;
  389. tree_append(t, t->stack->name, strlen(t->stack->name));
  390. t->stack->flags &= ~needsPreVisit;
  391. /* If it is a link, set up fd for the ascent. */
  392. if (t->stack->flags & isDirLink) {
  393. #ifdef HAVE_FCHDIR
  394. t->stack->fd = open(".", O_RDONLY);
  395. #elif defined(_WIN32) && !defined(__CYGWIN__)
  396. t->stack->fullpath = getcwd(NULL, 0);
  397. #endif
  398. t->openCount++;
  399. if (t->openCount > t->maxOpenCount)
  400. t->maxOpenCount = t->openCount;
  401. }
  402. t->dirname_length = t->path_length;
  403. if (chdir(t->stack->name) != 0) {
  404. /* chdir() failed; return error */
  405. t->tree_errno = errno;
  406. tree_pop(t);
  407. return (t->visit_type = TREE_ERROR_DIR);
  408. }
  409. t->depth++;
  410. t->d = opendir(".");
  411. if (t->d == NULL) {
  412. t->tree_errno = errno;
  413. r = tree_ascend(t); /* Undo "chdir" */
  414. tree_pop(t);
  415. t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
  416. return (t->visit_type);
  417. }
  418. t->flags &= ~hasLstat;
  419. t->flags &= ~hasStat;
  420. t->basename = ".";
  421. /* Figure out where we are. */
  422. if (getcwd(t->realpath, PATH_MAX) != NULL) {
  423. t->realpath_dirname_length =
  424. strlen(t->realpath);
  425. if (t->realpath[0] == '/' &&
  426. t->realpath[1] == '\0')
  427. t->realpath_dirname_length = 0;
  428. t->realpath_valid = 1;
  429. } else {
  430. t->realpath_valid = 0;
  431. }
  432. return (t->visit_type = TREE_POSTDESCENT);
  433. }
  434. /* We've done everything necessary for the top stack entry. */
  435. if (t->stack->flags & needsPostVisit) {
  436. r = tree_ascend(t);
  437. tree_pop(t);
  438. t->flags &= ~hasLstat;
  439. t->flags &= ~hasStat;
  440. t->visit_type = r != 0 ? r : TREE_POSTASCENT;
  441. return (t->visit_type);
  442. }
  443. }
  444. return (t->visit_type = 0);
  445. }
  446. /*
  447. * Return error code.
  448. */
  449. int
  450. tree_errno(struct tree *t)
  451. {
  452. return (t->tree_errno);
  453. }
  454. /*
  455. * Called by the client to mark the directory just returned from
  456. * tree_next() as needing to be visited.
  457. */
  458. void
  459. tree_descend(struct tree *t)
  460. {
  461. if (t->visit_type != TREE_REGULAR)
  462. return;
  463. if (tree_current_is_physical_dir(t)) {
  464. tree_push(t, t->basename);
  465. t->stack->flags |= isDir;
  466. } else if (tree_current_is_dir(t)) {
  467. tree_push(t, t->basename);
  468. t->stack->flags |= isDirLink;
  469. }
  470. }
  471. /*
  472. * Get the stat() data for the entry just returned from tree_next().
  473. */
  474. const struct stat *
  475. tree_current_stat(struct tree *t)
  476. {
  477. if (!(t->flags & hasStat)) {
  478. if (stat(t->basename, &t->st) != 0)
  479. return NULL;
  480. t->flags |= hasStat;
  481. }
  482. return (&t->st);
  483. }
  484. /*
  485. * Get the lstat() data for the entry just returned from tree_next().
  486. */
  487. const struct stat *
  488. tree_current_lstat(struct tree *t)
  489. {
  490. if (!(t->flags & hasLstat)) {
  491. if (lstat(t->basename, &t->lst) != 0)
  492. return NULL;
  493. t->flags |= hasLstat;
  494. }
  495. return (&t->lst);
  496. }
  497. /*
  498. * Test whether current entry is a dir or link to a dir.
  499. */
  500. int
  501. tree_current_is_dir(struct tree *t)
  502. {
  503. const struct stat *st;
  504. /*
  505. * If we already have lstat() info, then try some
  506. * cheap tests to determine if this is a dir.
  507. */
  508. if (t->flags & hasLstat) {
  509. /* If lstat() says it's a dir, it must be a dir. */
  510. if (S_ISDIR(tree_current_lstat(t)->st_mode))
  511. return 1;
  512. /* Not a dir; might be a link to a dir. */
  513. /* If it's not a link, then it's not a link to a dir. */
  514. if (!S_ISLNK(tree_current_lstat(t)->st_mode))
  515. return 0;
  516. /*
  517. * It's a link, but we don't know what it's a link to,
  518. * so we'll have to use stat().
  519. */
  520. }
  521. st = tree_current_stat(t);
  522. /* If we can't stat it, it's not a dir. */
  523. if (st == NULL)
  524. return 0;
  525. /* Use the definitive test. Hopefully this is cached. */
  526. return (S_ISDIR(st->st_mode));
  527. }
  528. /*
  529. * Test whether current entry is a physical directory. Usually, we
  530. * already have at least one of stat() or lstat() in memory, so we
  531. * use tricks to try to avoid an extra trip to the disk.
  532. */
  533. int
  534. tree_current_is_physical_dir(struct tree *t)
  535. {
  536. const struct stat *st;
  537. /*
  538. * If stat() says it isn't a dir, then it's not a dir.
  539. * If stat() data is cached, this check is free, so do it first.
  540. */
  541. if ((t->flags & hasStat)
  542. && (!S_ISDIR(tree_current_stat(t)->st_mode)))
  543. return 0;
  544. /*
  545. * Either stat() said it was a dir (in which case, we have
  546. * to determine whether it's really a link to a dir) or
  547. * stat() info wasn't available. So we use lstat(), which
  548. * hopefully is already cached.
  549. */
  550. st = tree_current_lstat(t);
  551. /* If we can't stat it, it's not a dir. */
  552. if (st == NULL)
  553. return 0;
  554. /* Use the definitive test. Hopefully this is cached. */
  555. return (S_ISDIR(st->st_mode));
  556. }
  557. /*
  558. * Test whether current entry is a symbolic link.
  559. */
  560. int
  561. tree_current_is_physical_link(struct tree *t)
  562. {
  563. const struct stat *st = tree_current_lstat(t);
  564. if (st == NULL)
  565. return 0;
  566. return (S_ISLNK(st->st_mode));
  567. }
  568. /*
  569. * Return the access path for the entry just returned from tree_next().
  570. */
  571. const char *
  572. tree_current_access_path(struct tree *t)
  573. {
  574. return (t->basename);
  575. }
  576. /*
  577. * Return the full path for the entry just returned from tree_next().
  578. */
  579. const char *
  580. tree_current_path(struct tree *t)
  581. {
  582. return (t->buff);
  583. }
  584. /*
  585. * Return what you would get by calling realpath(3) on the path returned
  586. * by tree_current_access_path(t). In most cases this avoids needing to
  587. * call realpath(3).
  588. */
  589. const char *
  590. tree_current_realpath(struct tree *t)
  591. {
  592. if (tree_current_is_physical_link(t))
  593. return (realpath(t->basename, t->realpath_symlink));
  594. else if (t->realpath_valid)
  595. return (t->realpath);
  596. else
  597. return (realpath(t->basename, t->realpath));
  598. }
  599. /*
  600. * Return the length of the path for the entry just returned from tree_next().
  601. */
  602. size_t
  603. tree_current_pathlen(struct tree *t)
  604. {
  605. return (t->path_length);
  606. }
  607. /*
  608. * Return the nesting depth of the entry just returned from tree_next().
  609. */
  610. int
  611. tree_current_depth(struct tree *t)
  612. {
  613. return (t->depth);
  614. }
  615. /*
  616. * Terminate the traversal and release any resources.
  617. */
  618. int
  619. tree_close(struct tree *t)
  620. {
  621. int rc = 0;
  622. /* Release anything remaining in the stack. */
  623. while (t->stack != NULL)
  624. tree_pop(t);
  625. if (t->buff)
  626. free(t->buff);
  627. /* chdir() back to where we started. */
  628. #ifdef HAVE_FCHDIR
  629. if (t->initialDirFd >= 0) {
  630. rc = fchdir(t->initialDirFd);
  631. close(t->initialDirFd);
  632. t->initialDirFd = -1;
  633. }
  634. #elif defined(_WIN32) && !defined(__CYGWIN__)
  635. if (t->initialDir != NULL) {
  636. rc = chdir(t->initialDir);
  637. free(t->initialDir);
  638. t->initialDir = NULL;
  639. }
  640. #endif
  641. free(t);
  642. return (rc);
  643. }