diff options
| author | Eli Zaretskii | 2015-09-07 18:26:36 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2015-09-07 18:26:36 +0300 |
| commit | caf4a0192621f49b677ad05fe86e358020a88b7e (patch) | |
| tree | 0ca50fcfa4969ef71319af161a310772ea18c894 /src | |
| parent | 066b26d6c47d1384d5ed3ce09c6379a9df350256 (diff) | |
| download | emacs-caf4a0192621f49b677ad05fe86e358020a88b7e.tar.gz emacs-caf4a0192621f49b677ad05fe86e358020a88b7e.zip | |
Fix deletion of symlinks to directories on MS-Windows
* src/w32.c (sys_unlink): If 'unlink' fails, and the argument is a
symlink to a directory, try again with 'rmdir'.
(is_symlink): If the argument is a symlink to a directory, set a
bit in the return value to indicate that fact.
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32.c | 33 |
1 files changed, 29 insertions, 4 deletions
| @@ -4534,6 +4534,8 @@ sys_rmdir (const char * path) | |||
| 4534 | int | 4534 | int |
| 4535 | sys_unlink (const char * path) | 4535 | sys_unlink (const char * path) |
| 4536 | { | 4536 | { |
| 4537 | int rmstatus, e; | ||
| 4538 | |||
| 4537 | path = map_w32_filename (path, NULL); | 4539 | path = map_w32_filename (path, NULL); |
| 4538 | 4540 | ||
| 4539 | if (w32_unicode_filenames) | 4541 | if (w32_unicode_filenames) |
| @@ -4541,9 +4543,18 @@ sys_unlink (const char * path) | |||
| 4541 | wchar_t path_w[MAX_PATH]; | 4543 | wchar_t path_w[MAX_PATH]; |
| 4542 | 4544 | ||
| 4543 | filename_to_utf16 (path, path_w); | 4545 | filename_to_utf16 (path, path_w); |
| 4544 | /* On Unix, unlink works without write permission. */ | 4546 | /* On Unix, unlink works without write permission. */ |
| 4545 | _wchmod (path_w, 0666); | 4547 | _wchmod (path_w, 0666); |
| 4546 | return _wunlink (path_w); | 4548 | rmstatus = _wunlink (path_w); |
| 4549 | e = errno; | ||
| 4550 | /* Symlinks to directories can only be deleted by _rmdir; | ||
| 4551 | _unlink returns EACCES. */ | ||
| 4552 | if (rmstatus != 0 | ||
| 4553 | && errno == EACCES | ||
| 4554 | && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 4555 | rmstatus = _wrmdir (path_w); | ||
| 4556 | else | ||
| 4557 | errno = e; | ||
| 4547 | } | 4558 | } |
| 4548 | else | 4559 | else |
| 4549 | { | 4560 | { |
| @@ -4551,8 +4562,17 @@ sys_unlink (const char * path) | |||
| 4551 | 4562 | ||
| 4552 | filename_to_ansi (path, path_a); | 4563 | filename_to_ansi (path, path_a); |
| 4553 | _chmod (path_a, 0666); | 4564 | _chmod (path_a, 0666); |
| 4554 | return _unlink (path_a); | 4565 | rmstatus = _unlink (path_a); |
| 4566 | e = errno; | ||
| 4567 | if (rmstatus != 0 | ||
| 4568 | && errno == EACCES | ||
| 4569 | && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0) | ||
| 4570 | rmstatus = _rmdir (path_a); | ||
| 4571 | else | ||
| 4572 | errno = e; | ||
| 4555 | } | 4573 | } |
| 4574 | |||
| 4575 | return rmstatus; | ||
| 4556 | } | 4576 | } |
| 4557 | 4577 | ||
| 4558 | static FILETIME utc_base_ft; | 4578 | static FILETIME utc_base_ft; |
| @@ -5626,7 +5646,8 @@ symlink (char const *filename, char const *linkname) | |||
| 5626 | /* A quick inexpensive test of whether FILENAME identifies a file that | 5646 | /* A quick inexpensive test of whether FILENAME identifies a file that |
| 5627 | is a symlink. Returns non-zero if it is, zero otherwise. FILENAME | 5647 | is a symlink. Returns non-zero if it is, zero otherwise. FILENAME |
| 5628 | must already be in the normalized form returned by | 5648 | must already be in the normalized form returned by |
| 5629 | map_w32_filename. | 5649 | map_w32_filename. If the symlink is to a directory, the |
| 5650 | FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value. | ||
| 5630 | 5651 | ||
| 5631 | Note: for repeated operations on many files, it is best to test | 5652 | Note: for repeated operations on many files, it is best to test |
| 5632 | whether the underlying volume actually supports symlinks, by | 5653 | whether the underlying volume actually supports symlinks, by |
| @@ -5684,6 +5705,8 @@ is_symlink (const char *filename) | |||
| 5684 | attrs_mean_symlink = | 5705 | attrs_mean_symlink = |
| 5685 | (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 | 5706 | (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 |
| 5686 | && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; | 5707 | && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; |
| 5708 | if (attrs_mean_symlink) | ||
| 5709 | attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); | ||
| 5687 | } | 5710 | } |
| 5688 | else if (_mbspbrk (filename_a, "?")) | 5711 | else if (_mbspbrk (filename_a, "?")) |
| 5689 | { | 5712 | { |
| @@ -5697,6 +5720,8 @@ is_symlink (const char *filename) | |||
| 5697 | attrs_mean_symlink = | 5720 | attrs_mean_symlink = |
| 5698 | (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 | 5721 | (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 |
| 5699 | && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; | 5722 | && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK; |
| 5723 | if (attrs_mean_symlink) | ||
| 5724 | attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); | ||
| 5700 | } | 5725 | } |
| 5701 | if (fh == INVALID_HANDLE_VALUE) | 5726 | if (fh == INVALID_HANDLE_VALUE) |
| 5702 | return 0; | 5727 | return 0; |