Changeset 2985 for trunk/src/lib/nt/fts-nt.c
- Timestamp:
- Nov 1, 2016, 7:26:35 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib/nt/fts-nt.c
r2982 r2985 1 /* $Id: $ */ 2 /** @file 3 * Source for the NT port of BSD fts.c. 4 * 5 * @copyright 1990, 1993, 1994 The Regents of the University of California. All rights reserved. 6 * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net> 7 * @licenses BSD3 8 * 9 * 10 * Some hints about how the code works. 11 * 12 * The input directories & files are entered into a pseudo root directory and 13 * processed one after another, depth first. 14 * 15 * Directories are completely read into memory first and arranged as linked 16 * list anchored on FTS::fts_cur. fts_read does a pop-like operation on that 17 * list, freeing the nodes after they've been completely processed. 18 * Subdirectories are returned twice by fts_read, the first time when it 19 * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP). 20 * 21 * In parallel to fts_read, there's the fts_children API that fetches the 22 * directory content in a similar manner, but for the consumption of the API 23 * caller rather than FTS itself. The result hangs on FTS::fts_child so it can 24 * be freed when the directory changes or used by fts_read when it is called 25 * upon to enumerate the directory. 26 * 27 * 28 * The NT port of the code does away with the directory changing in favor of 29 * using directory relative opens (present in NT since for ever, just not 30 * exposed thru Win32). A new FTSENT member fts_dirfd has been added to make 31 * this possible for API users too. 32 * 33 * Note! When using Win32 APIs with path input relative to the current 34 * directory, the internal DOS <-> NT path converter will expand it to a 35 * full path and subject it to the 260 char limit. 36 * 37 * The richer NT directory enumeration API allows us to do away with all the 38 * stat() calls, and not have to do link counting and other interesting things 39 * to try speed things up. (You typical stat() implementation on windows is 40 * actually a directory enum call with the name of the file as filter.) 41 */ 42 1 43 /*- 2 44 * Copyright (c) 1990, 1993, 1994 … … 36 78 #endif 37 79 38 #include <sys/cdefs.h>39 __FBSDID("$FreeBSD$");40 41 #include "namespace.h"42 #include <sys/param.h>43 #include <sys/mount.h>44 #include <sys/stat.h>45 46 #include <dirent.h>80 //#include <sys/cdefs.h> 81 //__FBSDID("$FreeBSD$"); 82 83 //#include "namespace.h" 84 //#include <sys/param.h> 85 //#include <sys/mount.h> 86 //#include <sys/stat.h> 87 88 //#include <dirent.h> 47 89 #include <errno.h> 48 #include <fcntl.h>49 #include <fts.h>90 //#include <fcntl.h> 91 #include "fts-nt.h" 50 92 #include <stdlib.h> 51 93 #include <string.h> 52 #include <unistd.h> 53 #include "un-namespace.h" 54 55 #include "gen-private.h" 94 //#include <unistd.h> 95 //#include "un-namespace.h" 96 // 97 //#include "gen-private.h" 98 #include <assert.h> 99 #include "nthlp.h" 100 #include "ntdir.h" 56 101 57 102 static FTSENT *fts_alloc(FTS *, char *, size_t); … … 63 108 static int fts_palloc(FTS *, size_t); 64 109 static FTSENT *fts_sort(FTS *, FTSENT *, size_t); 65 static int fts_stat(FTS *, FTSENT *, int, int); 110 static int fts_stat(FTS *, FTSENT *, int, HANDLE); 111 static int fts_process_stats(FTSENT *, BirdStat_T const *); 66 112 static int fts_safe_changedir(FTS *, FTSENT *, int, char *); 67 113 static int fts_ufslinks(FTS *, const FTSENT *); … … 80 126 #define BREAD 3 /* fts_read */ 81 127 128 /* NT needs these: */ 129 #define MAXPATHLEN 260 130 #define MAX(a, b) ( (a) >= (b) ? (a) : (b) ) 131 132 #define AT_SYMLINK_NOFOLLOW 1 133 #define fstatat(hDir, pszPath, pStat, fFlags) birdStatAt((hDir), (pszPath), (pStat), (fFlags) != 0) 134 #define FTS_NT_DUMMY_SYMFD_VALUE ((HANDLE)~(intptr_t)(2)) /* current process */ 135 #define fchdir(fd) todo_fchdir(fd) 136 extern int todo_fchdir(fts_fd_t fd); 137 82 138 /* 83 139 * Internal representation of an FTS, including extra implementation … … 87 143 struct _fts_private { 88 144 FTS ftsp_fts; 145 #if 0 /* Not needed on NT, see comment on fts_ufslinks */ 89 146 struct statfs ftsp_statfs; 90 147 dev_t ftsp_dev; 91 148 int ftsp_linksreliable; 149 #endif 92 150 }; 93 151 152 #if 0 /* Not needed on NT, see comment on fts_ufslinks */ 94 153 /* 95 154 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it … … 108 167 0 109 168 }; 110 111 FTS * 169 #endif 170 171 FTS * FTSCALL 112 172 fts_open(char * const *argv, int options, 113 173 int (*compar)(const FTSENT * const *, const FTSENT * const *)) … … 159 219 /* Allocate/initialize root(s). */ 160 220 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { 221 /* NT: We need to do some small input transformations to make this and 222 the API user code happy. 1. Lone drive letters get a dot 223 appended so it won't matter if a slash is appended afterwards. 224 2. DOS slashes are converted to UNIX ones. */ 225 char *slash; 161 226 len = strlen(*argv); 162 163 p = fts_alloc(sp, *argv, len); 227 if (len == 2 && argv[0][1] == ':') { 228 char tmp[4]; 229 tmp[0] = argv[0][0]; 230 tmp[1] = ':'; 231 tmp[2] = '.'; 232 tmp[3] = '\0'; 233 p = fts_alloc(sp, tmp, 3); 234 } else { 235 p = fts_alloc(sp, *argv, len); 236 } 237 #if 1 /* bird */ 238 if (p != NULL) { /* likely */ } else { goto mem3; } 239 #endif 240 slash = strchr(p->fts_name, '\\'); 241 while (slash != NULL) { 242 *slash++ = '/'; 243 slash = strchr(p->fts_name, '\\'); 244 } 164 245 p->fts_level = FTS_ROOTLEVEL; 165 246 p->fts_parent = parent; 166 247 p->fts_accpath = p->fts_name; 167 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);248 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE); 168 249 169 250 /* Command-line "." and ".." are real directories. */ … … 201 282 sp->fts_cur->fts_info = FTS_INIT; 202 283 203 /*204 * If using chdir(2), grab a file descriptor pointing to dot to ensure205 * that we can get back here; this could be avoided for some paths,206 * but almost certainly not worth the effort. Slashes, symbolic links,207 * and ".." are all fairly nasty problems. Note, if we can't get the208 * descriptor we run anyway, just more slowly.209 */210 if (!ISSET(FTS_NOCHDIR) &&211 (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)212 SET(FTS_NOCHDIR);213 214 284 return (sp); 215 285 … … 221 291 } 222 292 293 223 294 static void 224 295 fts_load(FTS *sp, FTSENT *p) … … 236 307 len = p->fts_pathlen = p->fts_namelen; 237 308 memmove(sp->fts_path, p->fts_name, len + 1); 309 /** @todo check for ':' and '\\'? */ 238 310 if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { 239 311 len = strlen(++cp); … … 245 317 } 246 318 247 int 319 int FTSCALL 248 320 fts_close(FTS *sp) 249 321 { 250 322 FTSENT *freep, *p; 251 int saved_errno;323 /*int saved_errno;*/ 252 324 253 325 /* … … 272 344 free(sp->fts_path); 273 345 274 /* Return to original directory, save errno if necessary. */275 if (!ISSET(FTS_NOCHDIR)) {276 saved_errno = fchdir(sp->fts_rfd) ? errno : 0;277 (void)_close(sp->fts_rfd);278 279 /* Set errno and return. */280 if (saved_errno != 0) {281 /* Free up the stream pointer. */282 free(sp);283 errno = saved_errno;284 return (-1);285 }286 }287 288 346 /* Free up the stream pointer. */ 289 347 free(sp); … … 299 357 ? p->fts_pathlen - 1 : p->fts_pathlen) 300 358 301 FTSENT * 359 static void 360 fts_free_entry(FTSENT *tmp) 361 { 362 if (tmp != NULL) { 363 if (tmp->fts_dirfd != INVALID_HANDLE_VALUE) { 364 birdCloseFile(tmp->fts_dirfd); 365 tmp->fts_dirfd = INVALID_HANDLE_VALUE; 366 } 367 free(tmp); 368 } 369 } 370 371 FTSENT * FTSCALL 302 372 fts_read(FTS *sp) 303 373 { … … 305 375 int instr; 306 376 char *t; 307 int saved_errno;308 377 309 378 /* If finished or unrecoverable error, return NULL. */ … … 320 389 /* Any type of file may be re-visited; re-stat and re-turn. */ 321 390 if (instr == FTS_AGAIN) { 322 p->fts_info = fts_stat(sp, p, 0, -1);391 p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE); 323 392 return (p); 324 393 } … … 329 398 * keep a pointer to current location. If unable to get that 330 399 * pointer, follow fails. 400 * 401 * NT: Since we don't change directory, we just set fts_symfd to a 402 * placeholder value handle value here in case a API client 403 * checks it. Ditto FTS_SYMFOLLOW. 331 404 */ 332 405 if (instr == FTS_FOLLOW && 333 406 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { 334 p->fts_info = fts_stat(sp, p, 1, -1); 335 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 336 if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, 337 0)) < 0) { 338 p->fts_errno = errno; 339 p->fts_info = FTS_ERR; 340 } else 341 p->fts_flags |= FTS_SYMFOLLOW; 407 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); 408 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { 409 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE; 410 p->fts_flags |= FTS_SYMFOLLOW; 342 411 } 343 412 return (p); … … 349 418 if (instr == FTS_SKIP || 350 419 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 351 if (p->fts_flags & FTS_SYMFOLLOW) 352 (void)_close(p->fts_symfd); 420 if (p->fts_flags & FTS_SYMFOLLOW) { 421 p->fts_symfd = INVALID_HANDLE_VALUE; 422 } 353 423 if (sp->fts_child) { 354 424 fts_lfree(sp->fts_child); … … 405 475 */ 406 476 if (p->fts_level == FTS_ROOTLEVEL) { 407 if (FCHDIR(sp, sp->fts_rfd)) {477 /*NT: No fchdir: if (FCHDIR(sp, sp->fts_rfd)) { 408 478 SET(FTS_STOP); 409 479 return (NULL); 410 } 411 f ree(tmp);480 } */ 481 fts_free_entry(tmp); 412 482 fts_load(sp, p); 413 483 return (sp->fts_cur = p); … … 420 490 */ 421 491 if (p->fts_instr == FTS_SKIP) { 422 f ree(tmp);492 fts_free_entry(tmp); 423 493 goto next; 424 494 } 425 495 if (p->fts_instr == FTS_FOLLOW) { 426 p->fts_info = fts_stat(sp, p, 1, -1); 427 if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { 428 if ((p->fts_symfd = 429 _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { 430 p->fts_errno = errno; 431 p->fts_info = FTS_ERR; 432 } else 433 p->fts_flags |= FTS_SYMFOLLOW; 496 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); 497 /* NT: See above regarding fts_symfd. */ 498 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { 499 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE; 500 p->fts_flags |= FTS_SYMFOLLOW; 434 501 } 435 502 p->fts_instr = FTS_NOINSTR; 436 503 } 437 504 438 f ree(tmp);505 fts_free_entry(tmp); 439 506 440 507 name: t = sp->fts_path + NAPPEND(p->fts_parent); … … 452 519 * can distinguish between error and EOF. 453 520 */ 454 f ree(tmp);455 f ree(p);521 fts_free_entry(tmp); 522 fts_free_entry(p); 456 523 errno = 0; 457 524 return (sp->fts_cur = NULL); … … 465 532 * a symlink, go back through the file descriptor. Otherwise, cd up 466 533 * one directory. 467 */ 468 if (p->fts_level == FTS_ROOTLEVEL) { 469 if (FCHDIR(sp, sp->fts_rfd)) { 470 SET(FTS_STOP); 471 return (NULL); 472 } 473 } else if (p->fts_flags & FTS_SYMFOLLOW) { 474 if (FCHDIR(sp, p->fts_symfd)) { 475 saved_errno = errno; 476 (void)_close(p->fts_symfd); 477 errno = saved_errno; 478 SET(FTS_STOP); 479 return (NULL); 480 } 481 (void)_close(p->fts_symfd); 482 } else if (!(p->fts_flags & FTS_DONTCHDIR) && 483 fts_safe_changedir(sp, p->fts_parent, -1, "..")) { 484 SET(FTS_STOP); 485 return (NULL); 486 } 487 free(tmp); 534 * 535 * NT: We're doing no fchdir, but we need to close the directory handle 536 * and clear fts_symfd now. 537 */ 538 if (p->fts_flags & FTS_SYMFOLLOW) { 539 p->fts_symfd = INVALID_HANDLE_VALUE; 540 } 541 if (p->fts_dirfd != INVALID_HANDLE_VALUE) { 542 birdCloseFile(p->fts_dirfd); 543 p->fts_dirfd = INVALID_HANDLE_VALUE; 544 } 545 fts_free_entry(tmp); 488 546 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 489 547 return (sp->fts_cur = p); … … 497 555 */ 498 556 /* ARGSUSED */ 499 int 557 int FTSCALL 500 558 fts_set(FTS *sp, FTSENT *p, int instr) 501 559 { … … 509 567 } 510 568 511 FTSENT * 569 #if 0 570 FTSENT * FTSCALL 512 571 fts_children(FTS *sp, int instr) 513 572 { … … 579 638 return (sp->fts_child); 580 639 } 640 #endif /* PORTME */ 581 641 582 642 #ifndef fts_get_clientptr … … 585 645 586 646 void * 587 ( fts_get_clientptr)(FTS *sp)647 (FTSCALL fts_get_clientptr)(FTS *sp) 588 648 { 589 649 … … 596 656 597 657 FTS * 598 ( fts_get_stream)(FTSENT *p)658 (FTSCALL fts_get_stream)(FTSENT *p) 599 659 { 600 660 return (fts_get_stream(p)); 601 661 } 602 662 603 void 663 void FTSCALL 604 664 fts_set_clientptr(FTS *sp, void *clientptr) 605 665 { … … 621 681 * directories and for any files after the subdirectories in the directory have 622 682 * been found, cutting the stat calls by about 2/3. 683 * 684 * NT: We do not do any link counting or stat avoiding, which invalidates the 685 * above warnings. This function is very simple for us. 623 686 */ 624 687 static FTSENT * 625 688 fts_build(FTS *sp, int type) 626 689 { 627 struct dirent*dp;690 BirdDirEntry_T *dp; 628 691 FTSENT *p, *head; 629 692 FTSENT *cur, *tail; … … 631 694 void *oldaddr; 632 695 char *cp; 633 int cderrno, descend, oflag, saved_errno, nostat, doadjust;696 int saved_errno, doadjust; 634 697 long level; 635 long nlinks; /* has to be signed because -1 is a magic value */636 698 size_t dnamlen, len, maxlen, nitems; 699 unsigned fDirOpenFlags; 637 700 638 701 /* Set current node pointer. */ … … 642 705 * Open the directory for reading. If this fails, we're done. 643 706 * If being called from fts_read, set the fts_info field. 644 */ 645 #ifdef FTS_WHITEOUT 646 if (ISSET(FTS_WHITEOUT)) 647 oflag = DTF_NODUP | DTF_REWIND; 648 else 649 oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND; 650 #else 651 #define __opendir2(path, flag) opendir(path) 652 #endif 653 if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { 707 * 708 * NT: We do a two stage open so we can keep the directory handle around 709 * after we've enumerated the directory. The dir handle is used by 710 * us here and by the API users to more efficiently and safely open 711 * members of the directory. 712 */ 713 fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE; 714 if (cur->fts_dirfd == INVALID_HANDLE_VALUE) { 715 if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) { 716 /* (This works fine for symlinks too, since we follow them.) */ 717 cur->fts_dirfd = birdOpenFileEx(cur->fts_parent->fts_dirfd, 718 cur->fts_name, 719 FILE_READ_DATA | SYNCHRONIZE, 720 FILE_ATTRIBUTE_NORMAL, 721 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 722 FILE_OPEN, 723 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 724 OBJ_CASE_INSENSITIVE); 725 } else { 726 cur->fts_dirfd = birdOpenFile(cur->fts_accpath, 727 FILE_READ_DATA | SYNCHRONIZE, 728 FILE_ATTRIBUTE_NORMAL, 729 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 730 FILE_OPEN, 731 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 732 OBJ_CASE_INSENSITIVE); 733 } 734 } else { 735 fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN; 736 } 737 dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags); 738 if (dirp == NULL) { 654 739 if (type == BREAD) { 655 740 cur->fts_info = FTS_DNR; … … 658 743 return (NULL); 659 744 } 660 661 /*662 * Nlinks is the number of possible entries of type directory in the663 * directory if we're cheating on stat calls, 0 if we're not doing664 * any stat calls at all, -1 if we're doing stats on everything.665 */666 if (type == BNAMES) {667 nlinks = 0;668 /* Be quiet about nostat, GCC. */669 nostat = 0;670 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {671 if (fts_ufslinks(sp, cur))672 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);673 else674 nlinks = -1;675 nostat = 1;676 } else {677 nlinks = -1;678 nostat = 0;679 }680 681 #ifdef notdef682 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);683 (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",684 ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));685 #endif686 /*687 * If we're going to need to stat anything or we want to descend688 * and stay in the directory, chdir. If this fails we keep going,689 * but set a flag so we don't chdir after the post-order visit.690 * We won't be able to stat anything, but we can still return the691 * names themselves. Note, that since fts_read won't be able to692 * chdir into the directory, it will have to return different path693 * names than before, i.e. "a/b" instead of "b". Since the node694 * has already been visited in pre-order, have to wait until the695 * post-order visit to return the error. There is a special case696 * here, if there was nothing to stat then it's not an error to697 * not be able to stat. This is all fairly nasty. If a program698 * needed sorted entries or stat information, they had better be699 * checking FTS_NS on the returned nodes.700 */701 cderrno = 0;702 if (nlinks || type == BREAD) {703 if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {704 if (nlinks && type == BREAD)705 cur->fts_errno = errno;706 cur->fts_flags |= FTS_DONTCHDIR;707 descend = 0;708 cderrno = errno;709 } else710 descend = 1;711 } else712 descend = 0;713 745 714 746 /* … … 723 755 */ 724 756 len = NAPPEND(cur); 725 if (ISSET(FTS_NOCHDIR)) { 726 cp = sp->fts_path + len; 727 *cp++ = '/'; 728 } else { 729 /* GCC, you're too verbose. */ 730 cp = NULL; 731 } 757 cp = sp->fts_path + len; 758 *cp++ = '/'; 732 759 len++; 733 760 maxlen = sp->fts_pathlen - len; … … 737 764 /* Read the directory, attaching each entry to the `link' pointer. */ 738 765 doadjust = 0; 739 for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {766 for (head = tail = NULL, nitems = 0; dirp && (dp = birdDirRead(dirp));) { 740 767 dnamlen = dp->d_namlen; 741 768 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) … … 756 783 free(p); 757 784 fts_lfree(head); 758 (void)closedir(dirp); 785 birdDirClose(dirp); 786 birdCloseFile(cur->fts_dirfd); 787 cur->fts_dirfd = INVALID_HANDLE_VALUE; 759 788 cur->fts_info = FTS_ERR; 760 789 SET(FTS_STOP); … … 774 803 p->fts_parent = sp->fts_cur; 775 804 p->fts_pathlen = len + dnamlen; 776 777 #ifdef FTS_WHITEOUT 778 if (dp->d_type == DT_WHT) 779 p->fts_flags |= FTS_ISW; 780 #endif 781 782 if (cderrno) { 783 if (nlinks) { 784 p->fts_info = FTS_NS; 785 p->fts_errno = cderrno; 786 } else 787 p->fts_info = FTS_NSOK; 788 p->fts_accpath = cur->fts_accpath; 789 } else if (nlinks == 0 790 #ifdef DT_DIR 791 || (nostat && 792 dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) 793 #endif 794 ) { 795 p->fts_accpath = 796 ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; 797 p->fts_info = FTS_NSOK; 798 } else { 799 /* Build a file name for fts_stat to stat. */ 800 if (ISSET(FTS_NOCHDIR)) { 801 p->fts_accpath = p->fts_path; 802 memmove(cp, p->fts_name, p->fts_namelen + 1); 803 p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp)); 804 } else { 805 p->fts_accpath = p->fts_name; 806 p->fts_info = fts_stat(sp, p, 0, -1); 807 } 808 809 /* Decrement link count if applicable. */ 810 if (nlinks > 0 && (p->fts_info == FTS_D || 811 p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) 812 --nlinks; 813 } 805 p->fts_accpath = p->fts_path; 806 p->fts_stat = dp->d_stat; 807 p->fts_info = fts_process_stats(p, &dp->d_stat); 814 808 815 809 /* We walk in directory order so "ls -f" doesn't get upset. */ … … 823 817 ++nitems; 824 818 } 825 if (dirp) 826 (void)closedir(dirp);819 820 birdDirClose(dirp); 827 821 828 822 /* … … 834 828 835 829 /* 836 * If not changing directories, reset the path back to original 837 * state. 838 */ 839 if (ISSET(FTS_NOCHDIR)) 840 sp->fts_path[cur->fts_pathlen] = '\0'; 841 842 /* 843 * If descended after called from fts_children or after called from 844 * fts_read and nothing found, get back. At the root level we use 845 * the saved fd; if one of fts_open()'s arguments is a relative path 846 * to an empty directory, we wind up here with no other way back. If 847 * can't get back, we're done. 848 */ 849 if (descend && (type == BCHILD || !nitems) && 850 (cur->fts_level == FTS_ROOTLEVEL ? 851 FCHDIR(sp, sp->fts_rfd) : 852 fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { 853 cur->fts_info = FTS_ERR; 854 SET(FTS_STOP); 855 return (NULL); 856 } 830 * Reset the path back to original state. 831 */ 832 sp->fts_path[cur->fts_pathlen] = '\0'; 857 833 858 834 /* If didn't find anything, return NULL. */ … … 869 845 } 870 846 847 848 /** 849 * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs 850 * following. On link information is generally retrieved during directory 851 * enumeration on NT, in line with it's DOS/OS2/FAT API heritage. 852 */ 871 853 static int 872 fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) 873 { 874 FTSENT *t; 875 dev_t dev; 876 ino_t ino; 877 struct stat *sbp, sb; 854 fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd) 855 { 878 856 int saved_errno; 879 857 const char *path; 880 858 881 if (dfd == -1)882 path = p->fts_accpath , dfd = AT_FDCWD;883 else859 if (dfd == INVALID_HANDLE_VALUE) { 860 path = p->fts_accpath; 861 } else { 884 862 path = p->fts_name; 885 886 /* If user needs stat info, stat buffer already allocated. */ 887 sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; 888 889 #ifdef FTS_WHITEOUT 890 /* Check for whiteout. */ 891 if (p->fts_flags & FTS_ISW) { 892 if (sbp != &sb) { 893 memset(sbp, '\0', sizeof(*sbp)); 894 sbp->st_mode = S_IFWHT; 895 } 896 return (FTS_W); 897 } 898 #endif 863 } 899 864 900 865 /* … … 904 869 */ 905 870 if (ISSET(FTS_LOGICAL) || follow) { 906 if (fstatat(dfd, path, sbp, 0)) {871 if (fstatat(dfd, path, &p->fts_stat, 0)) { 907 872 saved_errno = errno; 908 if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {873 if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) { 909 874 p->fts_errno = saved_errno; 910 875 goto err; 911 876 } 912 877 errno = 0; 913 if (S_ISLNK( sbp->st_mode))878 if (S_ISLNK(p->fts_stat.st_mode)) 914 879 return (FTS_SLNONE); 915 880 } 916 } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {881 } else if (fstatat(dfd, path, &p->fts_stat, AT_SYMLINK_NOFOLLOW)) { 917 882 p->fts_errno = errno; 918 err: memset( sbp, 0, sizeof(struct stat));883 err: memset(&p->fts_stat, 0, sizeof(struct stat)); 919 884 return (FTS_NS); 920 885 } 921 886 return fts_process_stats(p, &p->fts_stat); 887 } 888 889 /* Shared between fts_stat and fts_build. */ 890 static int 891 fts_process_stats(FTSENT *p, BirdStat_T const *sbp) 892 { 922 893 if (S_ISDIR(sbp->st_mode)) { 894 FTSENT *t; 895 fts_dev_t dev; 896 fts_ino_t ino; 897 923 898 /* 924 899 * Set the device/inode. Used to find cycles and check for … … 984 959 */ 985 960 if (nitems > sp->fts_nitems) { 961 void *ptr; 986 962 sp->fts_nitems = nitems + 40; 987 if ((sp->fts_array = reallocf(sp->fts_array, 988 sp->fts_nitems * sizeof(FTSENT *))) == NULL) { 963 ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *)); 964 if (ptr != NULL) { 965 sp->fts_array = ptr; 966 } else { 967 free(sp->fts_array); 968 sp->fts_array = NULL; 989 969 sp->fts_nitems = 0; 990 970 return (head); … … 1012 992 1013 993 /* 1014 * The file name is a variable length array and no stat structure is 1015 * necessary if the user has set the nostat bit. Allocate the FTSENT 1016 * structure, the file name and the stat structure in one chunk, but 1017 * be careful that the stat structure is reasonably aligned. 1018 */ 1019 if (ISSET(FTS_NOSTAT)) 1020 len = sizeof(FTSENT) + namelen + 1; 1021 else 1022 len = sizeof(struct ftsent_withstat) + namelen + 1; 1023 994 * The file name is a variable length array. Allocate the FTSENT 995 * structure and the file name. 996 */ 997 len = sizeof(FTSENT) + namelen + 1; 1024 998 if ((p = malloc(len)) == NULL) 1025 999 return (NULL); 1026 1000 1027 if (ISSET(FTS_NOSTAT)) { 1028 p->fts_name = (char *)(p + 1); 1029 p->fts_statp = NULL; 1030 } else { 1031 p->fts_name = (char *)((struct ftsent_withstat *)p + 1); 1032 p->fts_statp = &((struct ftsent_withstat *)p)->statbuf; 1033 } 1001 p->fts_name = (char *)(p + 1); 1002 p->fts_statp = &p->fts_stat; 1034 1003 1035 1004 /* Copy the name and guarantee NUL termination. */ … … 1044 1013 p->fts_pointer = NULL; 1045 1014 p->fts_fts = sp; 1015 p->fts_symfd = INVALID_HANDLE_VALUE; 1016 p->fts_dirfd = INVALID_HANDLE_VALUE; 1046 1017 return (p); 1047 1018 } … … 1055 1026 while ((p = head)) { 1056 1027 head = head->fts_link; 1028 assert(p->fts_dirfd == INVALID_HANDLE_VALUE); 1057 1029 free(p); 1058 1030 } … … 1068 1040 fts_palloc(FTS *sp, size_t more) 1069 1041 { 1042 void *ptr; 1070 1043 1071 1044 sp->fts_pathlen += more + 256; 1072 sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); 1073 return (sp->fts_path == NULL); 1045 ptr = realloc(sp->fts_path, sp->fts_pathlen); 1046 if (ptr) { 1047 /*likely */ 1048 } else { 1049 free(sp->fts_path); 1050 } 1051 sp->fts_path = ptr; 1052 return (ptr == NULL); 1074 1053 } 1075 1054 … … 1121 1100 fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) 1122 1101 { 1102 #if 0 1123 1103 int ret, oerrno, newfd; 1124 1104 struct stat sb; 1125 1105 1126 1106 newfd = fd; 1107 #endif 1127 1108 if (ISSET(FTS_NOCHDIR)) 1128 1109 return (0); 1110 assert(0); 1111 return -1; 1112 #if 0 1129 1113 if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | 1130 1114 O_CLOEXEC, 0)) < 0) … … 1146 1130 errno = oerrno; 1147 1131 return (ret); 1132 #endif 1148 1133 } 1149 1134 1150 1135 /* 1151 1136 * Check if the filesystem for "ent" has UFS-style links. 1137 * 1138 * bird: NT does not, which is why they need this check. 1139 * See comment on r129052 (2004-05-08 15:09:02Z). 1152 1140 */ 1153 1141 static int 1154 1142 fts_ufslinks(FTS *sp, const FTSENT *ent) 1155 1143 { 1144 #if 0 1156 1145 struct _fts_private *priv; 1157 1146 const char **cpp; … … 1180 1169 } 1181 1170 return (priv->ftsp_linksreliable); 1182 } 1171 #else 1172 (void)sp; (void)ent; 1173 return 0; 1174 #endif 1175 } 1176
Note:
See TracChangeset
for help on using the changeset viewer.