Changeset 2985 for trunk/src/lib/nt
- Timestamp:
- Nov 1, 2016, 7:26:35 PM (9 years ago)
- Location:
- trunk/src/lib/nt
- Files:
-
- 12 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 -
trunk/src/lib/nt/fts-nt.h
r2983 r2985 1 /* $Id: $ */ 2 /** @file 3 * Header for the NT port of BSD fts.h. 4 * 5 * @copyright Copyright (c) 1989, 1993 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 1 10 /* 2 11 * Copyright (c) 1989, 1993 … … 29 38 * @(#)fts.h 8.3 (Berkeley) 8/14/94 30 39 * $FreeBSD$ 40 * 31 41 */ 32 42 33 #ifndef _FTS_H_34 #define _FTS_H_43 #ifndef INCLUDED_FTS_NT_H 44 #define INCLUDED_FTS_NT_H 35 45 36 #include <sys/_types.h> 46 #include <sys/types.h> 47 #include <stdint.h> 48 #include "ntstat.h" /* ensure correct stat structure */ 49 50 typedef uint64_t fts_dev_t; 51 typedef uint64_t fts_ino_t; 52 typedef uint32_t fts_nlink_t; 53 #ifdef _WINNT_ 54 typedef HANDLE fts_fd_t; 55 #else 56 typedef void * fts_fd_t; 57 #endif 58 #define FTSCALL __cdecl 37 59 38 60 typedef struct { … … 40 62 struct _ftsent *fts_child; /* linked list of children */ 41 63 struct _ftsent **fts_array; /* sort array */ 42 __dev_t fts_dev; /* starting device # */64 fts_dev_t fts_dev; /* starting device # */ 43 65 char *fts_path; /* path for this descent */ 44 int fts_rfd; /* fd for root */ 45 __size_t fts_pathlen; /* sizeof(path) */ 46 __size_t fts_nitems; /* elements in the sort array */ 47 int (*fts_compar) /* compare function */ 66 size_t fts_pathlen; /* sizeof(path) */ 67 size_t fts_nitems; /* elements in the sort array */ 68 int (FTSCALL *fts_compar) /* compare function */ 48 69 (const struct _ftsent * const *, const struct _ftsent * const *); 49 70 … … 55 76 #define FTS_SEEDOT 0x020 /* return dot and dot-dot */ 56 77 #define FTS_XDEV 0x040 /* don't cross devices */ 78 #if 0 /* No whiteout on NT. */ 57 79 #define FTS_WHITEOUT 0x080 /* return whiteout information */ 80 #endif 58 81 #define FTS_OPTIONMASK 0x0ff /* valid user option mask */ 59 82 … … 68 91 struct _ftsent *fts_parent; /* parent directory */ 69 92 struct _ftsent *fts_link; /* next file in directory */ 70 long longfts_number; /* local numeric value */93 int64_t fts_number; /* local numeric value */ 71 94 #define fts_bignum fts_number /* XXX non-std, should go away */ 72 95 void *fts_pointer; /* local address value */ … … 74 97 char *fts_path; /* root path */ 75 98 int fts_errno; /* errno for this node */ 76 int fts_symfd; /* fd for symlink */ 77 __size_t fts_pathlen; /* strlen(fts_path) */ 78 __size_t fts_namelen; /* strlen(fts_name) */ 99 fts_fd_t fts_symfd; /* NT: Normally -1; -2 we followed this symlinked dir */ 100 fts_fd_t fts_dirfd; /* NT: Handle to the directory */ 101 size_t fts_pathlen; /* strlen(fts_path) */ 102 size_t fts_namelen; /* strlen(fts_name) */ 79 103 80 __ino_t fts_ino; /* inode */81 __dev_t fts_dev; /* device */82 __nlink_t fts_nlink; /* link count */104 fts_ino_t fts_ino; /* inode */ 105 fts_dev_t fts_dev; /* device */ 106 fts_nlink_t fts_nlink; /* link count */ 83 107 84 108 #define FTS_ROOTPARENTLEVEL -1 … … 99 123 #define FTS_SL 12 /* symbolic link */ 100 124 #define FTS_SLNONE 13 /* symbolic link without target */ 101 #define FTS_W 14 /* whiteout object */125 //#define FTS_W 14 /* whiteout object */ 102 126 int fts_info; /* user status for FTSENT structure */ 103 127 … … 116 140 char *fts_name; /* file name */ 117 141 FTS *fts_fts; /* back pointer to main FTS */ 142 BirdStat_T fts_stat; /* NT: We always got stat info. */ 118 143 } FTSENT; 119 144 120 #include <sys/cdefs.h>121 145 122 __BEGIN_DECLS 123 FTSENT *fts_children(FTS *, int); 124 int fts_close(FTS *); 125 void *fts_get_clientptr(FTS *); 146 #ifdef __cplusplus 147 extern "C" { 148 #endif 149 FTSENT *FTSCALL fts_children(FTS *, int); 150 int FTSCALL fts_close(FTS *); 151 void *FTSCALL fts_get_clientptr(FTS *); 126 152 #define fts_get_clientptr(fts) ((fts)->fts_clientptr) 127 FTS * fts_get_stream(FTSENT *);153 FTS *FTSCALL fts_get_stream(FTSENT *); 128 154 #define fts_get_stream(ftsent) ((ftsent)->fts_fts) 129 FTS *fts_open(char * const *, int, 130 int (*)(const FTSENT * const *, const FTSENT * const *)); 131 FTSENT *fts_read(FTS *); 132 int fts_set(FTS *, FTSENT *, int); 133 void fts_set_clientptr(FTS *, void *); 134 __END_DECLS 155 FTS *FTSCALL fts_open(char * const *, int, 156 int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *)); 157 FTSENT *FTSCALL fts_read(FTS *); 158 int FTSCALL fts_set(FTS *, FTSENT *, int); 159 void FTSCALL fts_set_clientptr(FTS *, void *); 160 #ifdef __cplusplus 161 } 162 #endif 135 163 136 #endif /* !_FTS_H_ */ 164 #endif /* !INCLUDED_FTS_NT_H */ 165 -
trunk/src/lib/nt/kFsCache.c
r2969 r2985 2171 2171 HANDLE hDir; 2172 2172 MY_NTSTATUS rcNt; 2173 rcNt = birdOpenFileUniStr(&NtPath, 2173 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, 2174 &NtPath, 2174 2175 FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 2175 2176 FILE_ATTRIBUTE_NORMAL, -
trunk/src/lib/nt/ntdir.c
r2708 r2985 5 5 6 6 /* 7 * Copyright (c) 2005-201 3knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2005-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 9 9 * Permission is hereby granted, free of charge, to any person obtaining a … … 36 36 #include <errno.h> 37 37 #include <malloc.h> 38 #include <assert.h> 38 39 39 40 #include "ntstuff.h" … … 43 44 44 45 /** 46 * Implements opendir. 47 */ 48 BirdDir_T *birdDirOpen(const char *pszPath) 49 { 50 HANDLE hDir = birdOpenFile(pszPath, 51 FILE_READ_DATA | SYNCHRONIZE, 52 FILE_ATTRIBUTE_NORMAL, 53 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 54 FILE_OPEN, 55 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 56 OBJ_CASE_INSENSITIVE); 57 if (hDir != INVALID_HANDLE_VALUE) 58 { 59 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE); 60 if (pDir) 61 return pDir; 62 birdCloseFile(hDir); 63 } 64 return NULL; 65 } 66 67 68 /** 69 * Alternative opendir, with extra stat() info returned by readdir(). 70 */ 71 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath) 72 { 73 HANDLE hDir = birdOpenFile(pszPath, 74 FILE_READ_DATA | SYNCHRONIZE, 75 FILE_ATTRIBUTE_NORMAL, 76 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 77 FILE_OPEN, 78 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 79 OBJ_CASE_INSENSITIVE); 80 if (hDir != INVALID_HANDLE_VALUE) 81 { 82 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO); 83 if (pDir) 84 return pDir; 85 birdCloseFile(hDir); 86 } 87 return NULL; 88 } 89 90 91 BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags) 92 { 93 HANDLE hDir = birdOpenFileExW((HANDLE)hRoot, 94 pwszPath, 95 FILE_READ_DATA | SYNCHRONIZE, 96 FILE_ATTRIBUTE_NORMAL, 97 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 98 FILE_OPEN, 99 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 100 OBJ_CASE_INSENSITIVE); 101 if (hDir != INVALID_HANDLE_VALUE) 102 { 103 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE); 104 if (pDir) 105 return pDir; 106 birdCloseFile(hDir); 107 } 108 return NULL; 109 } 110 111 112 /** 45 113 * Internal worker for birdStatModTimeOnly. 46 114 */ 47 static BirdDir_T *birdDirOpenInternal(const char *pszPath, const char *pszFilter, int fMinimalInfo) 48 { 49 HANDLE hFile = birdOpenFile(pszPath, 50 FILE_READ_DATA | SYNCHRONIZE, 51 FILE_ATTRIBUTE_NORMAL, 52 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 53 FILE_OPEN, 54 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 55 OBJ_CASE_INSENSITIVE); 56 if (hFile != INVALID_HANDLE_VALUE) 115 BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags) 116 { 117 if (!pvReserved) 57 118 { 58 119 /* 59 * Allocate a handle.120 * Allocate and initialize the directory enum handle. 60 121 */ 61 122 BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir)); 62 123 if (pDir) 63 124 { 64 pDir->uMagic = BIRD_DIR_MAGIC; 65 pDir->pvHandle = (void *)hFile; 66 pDir->uDev = 0; 67 pDir->offPos = 0; 68 pDir->fHaveData = 0; 69 pDir->fFirst = 1; 70 pDir->iInfoClass = fMinimalInfo ? MyFileNamesInformation : MyFileIdFullDirectoryInformation; 71 pDir->offBuf = 0; 72 pDir->cbBuf = 0; 73 pDir->pabBuf = NULL; 125 pDir->uMagic = BIRD_DIR_MAGIC; 126 pDir->fFlags = fFlags; 127 pDir->pvHandle = pvHandle; 128 pDir->uDev = 0; 129 pDir->offPos = 0; 130 pDir->fHaveData = 0; 131 pDir->fFirst = 1; 132 pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; 133 pDir->offBuf = 0; 134 pDir->cbBuf = 0; 135 pDir->pabBuf = NULL; 74 136 return pDir; 75 137 } 76 77 birdCloseFile(hFile); 78 birdSetErrnoToNoMem(); 79 } 80 138 } 139 else 140 assert(pvReserved == NULL); 141 birdSetErrnoToNoMem(); 81 142 return NULL; 82 }83 84 85 /**86 * Implements opendir.87 */88 BirdDir_T *birdDirOpen(const char *pszPath)89 {90 return birdDirOpenInternal(pszPath, NULL, 1 /*fMinimalInfo*/);91 }92 93 94 /**95 * Alternative opendir, with extra stat() info returned by readdir().96 */97 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)98 {99 return birdDirOpenInternal(pszPath, NULL, 0 /*fMinimalInfo*/);100 143 } 101 144 … … 158 201 FALSE, /* fReturnSingleEntry */ 159 202 NULL, /* Filter / restart pos. */ 160 FALSE);/* fRestartScan */203 pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */ 161 204 if (!MY_NT_SUCCESS(rcNt)) 162 205 { … … 173 216 pDir->offBuf = 0; 174 217 pDir->fHaveData = 1; 218 pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN; 175 219 176 220 return 0; … … 355 399 356 400 pDir->uMagic++; 357 birdCloseFile((HANDLE)pDir->pvHandle); 401 if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) 402 birdCloseFile((HANDLE)pDir->pvHandle); 358 403 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE; 359 404 birdMemFree(pDir->pabBuf); -
trunk/src/lib/nt/ntdir.h
r2708 r2985 65 65 /** @} */ 66 66 67 /** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags 68 * @{ */ 69 /** birdDirClose should also close pvHandle. */ 70 #define BIRDDIR_F_CLOSE_HANDLE 1U 71 /** birdDirClose should not close the handle. */ 72 #define BIRDDIR_F_KEEP_HANDLE 0U 73 /** Provide extra info (stat). */ 74 #define BIRDDIR_F_EXTRA_INFO 2U 75 /** Whether to restart the scan. */ 76 #define BIRDDIR_F_RESTART_SCAN 4U 77 /** @} */ 78 67 79 typedef struct BirdDir 68 80 { 69 81 /** Magic value. */ 70 82 unsigned uMagic; 83 /** Flags. */ 84 unsigned fFlags; 71 85 /** The directory handle. */ 72 86 void *pvHandle; … … 98 112 BirdDir_T *birdDirOpen(const char *pszPath); 99 113 BirdDir_T *birdDirOpenExtraInfo(const char *pszPath); 114 BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags); 115 BirdDir_T *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags); 100 116 BirdDirEntry_T *birdDirRead(BirdDir_T *pDir); 101 117 long birdDirTell(BirdDir_T *pDir); -
trunk/src/lib/nt/nthlp.h
r2862 r2985 55 55 56 56 57 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, 58 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); 59 HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, 60 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 57 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 58 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); 59 HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 60 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); 61 HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 62 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); 63 HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 64 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); 65 HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 66 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 61 67 MY_UNICODE_STRING *pNameUniStr); 62 MY_NTSTATUS birdOpenFileUniStr(MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 68 HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 69 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 70 MY_UNICODE_STRING *pNameUniStr); 71 MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 63 72 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 64 73 HANDLE *phFile); 74 HANDLE birdOpenCurrentDirectory(void); 65 75 void birdCloseFile(HANDLE hFile); 66 76 int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); -
trunk/src/lib/nt/nthlpcore.c
r2913 r2985 46 46 PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); 47 47 MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); 48 MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, 49 MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); 48 50 MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, 49 51 MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, … … 63 65 UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch); 64 66 ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); 67 VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID); 68 VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID); 65 69 66 70 … … 74 78 { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" }, 75 79 { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" }, 80 { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" }, 76 81 { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" }, 77 82 { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" }, … … 87 92 { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" }, 88 93 { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" }, 94 { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" }, 95 { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" }, 89 96 }; 90 97 /** Set to 1 if we've successfully resolved the imports, otherwise 0. */ -
trunk/src/lib/nt/nthlpfs.c
r2713 r2985 34 34 *******************************************************************************/ 35 35 #include "nthlp.h" 36 #include <stddef.h> 37 #include <string.h> 38 #include <wchar.h> 39 #include <errno.h> 36 40 37 41 … … 61 65 62 66 67 static int birdHasTrailingSlashW(const wchar_t *pwszPath) 68 { 69 wchar_t wc, wc2; 70 71 /* Skip leading slashes. */ 72 while ((wc = *pwszPath) == '/' || wc == '\\') 73 pwszPath++; 74 if (wc == '\0') 75 return 0; 76 77 /* Find the last char. */ 78 while ((wc2 = *++pwszPath) != '\0') 79 wc = wc2; 80 81 return wc == '/' || wc == '\\' || wc == ':'; 82 } 83 84 63 85 static int birdIsPathDirSpec(const char *pszPath) 64 86 { … … 75 97 76 98 return ch == '/' || ch == '\\' || ch == ':'; 99 } 100 101 102 static int birdIsPathDirSpecW(const wchar_t *pwszPath) 103 { 104 wchar_t wc, wc2; 105 106 /* Check for empty string. */ 107 wc = *pwszPath; 108 if (wc == '\0') 109 return 0; 110 111 /* Find the last char. */ 112 while ((wc2 = *++pwszPath) != '\0') 113 wc = wc2; 114 115 return wc == '/' || wc == '\\' || wc == ':'; 77 116 } 78 117 … … 119 158 120 159 160 int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) 161 { 162 birdResolveImports(); 163 164 pNtPath->Length = pNtPath->MaximumLength = 0; 165 pNtPath->Buffer = NULL; 166 167 /* 168 * Convert the wide DOS path to an NT path. 169 */ 170 if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE)) 171 return 0; 172 return birdSetErrnoFromNt(STATUS_NO_MEMORY); 173 } 174 175 176 /** 177 * Converts UNIX slashes to DOS ones and trims trailing ones. 178 * 179 * @returns 0 180 * @param pNtPath The relative NT path to fix up. 181 */ 182 static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath) 183 { 184 size_t cwcLeft = pNtPath->Length / sizeof(wchar_t); 185 wchar_t *pwcStart = pNtPath->Buffer; 186 wchar_t *pwcHit; 187 188 /* Convert slashes. */ 189 while ((pwcHit = wmemchr(pwcStart, '/', cwcLeft)) != NULL) 190 { 191 *pwcHit = '\\'; 192 cwcLeft -= pwcHit - pwcStart; 193 pwcHit = pwcStart; 194 } 195 196 /* Strip trailing slashes (NT doesn't like them). */ 197 while ( pNtPath->Length >= sizeof(wchar_t) 198 && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\') 199 { 200 pNtPath->Length -= sizeof(wchar_t); 201 pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0'; 202 } 203 204 /* If it was all trailing slashes we convert it to a dot path. */ 205 if ( pNtPath->Length == 0 206 && pNtPath->MaximumLength >= sizeof(wchar_t) * 2) 207 { 208 pNtPath->Length = sizeof(wchar_t); 209 pNtPath->Buffer[0] = '.'; 210 pNtPath->Buffer[1] = '\0'; 211 } 212 213 return 0; 214 } 215 216 217 /** 218 * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U. 219 * 220 * @returns 0 on success, -1 + errno on failure. 221 * @param pszPath The relative path. 222 * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. 223 */ 224 int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) 225 { 226 MY_NTSTATUS rcNt; 227 MY_ANSI_STRING Src; 228 229 birdResolveImports(); 230 231 /* 232 * Just convert to wide char. 233 */ 234 pNtPath->Length = pNtPath->MaximumLength = 0; 235 pNtPath->Buffer = NULL; 236 237 Src.Buffer = (PCHAR)pszPath; 238 Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); 239 240 rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */); 241 if (MY_NT_SUCCESS(rcNt)) 242 return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); 243 return birdSetErrnoFromNt(rcNt); 244 } 245 246 247 /** 248 * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U. 249 * 250 * @returns 0 on success, -1 + errno on failure. 251 * @param pwszPath The relative path. 252 * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. 253 */ 254 int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) 255 { 256 size_t cwcPath = wcslen(pwszPath); 257 if (cwcPath < 0xfffe) 258 { 259 pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t)); 260 pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t); 261 pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength); 262 if (pNtPath->Buffer) 263 { 264 memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength); 265 return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); 266 } 267 errno = ENOMEM; 268 } 269 else 270 errno = ENAMETOOLONG; 271 return -1; 272 } 273 274 275 /** 276 * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or 277 * birdDosToRelativeNtPath. 278 * 279 * @param pNtPath The the NT path to free. 280 */ 121 281 void birdFreeNtPath(MY_UNICODE_STRING *pNtPath) 122 282 { … … 128 288 129 289 130 MY_NTSTATUS birdOpenFileUniStr( MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs,290 MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 131 291 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 132 292 HANDLE *phFile) … … 144 304 Ios.Information = -1; 145 305 Ios.u.Status = 0; 146 MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/);306 MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/); 147 307 148 308 rcNt = g_pfnNtCreateFile(phFile, … … 185 345 186 346 187 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,188 ULONG f CreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)347 HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 348 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) 189 349 { 190 350 MY_UNICODE_STRING NtPath; … … 198 358 199 359 /* 200 * C all the NT API directly.360 * Convert the path and call birdOpenFileUniStr to do the real work. 201 361 */ 202 362 if (birdDosToNtPath(pszPath, &NtPath) == 0) 203 363 { 204 364 HANDLE hFile; 205 rcNt = birdOpenFileUniStr( &NtPath, fDesiredAccess, fFileAttribs, fShareAccess,365 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 206 366 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 367 birdFreeNtPath(&NtPath); 368 if (MY_NT_SUCCESS(rcNt)) 369 return hFile; 370 birdSetErrnoFromNt(rcNt); 371 } 372 373 return INVALID_HANDLE_VALUE; 374 } 375 376 377 HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 378 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) 379 { 380 MY_UNICODE_STRING NtPath; 381 MY_NTSTATUS rcNt; 382 383 /* 384 * Adjust inputs. 385 */ 386 if (birdIsPathDirSpecW(pwszPath)) 387 fCreateOptions |= FILE_DIRECTORY_FILE; 388 389 /* 390 * Convert the path and call birdOpenFileUniStr to do the real work. 391 */ 392 if (birdDosToNtPathW(pwszPath, &NtPath) == 0) 393 { 394 HANDLE hFile; 395 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 396 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 397 birdFreeNtPath(&NtPath); 398 if (MY_NT_SUCCESS(rcNt)) 399 return hFile; 400 birdSetErrnoFromNt(rcNt); 401 } 402 403 return INVALID_HANDLE_VALUE; 404 } 405 406 407 HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 408 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) 409 { 410 MY_UNICODE_STRING NtPath; 411 MY_NTSTATUS rcNt; 412 413 /* 414 * Adjust inputs. 415 */ 416 if (birdIsPathDirSpec(pszPath)) 417 fCreateOptions |= FILE_DIRECTORY_FILE; 418 419 /* 420 * Convert the path and call birdOpenFileUniStr to do the real work. 421 */ 422 if (hRoot == INVALID_HANDLE_VALUE) 423 hRoot = NULL; 424 if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0) 425 { 426 HANDLE hFile; 427 rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 428 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 429 birdFreeNtPath(&NtPath); 430 if (MY_NT_SUCCESS(rcNt)) 431 return hFile; 432 birdSetErrnoFromNt(rcNt); 433 } 434 435 return INVALID_HANDLE_VALUE; 436 } 437 438 439 HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 440 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) 441 { 442 MY_UNICODE_STRING NtPath; 443 MY_NTSTATUS rcNt; 444 445 /* 446 * Adjust inputs. 447 */ 448 if (birdIsPathDirSpecW(pwszPath)) 449 fCreateOptions |= FILE_DIRECTORY_FILE; 450 451 /* 452 * Convert the path (could save ourselves this if pwszPath is perfect) and 453 * call birdOpenFileUniStr to do the real work. 454 */ 455 if (hRoot == INVALID_HANDLE_VALUE) 456 hRoot = NULL; 457 if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0) 458 { 459 HANDLE hFile; 460 rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 461 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 462 birdFreeNtPath(&NtPath); 463 if (MY_NT_SUCCESS(rcNt)) 464 return hFile; 465 birdSetErrnoFromNt(rcNt); 466 } 467 468 return INVALID_HANDLE_VALUE; 469 } 470 471 472 static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 473 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 474 MY_UNICODE_STRING *pNameUniStr) 475 { 476 MY_NTSTATUS rcNt; 477 478 /* 479 * Strip the path down to the directory. 480 */ 481 USHORT offName = pNtPath->Length / sizeof(WCHAR); 482 USHORT cwcName = offName; 483 WCHAR wc = 0; 484 while ( offName > 0 485 && (wc = pNtPath->Buffer[offName - 1]) != '\\' 486 && wc != '/' 487 && wc != ':') 488 offName--; 489 if ( offName > 0 490 || (hRoot != NULL && cwcName > 0)) 491 { 492 cwcName -= offName; 493 494 /* Make a copy of the file name, if requested. */ 495 rcNt = STATUS_SUCCESS; 496 if (pNameUniStr) 497 { 498 pNameUniStr->Length = cwcName * sizeof(WCHAR); 499 pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR); 500 pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength); 501 if (pNameUniStr->Buffer) 502 { 503 memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length); 504 pNameUniStr->Buffer[cwcName] = '\0'; 505 } 506 else 507 rcNt = STATUS_NO_MEMORY; 508 } 509 510 /* Chop, chop. */ 511 // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0 512 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = pNtPath->Buffer[offName - 1]) == '\\' 513 // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/')) 514 // Bad idea, breaks \\?\c:\pagefile.sys. // offName--; 515 if (offName == 0) 516 pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */ 517 pNtPath->Length = offName * sizeof(WCHAR); 518 pNtPath->Buffer[offName] = '\0'; 207 519 if (MY_NT_SUCCESS(rcNt)) 208 520 { 209 birdFreeNtPath(&NtPath); 210 return hFile; 211 } 212 213 birdFreeNtPath(&NtPath); 214 birdSetErrnoFromNt(rcNt); 215 } 216 217 return INVALID_HANDLE_VALUE; 218 } 219 220 221 HANDLE birdOpenParentDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, 222 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 223 MY_UNICODE_STRING *pNameUniStr) 224 { 225 MY_UNICODE_STRING NtPath; 226 MY_NTSTATUS rcNt; 227 228 /* 229 * Adjust inputs. 230 */ 231 fCreateOptions |= FILE_DIRECTORY_FILE; 232 233 /* 234 * Convert the path and split off the filename. 235 */ 236 if (birdDosToNtPath(pszPath, &NtPath) == 0) 237 { 238 USHORT offName = NtPath.Length / sizeof(WCHAR); 239 USHORT cwcName = offName; 240 WCHAR wc = 0; 241 242 while ( offName > 0 243 && (wc = NtPath.Buffer[offName - 1]) != '\\' 244 && wc != '/' 245 && wc != ':') 246 offName--; 247 if (offName > 0) 248 { 249 cwcName -= offName; 250 251 /* Make a copy of the file name, if requested. */ 252 rcNt = STATUS_SUCCESS; 253 if (pNameUniStr) 254 { 255 pNameUniStr->Length = cwcName * sizeof(WCHAR); 256 pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR); 257 pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength); 258 if (pNameUniStr->Buffer) 259 { 260 memcpy(pNameUniStr->Buffer, &NtPath.Buffer[offName],pNameUniStr->Length); 261 pNameUniStr->Buffer[cwcName] = '\0'; 262 } 263 else 264 rcNt = STATUS_NO_MEMORY; 265 } 266 267 /* Chop, chop. */ 268 // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0 269 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = NtPath.Buffer[offName - 1]) == '\\' 270 // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/')) 271 // Bad idea, breaks \\?\c:\pagefile.sys. // offName--; 272 NtPath.Length = offName * sizeof(WCHAR); 273 NtPath.Buffer[offName] = '\0'; 521 /* 522 * Finally, try open the directory. 523 */ 524 HANDLE hFile; 525 fCreateOptions |= FILE_DIRECTORY_FILE; 526 rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess, 527 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 274 528 if (MY_NT_SUCCESS(rcNt)) 275 529 { 276 /* 277 * Finally, try open the directory. 278 */ 279 HANDLE hFile; 280 rcNt = birdOpenFileUniStr(&NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 281 fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); 282 if (MY_NT_SUCCESS(rcNt)) 283 { 284 birdFreeNtPath(&NtPath); 285 return hFile; 286 } 530 birdFreeNtPath(pNtPath); 531 return hFile; 287 532 } 288 289 if (pNameUniStr)290 birdFreeNtPath(pNameUniStr);291 533 } 292 534 293 birdFreeNtPath(&NtPath); 294 birdSetErrnoFromNt(rcNt); 295 } 296 535 if (pNameUniStr) 536 birdFreeNtPath(pNameUniStr); 537 } 538 else 539 rcNt = STATUS_INVALID_PARAMETER; 540 541 birdFreeNtPath(pNtPath); 542 birdSetErrnoFromNt(rcNt); 297 543 return INVALID_HANDLE_VALUE; 544 } 545 546 547 HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 548 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 549 MY_UNICODE_STRING *pNameUniStr) 550 { 551 /* 552 * Convert the path and join up with the UTF-16 version (it'll free NtPath). 553 */ 554 MY_UNICODE_STRING NtPath; 555 if (hRoot == INVALID_HANDLE_VALUE) 556 hRoot = NULL; 557 if ( hRoot == NULL 558 ? birdDosToNtPath(pszPath, &NtPath) == 0 559 : birdDosToRelativeNtPath(pszPath, &NtPath) == 0) 560 return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 561 fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); 562 return INVALID_HANDLE_VALUE; 563 } 564 565 566 HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, 567 ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, 568 MY_UNICODE_STRING *pNameUniStr) 569 { 570 /* 571 * Convert the path and join up with the ansi version (it'll free NtPath). 572 */ 573 MY_UNICODE_STRING NtPath; 574 if (hRoot == INVALID_HANDLE_VALUE) 575 hRoot = NULL; 576 if ( hRoot == NULL 577 ? birdDosToNtPathW(pwszPath, &NtPath) == 0 578 : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0) 579 return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, 580 fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); 581 return INVALID_HANDLE_VALUE; 582 } 583 584 585 /** 586 * Returns a handle to the current working directory of the process. 587 * 588 * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access. May return 589 * INVALID_HANDLE_VALUE w/ errno for invalid CWD. 590 */ 591 HANDLE birdOpenCurrentDirectory(void) 592 { 593 PMY_RTL_USER_PROCESS_PARAMETERS pProcParams; 594 MY_NTSTATUS rcNt; 595 HANDLE hRet = INVALID_HANDLE_VALUE; 596 597 birdResolveImports(); 598 599 /* 600 * We'll try get this from the PEB. 601 */ 602 g_pfnRtlAcquirePebLock(); 603 pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters; 604 if (pProcParams != NULL) 605 rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle, 606 MY_NT_CURRENT_PROCESS, &hRet, 607 FILE_TRAVERSE | SYNCHRONIZE, 608 0 /*fAttribs*/, 609 0 /*fOptions*/); 610 else 611 rcNt = STATUS_INVALID_PARAMETER; 612 g_pfnRtlReleasePebLock(); 613 if (MY_NT_SUCCESS(rcNt)) 614 return hRet; 615 616 /* 617 * Fallback goes thru birdOpenFileW. 618 */ 619 return birdOpenFileW(L".", 620 FILE_TRAVERSE | SYNCHRONIZE, 621 FILE_ATTRIBUTE_NORMAL, 622 FILE_SHARE_READ | FILE_SHARE_WRITE, 623 FILE_OPEN, 624 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 625 OBJ_CASE_INSENSITIVE); 298 626 } 299 627 -
trunk/src/lib/nt/ntstat.c
r2880 r2985 93 93 94 94 95 static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName) 95 /** 96 * @a pwcName could be the full path. 97 */ 98 static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName) 96 99 { 97 100 char szExt[8]; … … 128 131 129 132 static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName, 130 MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)133 const wchar_t *pwszName, size_t cbNameW, __int16 *pfIsDirSymlink) 131 134 { 132 135 unsigned short fMode; … … 169 172 || (pszName 170 173 ? birdIsFileExecutable(pszName) 171 : birdIsFileExecutableW(p NameInfo->FileName, pNameInfo->FileNameLength)) )174 : birdIsFileExecutableW(pwszName, cbNameW)) ) 172 175 fMode |= S_IXOTH | S_IXGRP | S_IXUSR; 173 176 … … 186 189 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath) 187 190 { 188 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,189 NULL, &pStat->st_dirsymlink);191 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, 192 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink); 190 193 pStat->st_padding0[0] = 0; 191 194 pStat->st_padding0[1] = 0; … … 218 221 void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath) 219 222 { 220 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,221 NULL, &pStat->st_dirsymlink);223 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, 224 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink); 222 225 pStat->st_padding0[0] = 0; 223 226 pStat->st_padding0[1] = 0; … … 250 253 void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath) 251 254 { 252 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,253 NULL, &pStat->st_dirsymlink);255 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, 256 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink); 254 257 pStat->st_padding0[0] = 0; 255 258 pStat->st_padding0[1] = 0; … … 272 275 273 276 274 int birdStatHandle (HANDLE hFile, BirdStat_T *pStat, const char *pszPath)277 int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath) 275 278 { 276 279 int rc; … … 290 293 { 291 294 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath, 292 &pAll->NameInformation, &pStat->st_dirsymlink); 295 pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength, 296 &pStat->st_dirsymlink); 293 297 pStat->st_padding0[0] = 0; 294 298 pStat->st_padding0[1] = 0; … … 352 356 if (MY_NT_SUCCESS(rcNt)) 353 357 rcNt = Ios.u.Status; 354 if (MY_NT_SUCCESS(rcNt) && !pszPath )358 if (MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath) 355 359 { 356 360 cbNameInfo = 0x10020; … … 364 368 { 365 369 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath, 366 pNameInfo, &pStat->st_dirsymlink); 370 pNameInfo ? pNameInfo->FileName : pwszPath, 371 pNameInfo ? pNameInfo->FileNameLength 372 : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0, 373 &pStat->st_dirsymlink); 367 374 pStat->st_padding0[0] = 0; 368 375 pStat->st_padding0[1] = 0; … … 413 420 414 421 422 int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath) 423 { 424 return birdStatHandle2(hFile, pStat, pszPath, NULL); 425 } 426 427 415 428 /** 416 429 * Generates a device number from the volume information. … … 460 473 461 474 462 static int birdStatInternal( const char *pszPath, BirdStat_T *pStat, int fFollow)475 static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow) 463 476 { 464 477 int rc; 465 HANDLE hFile = birdOpenFile (pszPath,466 FILE_READ_ATTRIBUTES,467 FILE_ATTRIBUTE_NORMAL,468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,469 FILE_OPEN,470 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),471 OBJ_CASE_INSENSITIVE);478 HANDLE hFile = birdOpenFileEx(hRoot, pszPath, 479 FILE_READ_ATTRIBUTES, 480 FILE_ATTRIBUTE_NORMAL, 481 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 482 FILE_OPEN, 483 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), 484 OBJ_CASE_INSENSITIVE); 472 485 if (hFile != INVALID_HANDLE_VALUE) 473 486 { 474 rc = birdStatHandle (hFile, pStat, pszPath);487 rc = birdStatHandle2(hFile, pStat, pszPath, NULL); 475 488 birdCloseFile(hFile); 476 489 … … 500 513 { 501 514 MY_UNICODE_STRING NameUniStr; 502 hFile = birdOpenParentDir( pszPath,515 hFile = birdOpenParentDir(hRoot, pszPath, 503 516 FILE_READ_DATA | SYNCHRONIZE, 504 517 FILE_ATTRIBUTE_NORMAL, … … 552 565 553 566 567 static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow) 568 { 569 int rc; 570 HANDLE hFile = birdOpenFileExW(hRoot, pwszPath, 571 FILE_READ_ATTRIBUTES, 572 FILE_ATTRIBUTE_NORMAL, 573 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 574 FILE_OPEN, 575 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), 576 OBJ_CASE_INSENSITIVE); 577 if (hFile != INVALID_HANDLE_VALUE) 578 { 579 rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); 580 birdCloseFile(hFile); 581 } 582 else 583 { 584 /* 585 * On things like pagefile.sys we may get sharing violation. We fall 586 * back on directory enumeration for dealing with that. 587 */ 588 if ( errno == ETXTBSY 589 && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */ 590 && wcschr(pwszPath, '?') == NULL) 591 { 592 MY_UNICODE_STRING NameUniStr; 593 hFile = birdOpenParentDirW(hRoot, pwszPath, 594 FILE_READ_DATA | SYNCHRONIZE, 595 FILE_ATTRIBUTE_NORMAL, 596 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 597 FILE_OPEN, 598 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 599 OBJ_CASE_INSENSITIVE, 600 &NameUniStr); 601 if (hFile != INVALID_HANDLE_VALUE) 602 { 603 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; 604 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; 605 MY_IO_STATUS_BLOCK Ios; 606 MY_NTSTATUS rcNt; 607 608 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); 609 Ios.u.Status = -1; 610 Ios.Information = -1; 611 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, 612 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); 613 if (MY_NT_SUCCESS(rcNt)) 614 rcNt = Ios.u.Status; 615 if (MY_NT_SUCCESS(rcNt)) 616 { 617 /* 618 * Convert the data. 619 */ 620 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, NULL); 621 622 /* Get the serial number, reusing the buffer from above. */ 623 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); 624 if (MY_NT_SUCCESS(rcNt)) 625 rc = 0; 626 else 627 rc = birdSetErrnoFromNt(rcNt); 628 } 629 630 birdFreeNtPath(&NameUniStr); 631 birdCloseFile(hFile); 632 633 if (MY_NT_SUCCESS(rcNt)) 634 return 0; 635 birdSetErrnoFromNt(rcNt); 636 } 637 } 638 rc = -1; 639 } 640 641 return rc; 642 } 643 644 554 645 /** 555 646 * Implements UNIX fstat(). … … 570 661 { 571 662 case FILE_TYPE_DISK: 572 rc = birdStatHandle (hFile, pStat, NULL);663 rc = birdStatHandle2(hFile, pStat, NULL, NULL); 573 664 break; 574 665 … … 657 748 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat) 658 749 { 659 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/); 750 return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/); 751 } 752 753 754 /** 755 * Implements UNIX stat(). 756 */ 757 int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) 758 { 759 return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/); 660 760 } 661 761 … … 666 766 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat) 667 767 { 668 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/); 768 return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/); 769 } 770 771 772 /** 773 * Implements UNIX lstat(). 774 */ 775 int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) 776 { 777 return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/); 778 } 779 780 781 /** 782 * Implements an API like UNIX fstatat(). 783 * 784 * @returns 0 on success, -1 and errno on failure. 785 * @param hRoot NT handle pwszPath is relative to. 786 * @param pszPath The path. 787 * @param pStat Where to return stats. 788 * @param fFollowLink Whether to follow links. 789 */ 790 int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink) 791 { 792 return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0); 793 } 794 795 796 /** 797 * Implements an API like UNIX fstatat(). 798 * 799 * @returns 0 on success, -1 and errno on failure. 800 * @param hRoot NT handle pwszPath is relative to. 801 * @param pwszPath The path. 802 * @param pStat Where to return stats. 803 * @param fFollowLink Whether to follow links. 804 */ 805 int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink) 806 { 807 return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0); 669 808 } 670 809 -
trunk/src/lib/nt/ntstat.h
r2858 r2985 77 77 78 78 int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat); 79 int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); 79 80 int birdStatOnLink(const char *pszPath, BirdStat_T *pStat); 81 int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); 82 int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink); 83 int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink); 80 84 int birdStatOnFd(int fd, BirdStat_T *pStat); 81 85 int birdStatOnFdJustSize(int fd, __int64 *pcbFile); -
trunk/src/lib/nt/ntstuff.h
r2913 r2985 40 40 #include <ntstatus.h> 41 41 #undef timeval 42 43 #include <k/kTypes.h> 42 44 43 45 … … 467 469 #endif 468 470 471 #ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */ 472 # define DUPLICATE_CLOSE_SOURCE 0x00000001U 473 # define DUPLICATE_SAME_ACCESS 0x00000002U 474 #endif 475 #ifndef DUPLICATE_SAME_ATTRIBUTES 476 # define DUPLICATE_SAME_ATTRIBUTES 0x00000004U 477 #endif 478 469 479 470 480 /** @name NT status codes and associated macros. … … 480 490 /** @} */ 481 491 492 /** The pseudohandle for the current process. */ 493 #define MY_NT_CURRENT_PROCESS ((HANDLE)~(uintptr_t)0) 494 /** The pseudohandle for the current thread. */ 495 #define MY_NT_CURRENT_THREAD ((HANDLE)~(uintptr_t)1) 496 497 typedef struct MY_CLIENT_ID 498 { 499 HANDLE UniqueProcess; 500 HANDLE UniqueThread; 501 } MY_CLIENT_ID; 502 503 /** Partial TEB. */ 504 typedef struct MY_PARTIAL_TEB 505 { 506 NT_TIB NtTib; 507 PVOID EnvironmentPointer; 508 MY_CLIENT_ID ClientId; 509 PVOID ActiveRpcHandle; 510 PVOID ThreadLocalStoragePointer; 511 PPEB ProcessEnvironmentBlock; 512 KU32 LastErrorValue; 513 KU32 CountOfOwnedCriticalSections; 514 PVOID CsrClientThread; 515 PVOID Win32ThreadInfo; 516 } MY_PARTIAL_TEB; 517 518 /** Internal macro for reading uintptr_t sized TEB members. */ 519 #if K_ARCH == K_ARCH_AMD64 520 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) ) 521 #elif K_ARCH == K_ARCH_X86 522 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) ) 523 #else 524 # else "Port me!" 525 #endif 526 /** Get the PEB pointer. 527 * @remark Needs stddef.h. */ 528 #define MY_NT_CURRENT_PEB() ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) ) 529 /** Get the TEB pointer. 530 * @remark Needs stddef.h. */ 531 #define MY_NT_CURRENT_TEB() ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) ) 532 482 533 483 534 /******************************************************************************* … … 488 539 PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); 489 540 extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); 541 extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, 542 MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); 490 543 extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, 491 544 MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, … … 509 562 extern UCHAR (WINAPI * g_pfnRtlUpperChar)(UCHAR uch); 510 563 extern ULONG (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); 564 extern VOID (WINAPI * g_pfnRtlAcquirePebLock)(VOID); 565 extern VOID (WINAPI * g_pfnRtlReleasePebLock)(VOID); 511 566 512 567 -
trunk/src/lib/nt/ntunlink.c
r2713 r2985 46 46 HANDLE hFile; 47 47 48 rcNt = birdOpenFileUniStr(pNtPath, 48 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, 49 pNtPath, 49 50 FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 50 51 FILE_ATTRIBUTE_NORMAL, … … 112 113 for (;;) 113 114 { 114 rcNt = birdOpenFileUniStr(&NtPath, 115 rcNt = birdOpenFileUniStr(NULL /*hRoot*/, 116 &NtPath, 115 117 DELETE, 116 118 FILE_ATTRIBUTE_NORMAL,
Note:
See TracChangeset
for help on using the changeset viewer.