| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent abb7a15 commit 46762da
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -63,13 +63,17 @@ static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop, | |||
| 63 | 63 | handle->req_pending = 1; | |
| 64 | 64 | } | |
| 65 | 65 | ||
| 66 | - static void uv__relative_path(const WCHAR* filename, | ||
| 67 | - const WCHAR* dir, | ||
| 68 | - WCHAR** relpath) { | ||
| 66 | + /* Compute the path of `filename` relative to the watched directory `dir`. | ||
| 67 | + * Returns 0 on success, -1 if `filename` is not actually prefixed by `dir`, | ||
| 68 | + * which can happen if the directory is a short path. */ | ||
| 69 | + static int uv__relative_path(const WCHAR* filename, | ||
| 70 | + const WCHAR* dir, | ||
| 71 | + WCHAR** relpath) { | ||
| 69 | 72 | size_t relpathlen; | |
| 70 | 73 | size_t filenamelen = wcslen(filename); | |
| 71 | 74 | size_t dirlen = wcslen(dir); | |
| 72 | - assert(!_wcsnicmp(filename, dir, dirlen)); | ||
| 75 | + if (filenamelen <= dirlen || _wcsnicmp(filename, dir, dirlen) != 0) | ||
| 76 | + return -1; | ||
| 73 | 77 | if (dirlen > 0 && dir[dirlen - 1] == '\\') | |
| 74 | 78 | dirlen--; | |
| 75 | 79 | relpathlen = filenamelen - dirlen - 1; | |
@@ -78,6 +82,7 @@ static void uv__relative_path(const WCHAR* filename, | |||
| 78 | 82 | uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); | |
| 79 | 83 | wcsncpy(*relpath, filename + dirlen + 1, relpathlen); | |
| 80 | 84 | (*relpath)[relpathlen] = L'\0'; | |
| 85 | + return 0; | ||
| 81 | 86 | } | |
| 82 | 87 | ||
| 83 | 88 | static int uv__split_path(const WCHAR* filename, WCHAR** dir, | |
@@ -517,12 +522,21 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, | |||
| 517 | 522 | ||
| 518 | 523 | if (long_filenamew) { | |
| 519 | 524 | /* Get the file name out of the long path. */ | |
| 520 | - uv__relative_path(long_filenamew, | ||
| 521 | - handle->dirw, | ||
| 522 | - &filenamew); | ||
| 523 | - uv__free(long_filenamew); | ||
| 524 | - long_filenamew = filenamew; | ||
| 525 | - sizew = -1; | ||
| 525 | + if (uv__relative_path(long_filenamew, | ||
| 526 | + handle->dirw, | ||
| 527 | + &filenamew) == 0) { | ||
| 528 | + uv__free(long_filenamew); | ||
| 529 | + long_filenamew = filenamew; | ||
| 530 | + sizew = -1; | ||
| 531 | + } else { | ||
| 532 | + /* The resolved long path was not prefixed by the watched | ||
| 533 | + * directory (e.g. short name vs long name mismatch), | ||
| 534 | + * fall back to the name given by ReadDirectoryChangesW. */ | ||
| 535 | + uv__free(long_filenamew); | ||
| 536 | + long_filenamew = NULL; | ||
| 537 | + filenamew = file_info->FileName; | ||
| 538 | + sizew = file_info->FileNameLength / sizeof(WCHAR); | ||
| 539 | + } | ||
| 526 | 540 | } else { | |
| 527 | 541 | /* We couldn't get the long filename, use the one reported. */ | |
| 528 | 542 | filenamew = file_info->FileName; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -587,45 +587,119 @@ TEST_IMPL(fs_event_watch_dir_recursive) { | |||
| 587 | 587 | } | |
| 588 | 588 | ||
| 589 | 589 | #ifdef _WIN32 | |
| 590 | + static char short_path_file[MAX_PATH]; | ||
| 591 | + | ||
| 592 | + static void short_path_timer_cb(uv_timer_t* handle) { | ||
| 593 | + ++timer_cb_called; | ||
| 594 | + touch_file(short_path_file); | ||
| 595 | + } | ||
| 596 | + | ||
| 597 | + /* Try to create a unique watch directory that has a 8.3 short component | ||
| 598 | + under `parent` ("" means the cwd). If it's successful, fills `watch_dir` | ||
| 599 | + and `short_dir` with the long and short forms of the created directory | ||
| 600 | + respectively, and returns 1. Otherwise removes the directory created | ||
| 601 | + and returns 0. */ | ||
| 602 | + static int short_path_make(const char* parent, | ||
| 603 | + char* watch_dir, size_t watch_n, | ||
| 604 | + char* short_dir, size_t short_n) { | ||
| 605 | + uv_fs_t req; | ||
| 606 | + char tmpl[MAX_PATH]; | ||
| 607 | + WCHAR watch_dirw[MAX_PATH]; | ||
| 608 | + WCHAR short_dirw[MAX_PATH]; | ||
| 609 | + WCHAR long_dirw[MAX_PATH]; | ||
| 610 | + size_t pathlen; | ||
| 611 | + int r; | ||
| 612 | + | ||
| 613 | + if (parent[0] != '\0') | ||
| 614 | + r = snprintf(tmpl, sizeof(tmpl), "%s\\watch_dirXXXXXX", parent); | ||
| 615 | + else | ||
| 616 | + r = snprintf(tmpl, sizeof(tmpl), "watch_dirXXXXXX"); | ||
| 617 | + if (r < 0 || (size_t) r >= sizeof(tmpl)) | ||
| 618 | + return 0; | ||
| 619 | + | ||
| 620 | + r = uv_fs_mkdtemp(NULL, &req, tmpl, NULL); | ||
| 621 | + if (r != 0) { | ||
| 622 | + uv_fs_req_cleanup(&req); | ||
| 623 | + return 0; | ||
| 624 | + } | ||
| 625 | + | ||
| 626 | + /* Copy the created path out before cleaning up the request that owns it. */ | ||
| 627 | + pathlen = strlen(req.path); | ||
| 628 | + memcpy(watch_dir, req.path, pathlen + 1); | ||
| 629 | + uv_fs_req_cleanup(&req); | ||
| 630 | + | ||
| 631 | + /* The caller appends "\\file1" to both watch_dir and short_dir. If there is | ||
| 632 | + no room for that suffix, skip this location. */ | ||
| 633 | + if (pathlen + sizeof("\\file1") <= watch_n && | ||
| 634 | + MultiByteToWideChar(CP_UTF8, 0, watch_dir, -1, | ||
| 635 | + watch_dirw, ARRAY_SIZE(watch_dirw)) != 0 && | ||
| 636 | + GetShortPathNameW(watch_dirw, short_dirw, ARRAY_SIZE(short_dirw)) != 0 && | ||
| 637 | + GetLongPathNameW(watch_dirw, long_dirw, ARRAY_SIZE(long_dirw)) != 0 && | ||
| 638 | + _wcsicmp(short_dirw, long_dirw) != 0 && | ||
| 639 | + WideCharToMultiByte(CP_UTF8, 0, short_dirw, -1, | ||
| 640 | + short_dir, (int) short_n, NULL, NULL) != 0) | ||
| 641 | + return 1; | ||
| 642 | + | ||
| 643 | + uv_fs_rmdir(NULL, &req, watch_dir, NULL); | ||
| 644 | + uv_fs_req_cleanup(&req); | ||
| 645 | + return 0; | ||
| 646 | + } | ||
| 647 | + | ||
| 590 | 648 | TEST_IMPL(fs_event_watch_dir_short_path) { | |
| 591 | 649 | uv_loop_t* loop; | |
| 592 | - uv_fs_t req; | ||
| 650 | + char temp_path[MAX_PATH]; | ||
| 651 | + char watch_dir[MAX_PATH]; | ||
| 652 | + char watch_file[MAX_PATH]; | ||
| 653 | + char short_dir[MAX_PATH]; | ||
| 654 | + size_t temp_len; | ||
| 593 | 655 | int has_shortnames; | |
| 594 | 656 | int r; | |
| 595 | 657 | ||
| 596 | - /* Setup */ | ||
| 597 | 658 | loop = uv_default_loop(); | |
| 598 | - delete_file("watch_dir/file1"); | ||
| 599 | - delete_dir("watch_dir/"); | ||
| 600 | - create_dir("watch_dir"); | ||
| 601 | - create_file("watch_dir/file1"); | ||
| 602 | 659 | ||
| 603 | - /* Newer version of Windows ship with | ||
| 604 | - HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation | ||
| 605 | - not equal to 0. So we verify the files we created are addressable by a 8.3 | ||
| 606 | - short name */ | ||
| 607 | - has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT; | ||
| 660 | + /* This test needs the watched directory to have an 8.3 short component. The | ||
| 661 | + generated "watch_dirXXXXXX" name is > 8 chars, so it gets a short alias on | ||
| 662 | + volumes where 8.3 name creation is enabled. For non-system volumes on | ||
| 663 | + newer Windows it's disabled by default (NtfsDisable8dot3NameCreation=3). | ||
| 664 | + The temp dir and the cwd may be on different volumes, so try each and use | ||
| 665 | + whichever has a short alias, and skip if neither does. */ | ||
| 666 | + has_shortnames = 0; | ||
| 667 | + temp_len = sizeof(temp_path); | ||
| 668 | + if (uv_os_tmpdir(temp_path, &temp_len) == 0) | ||
| 669 | + has_shortnames = short_path_make(temp_path, | ||
| 670 | + watch_dir, sizeof(watch_dir), | ||
| 671 | + short_dir, sizeof(short_dir)); | ||
| 672 | + if (!has_shortnames) | ||
| 673 | + has_shortnames = short_path_make("", | ||
| 674 | + watch_dir, sizeof(watch_dir), | ||
| 675 | + short_dir, sizeof(short_dir)); | ||
| 676 | + | ||
| 608 | 677 | if (has_shortnames) { | |
| 678 | + snprintf(watch_file, sizeof(watch_file), "%s\\file1", watch_dir); | ||
| 679 | + /* short_path_file is used in the timer callback to touch the file. */ | ||
| 680 | + snprintf(short_path_file, sizeof(short_path_file), "%s\\file1", short_dir); | ||
| 681 | + /* The directory was just created, so file1 cannot exist yet. */ | ||
| 682 | + create_file(watch_file); | ||
| 683 | + | ||
| 609 | 684 | r = uv_fs_event_init(loop, &fs_event); | |
| 610 | 685 | ASSERT_OK(r); | |
| 611 | - r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); | ||
| 686 | + r = uv_fs_event_start(&fs_event, fs_event_cb_dir, short_dir, 0); | ||
| 612 | 687 | ASSERT_OK(r); | |
| 613 | 688 | r = uv_timer_init(loop, &timer); | |
| 614 | 689 | ASSERT_OK(r); | |
| 615 | - r = uv_timer_start(&timer, timer_cb_file, 100, 0); | ||
| 690 | + r = uv_timer_start(&timer, short_path_timer_cb, 100, 0); | ||
| 616 | 691 | ASSERT_OK(r); | |
| 617 | 692 | ||
| 618 | 693 | uv_run(loop, UV_RUN_DEFAULT); | |
| 619 | 694 | ||
| 620 | 695 | ASSERT_EQ(1, fs_event_cb_called); | |
| 621 | 696 | ASSERT_EQ(1, timer_cb_called); | |
| 622 | 697 | ASSERT_EQ(1, close_cb_called); | |
| 698 | + /* Cleanup */ | ||
| 699 | + delete_file(watch_file); | ||
| 700 | + delete_dir(watch_dir); | ||
| 623 | 701 | } | |
| 624 | 702 | ||
| 625 | - /* Cleanup */ | ||
| 626 | - delete_file("watch_dir/file1"); | ||
| 627 | - delete_dir("watch_dir/"); | ||
| 628 | - | ||
| 629 | 703 | MAKE_VALGRIND_HAPPY(loop); | |
| 630 | 704 | ||
| 631 | 705 | if (!has_shortnames) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments