diff options
| author | Eli Zaretskii | 2013-01-26 14:49:34 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-01-26 14:49:34 +0200 |
| commit | 806fed21f15908cee4e3cfdb18e21d988e08ea48 (patch) | |
| tree | ccb5ee9599c7b45ed9c698ca56f495d61c135feb /src/w32.c | |
| parent | 26854e9c9ee5469474bcaa496b94273082772c18 (diff) | |
| download | emacs-806fed21f15908cee4e3cfdb18e21d988e08ea48.tar.gz emacs-806fed21f15908cee4e3cfdb18e21d988e08ea48.zip | |
Fix bug #13553 with usage of IS_DIRECTORY_SEP on MS-Windows under DBCS.
src/w32.c (parse_root, get_volume_info, readdir, read_unc_volume)
(logon_network_drive, stat_worker, symlink, chase_symlinks): Use
CharNextExA and CharPrevExA to iterate over file names encoded in
DBCS.
Diffstat (limited to 'src/w32.c')
| -rw-r--r-- | src/w32.c | 173 |
1 files changed, 151 insertions, 22 deletions
| @@ -1503,12 +1503,17 @@ parse_root (char * name, char ** pPath) | |||
| 1503 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | 1503 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) |
| 1504 | { | 1504 | { |
| 1505 | int slashes = 2; | 1505 | int slashes = 2; |
| 1506 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 1507 | |||
| 1506 | name += 2; | 1508 | name += 2; |
| 1507 | do | 1509 | do |
| 1508 | { | 1510 | { |
| 1509 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 1511 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
| 1510 | break; | 1512 | break; |
| 1511 | name++; | 1513 | if (dbcs_p) |
| 1514 | name = CharNextExA (file_name_codepage, name, 0); | ||
| 1515 | else | ||
| 1516 | name++; | ||
| 1512 | } | 1517 | } |
| 1513 | while ( *name ); | 1518 | while ( *name ); |
| 1514 | if (IS_DIRECTORY_SEP (name[0])) | 1519 | if (IS_DIRECTORY_SEP (name[0])) |
| @@ -2369,12 +2374,23 @@ get_volume_info (const char * name, const char ** pPath) | |||
| 2369 | { | 2374 | { |
| 2370 | char *str = temp; | 2375 | char *str = temp; |
| 2371 | int slashes = 4; | 2376 | int slashes = 4; |
| 2377 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2378 | |||
| 2372 | rootname = temp; | 2379 | rootname = temp; |
| 2373 | do | 2380 | do |
| 2374 | { | 2381 | { |
| 2375 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | 2382 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) |
| 2376 | break; | 2383 | break; |
| 2377 | *str++ = *name++; | 2384 | if (!dbcs_p) |
| 2385 | *str++ = *name++; | ||
| 2386 | else | ||
| 2387 | { | ||
| 2388 | const char *p = name; | ||
| 2389 | |||
| 2390 | name = CharNextExA (file_name_codepage, name, 0); | ||
| 2391 | memcpy (str, p, name - p); | ||
| 2392 | str += name - p; | ||
| 2393 | } | ||
| 2378 | } | 2394 | } |
| 2379 | while ( *name ); | 2395 | while ( *name ); |
| 2380 | 2396 | ||
| @@ -2610,11 +2626,23 @@ readdir (DIR *dirp) | |||
| 2610 | { | 2626 | { |
| 2611 | char filename[MAXNAMLEN + 3]; | 2627 | char filename[MAXNAMLEN + 3]; |
| 2612 | int ln; | 2628 | int ln; |
| 2629 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2613 | 2630 | ||
| 2614 | strcpy (filename, dir_pathname); | 2631 | strcpy (filename, dir_pathname); |
| 2615 | ln = strlen (filename) - 1; | 2632 | ln = strlen (filename) - 1; |
| 2616 | if (!IS_DIRECTORY_SEP (filename[ln])) | 2633 | if (!dbcs_p) |
| 2617 | strcat (filename, "\\"); | 2634 | { |
| 2635 | if (!IS_DIRECTORY_SEP (filename[ln])) | ||
| 2636 | strcat (filename, "\\"); | ||
| 2637 | } | ||
| 2638 | else | ||
| 2639 | { | ||
| 2640 | char *end = filename + ln + 1; | ||
| 2641 | char *last_char = CharPrevExA (file_name_codepage, filename, end, 0); | ||
| 2642 | |||
| 2643 | if (!IS_DIRECTORY_SEP (*last_char)) | ||
| 2644 | strcat (filename, "\\"); | ||
| 2645 | } | ||
| 2618 | strcat (filename, "*"); | 2646 | strcat (filename, "*"); |
| 2619 | 2647 | ||
| 2620 | /* Note: No need to resolve symlinks in FILENAME, because | 2648 | /* Note: No need to resolve symlinks in FILENAME, because |
| @@ -2719,6 +2747,7 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) | |||
| 2719 | DWORD bufsize = 512; | 2747 | DWORD bufsize = 512; |
| 2720 | char *buffer; | 2748 | char *buffer; |
| 2721 | char *ptr; | 2749 | char *ptr; |
| 2750 | int dbcs_p = max_filename_mbslen () > 1; | ||
| 2722 | 2751 | ||
| 2723 | count = 1; | 2752 | count = 1; |
| 2724 | buffer = alloca (bufsize); | 2753 | buffer = alloca (bufsize); |
| @@ -2729,7 +2758,13 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) | |||
| 2729 | /* WNetEnumResource returns \\resource\share...skip forward to "share". */ | 2758 | /* WNetEnumResource returns \\resource\share...skip forward to "share". */ |
| 2730 | ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; | 2759 | ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; |
| 2731 | ptr += 2; | 2760 | ptr += 2; |
| 2732 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; | 2761 | if (!dbcs_p) |
| 2762 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; | ||
| 2763 | else | ||
| 2764 | { | ||
| 2765 | while (*ptr && !IS_DIRECTORY_SEP (*ptr)) | ||
| 2766 | ptr = CharNextExA (file_name_codepage, ptr, 0); | ||
| 2767 | } | ||
| 2733 | ptr++; | 2768 | ptr++; |
| 2734 | 2769 | ||
| 2735 | strncpy (readbuf, ptr, size); | 2770 | strncpy (readbuf, ptr, size); |
| @@ -2766,9 +2801,11 @@ logon_network_drive (const char *path) | |||
| 2766 | { | 2801 | { |
| 2767 | NETRESOURCE resource; | 2802 | NETRESOURCE resource; |
| 2768 | char share[MAX_PATH]; | 2803 | char share[MAX_PATH]; |
| 2769 | int i, n_slashes; | 2804 | int n_slashes; |
| 2770 | char drive[4]; | 2805 | char drive[4]; |
| 2771 | UINT drvtype; | 2806 | UINT drvtype; |
| 2807 | char *p; | ||
| 2808 | int dbcs_p; | ||
| 2772 | 2809 | ||
| 2773 | if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) | 2810 | if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) |
| 2774 | drvtype = DRIVE_REMOTE; | 2811 | drvtype = DRIVE_REMOTE; |
| @@ -2790,13 +2827,18 @@ logon_network_drive (const char *path) | |||
| 2790 | n_slashes = 2; | 2827 | n_slashes = 2; |
| 2791 | strncpy (share, path, MAX_PATH); | 2828 | strncpy (share, path, MAX_PATH); |
| 2792 | /* Truncate to just server and share name. */ | 2829 | /* Truncate to just server and share name. */ |
| 2793 | for (i = 2; i < MAX_PATH; i++) | 2830 | dbcs_p = max_filename_mbslen () > 1; |
| 2831 | for (p = share + 2; *p && p < share + MAX_PATH; ) | ||
| 2794 | { | 2832 | { |
| 2795 | if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3) | 2833 | if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3) |
| 2796 | { | 2834 | { |
| 2797 | share[i] = '\0'; | 2835 | *p = '\0'; |
| 2798 | break; | 2836 | break; |
| 2799 | } | 2837 | } |
| 2838 | if (dbcs_p) | ||
| 2839 | p = CharNextExA (file_name_codepage, p, 0); | ||
| 2840 | else | ||
| 2841 | p++; | ||
| 2800 | } | 2842 | } |
| 2801 | 2843 | ||
| 2802 | resource.dwType = RESOURCETYPE_DISK; | 2844 | resource.dwType = RESOURCETYPE_DISK; |
| @@ -3557,6 +3599,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3557 | DWORD access_rights = 0; | 3599 | DWORD access_rights = 0; |
| 3558 | DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; | 3600 | DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; |
| 3559 | FILETIME ctime, atime, wtime; | 3601 | FILETIME ctime, atime, wtime; |
| 3602 | int dbcs_p; | ||
| 3560 | 3603 | ||
| 3561 | if (path == NULL || buf == NULL) | 3604 | if (path == NULL || buf == NULL) |
| 3562 | { | 3605 | { |
| @@ -3751,6 +3794,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3751 | did not ask for extra precision, resolving symlinks will fly | 3794 | did not ask for extra precision, resolving symlinks will fly |
| 3752 | in the face of that request, since the user then wants the | 3795 | in the face of that request, since the user then wants the |
| 3753 | lightweight version of the code. */ | 3796 | lightweight version of the code. */ |
| 3797 | dbcs_p = max_filename_mbslen () > 1; | ||
| 3754 | rootdir = (path >= save_name + len - 1 | 3798 | rootdir = (path >= save_name + len - 1 |
| 3755 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); | 3799 | && (IS_DIRECTORY_SEP (*path) || *path == 0)); |
| 3756 | 3800 | ||
| @@ -3778,8 +3822,19 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3778 | } | 3822 | } |
| 3779 | else if (rootdir) | 3823 | else if (rootdir) |
| 3780 | { | 3824 | { |
| 3781 | if (!IS_DIRECTORY_SEP (name[len-1])) | 3825 | if (!dbcs_p) |
| 3782 | strcat (name, "\\"); | 3826 | { |
| 3827 | if (!IS_DIRECTORY_SEP (name[len-1])) | ||
| 3828 | strcat (name, "\\"); | ||
| 3829 | } | ||
| 3830 | else | ||
| 3831 | { | ||
| 3832 | char *end = name + len; | ||
| 3833 | char *n = CharPrevExA (file_name_codepage, name, end, 0); | ||
| 3834 | |||
| 3835 | if (!IS_DIRECTORY_SEP (*n)) | ||
| 3836 | strcat (name, "\\"); | ||
| 3837 | } | ||
| 3783 | if (GetDriveType (name) < 2) | 3838 | if (GetDriveType (name) < 2) |
| 3784 | { | 3839 | { |
| 3785 | errno = ENOENT; | 3840 | errno = ENOENT; |
| @@ -3791,15 +3846,37 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) | |||
| 3791 | } | 3846 | } |
| 3792 | else | 3847 | else |
| 3793 | { | 3848 | { |
| 3794 | if (IS_DIRECTORY_SEP (name[len-1])) | 3849 | if (!dbcs_p) |
| 3795 | name[len - 1] = 0; | 3850 | { |
| 3851 | if (IS_DIRECTORY_SEP (name[len-1])) | ||
| 3852 | name[len - 1] = 0; | ||
| 3853 | } | ||
| 3854 | else | ||
| 3855 | { | ||
| 3856 | char *end = name + len; | ||
| 3857 | char *n = CharPrevExA (file_name_codepage, name, end, 0); | ||
| 3858 | |||
| 3859 | if (IS_DIRECTORY_SEP (*n)) | ||
| 3860 | *n = 0; | ||
| 3861 | } | ||
| 3796 | 3862 | ||
| 3797 | /* (This is hacky, but helps when doing file completions on | 3863 | /* (This is hacky, but helps when doing file completions on |
| 3798 | network drives.) Optimize by using information available from | 3864 | network drives.) Optimize by using information available from |
| 3799 | active readdir if possible. */ | 3865 | active readdir if possible. */ |
| 3800 | len = strlen (dir_pathname); | 3866 | len = strlen (dir_pathname); |
| 3801 | if (IS_DIRECTORY_SEP (dir_pathname[len-1])) | 3867 | if (!dbcs_p) |
| 3802 | len--; | 3868 | { |
| 3869 | if (IS_DIRECTORY_SEP (dir_pathname[len-1])) | ||
| 3870 | len--; | ||
| 3871 | } | ||
| 3872 | else | ||
| 3873 | { | ||
| 3874 | char *end = dir_pathname + len; | ||
| 3875 | char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0); | ||
| 3876 | |||
| 3877 | if (IS_DIRECTORY_SEP (*n)) | ||
| 3878 | len--; | ||
| 3879 | } | ||
| 3803 | if (dir_find_handle != INVALID_HANDLE_VALUE | 3880 | if (dir_find_handle != INVALID_HANDLE_VALUE |
| 3804 | && !(is_a_symlink && follow_symlinks) | 3881 | && !(is_a_symlink && follow_symlinks) |
| 3805 | && strnicmp (save_name, dir_pathname, len) == 0 | 3882 | && strnicmp (save_name, dir_pathname, len) == 0 |
| @@ -4060,6 +4137,7 @@ symlink (char const *filename, char const *linkname) | |||
| 4060 | char linkfn[MAX_PATH], *tgtfn; | 4137 | char linkfn[MAX_PATH], *tgtfn; |
| 4061 | DWORD flags = 0; | 4138 | DWORD flags = 0; |
| 4062 | int dir_access, filename_ends_in_slash; | 4139 | int dir_access, filename_ends_in_slash; |
| 4140 | int dbcs_p; | ||
| 4063 | 4141 | ||
| 4064 | /* Diagnostics follows Posix as much as possible. */ | 4142 | /* Diagnostics follows Posix as much as possible. */ |
| 4065 | if (filename == NULL || linkname == NULL) | 4143 | if (filename == NULL || linkname == NULL) |
| @@ -4085,6 +4163,8 @@ symlink (char const *filename, char const *linkname) | |||
| 4085 | return -1; | 4163 | return -1; |
| 4086 | } | 4164 | } |
| 4087 | 4165 | ||
| 4166 | dbcs_p = max_filename_mbslen () > 1; | ||
| 4167 | |||
| 4088 | /* Note: since empty FILENAME was already rejected, we can safely | 4168 | /* Note: since empty FILENAME was already rejected, we can safely |
| 4089 | refer to FILENAME[1]. */ | 4169 | refer to FILENAME[1]. */ |
| 4090 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) | 4170 | if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) |
| @@ -4099,8 +4179,21 @@ symlink (char const *filename, char const *linkname) | |||
| 4099 | char tem[MAX_PATH]; | 4179 | char tem[MAX_PATH]; |
| 4100 | char *p = linkfn + strlen (linkfn); | 4180 | char *p = linkfn + strlen (linkfn); |
| 4101 | 4181 | ||
| 4102 | while (p > linkfn && !IS_ANY_SEP (p[-1])) | 4182 | if (!dbcs_p) |
| 4103 | p--; | 4183 | { |
| 4184 | while (p > linkfn && !IS_ANY_SEP (p[-1])) | ||
| 4185 | p--; | ||
| 4186 | } | ||
| 4187 | else | ||
| 4188 | { | ||
| 4189 | char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0); | ||
| 4190 | |||
| 4191 | while (p > linkfn && !IS_ANY_SEP (*p1)) | ||
| 4192 | { | ||
| 4193 | p = p1; | ||
| 4194 | p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0); | ||
| 4195 | } | ||
| 4196 | } | ||
| 4104 | if (p > linkfn) | 4197 | if (p > linkfn) |
| 4105 | strncpy (tem, linkfn, p - linkfn); | 4198 | strncpy (tem, linkfn, p - linkfn); |
| 4106 | tem[p - linkfn] = '\0'; | 4199 | tem[p - linkfn] = '\0'; |
| @@ -4115,7 +4208,15 @@ symlink (char const *filename, char const *linkname) | |||
| 4115 | exist, but ends in a slash, we create a symlink to directory. If | 4208 | exist, but ends in a slash, we create a symlink to directory. If |
| 4116 | FILENAME exists and is a directory, we always create a symlink to | 4209 | FILENAME exists and is a directory, we always create a symlink to |
| 4117 | directory. */ | 4210 | directory. */ |
| 4118 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); | 4211 | if (!dbcs_p) |
| 4212 | filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); | ||
| 4213 | else | ||
| 4214 | { | ||
| 4215 | const char *end = filename + strlen (filename); | ||
| 4216 | const char *n = CharPrevExA (file_name_codepage, filename, end, 0); | ||
| 4217 | |||
| 4218 | filename_ends_in_slash = IS_DIRECTORY_SEP (*n); | ||
| 4219 | } | ||
| 4119 | if (dir_access == 0 || filename_ends_in_slash) | 4220 | if (dir_access == 0 || filename_ends_in_slash) |
| 4120 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; | 4221 | flags = SYMBOLIC_LINK_FLAG_DIRECTORY; |
| 4121 | 4222 | ||
| @@ -4440,6 +4541,7 @@ chase_symlinks (const char *file) | |||
| 4440 | char link[MAX_PATH]; | 4541 | char link[MAX_PATH]; |
| 4441 | ssize_t res, link_len; | 4542 | ssize_t res, link_len; |
| 4442 | int loop_count = 0; | 4543 | int loop_count = 0; |
| 4544 | int dbcs_p; | ||
| 4443 | 4545 | ||
| 4444 | if (is_windows_9x () == TRUE || !is_symlink (file)) | 4546 | if (is_windows_9x () == TRUE || !is_symlink (file)) |
| 4445 | return (char *)file; | 4547 | return (char *)file; |
| @@ -4447,13 +4549,27 @@ chase_symlinks (const char *file) | |||
| 4447 | if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) | 4549 | if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) |
| 4448 | return (char *)file; | 4550 | return (char *)file; |
| 4449 | 4551 | ||
| 4552 | dbcs_p = max_filename_mbslen () > 1; | ||
| 4450 | target[0] = '\0'; | 4553 | target[0] = '\0'; |
| 4451 | do { | 4554 | do { |
| 4452 | 4555 | ||
| 4453 | /* Remove trailing slashes, as we want to resolve the last | 4556 | /* Remove trailing slashes, as we want to resolve the last |
| 4454 | non-trivial part of the link name. */ | 4557 | non-trivial part of the link name. */ |
| 4455 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) | 4558 | if (!dbcs_p) |
| 4456 | link[link_len--] = '\0'; | 4559 | { |
| 4560 | while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) | ||
| 4561 | link[link_len--] = '\0'; | ||
| 4562 | } | ||
| 4563 | else if (link_len > 3) | ||
| 4564 | { | ||
| 4565 | char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0); | ||
| 4566 | |||
| 4567 | while (n >= link + 2 && IS_DIRECTORY_SEP (*n)) | ||
| 4568 | { | ||
| 4569 | n[1] = '\0'; | ||
| 4570 | n = CharPrevExA (file_name_codepage, link, n, 0); | ||
| 4571 | } | ||
| 4572 | } | ||
| 4457 | 4573 | ||
| 4458 | res = readlink (link, target, MAX_PATH); | 4574 | res = readlink (link, target, MAX_PATH); |
| 4459 | if (res > 0) | 4575 | if (res > 0) |
| @@ -4466,8 +4582,21 @@ chase_symlinks (const char *file) | |||
| 4466 | the symlink, then copy the result back to target. */ | 4582 | the symlink, then copy the result back to target. */ |
| 4467 | char *p = link + link_len; | 4583 | char *p = link + link_len; |
| 4468 | 4584 | ||
| 4469 | while (p > link && !IS_ANY_SEP (p[-1])) | 4585 | if (!dbcs_p) |
| 4470 | p--; | 4586 | { |
| 4587 | while (p > link && !IS_ANY_SEP (p[-1])) | ||
| 4588 | p--; | ||
| 4589 | } | ||
| 4590 | else | ||
| 4591 | { | ||
| 4592 | char *p1 = CharPrevExA (file_name_codepage, link, p, 0); | ||
| 4593 | |||
| 4594 | while (p > link && !IS_ANY_SEP (*p1)) | ||
| 4595 | { | ||
| 4596 | p = p1; | ||
| 4597 | p1 = CharPrevExA (file_name_codepage, link, p1, 0); | ||
| 4598 | } | ||
| 4599 | } | ||
| 4471 | strcpy (p, target); | 4600 | strcpy (p, target); |
| 4472 | strcpy (target, link); | 4601 | strcpy (target, link); |
| 4473 | } | 4602 | } |