Fossil SCM
When removing a directory on Windows, make sure it is a real directory (i.e. not a junction, symbolic link, etc).
Commit
9bb25a28627be067847de63528aa23984590bed594abf7640b48fda5d276771d
Parent
743e166cf95c86e…
1 file changed
+48
-1
+48
-1
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -701,10 +701,53 @@ | ||
| 701 | 701 | } |
| 702 | 702 | free(zName); |
| 703 | 703 | return rc; |
| 704 | 704 | } |
| 705 | 705 | |
| 706 | +#if defined(_WIN32) | |
| 707 | +/* | |
| 708 | +** Returns non-zero if the specified name represents a real directory, i.e. | |
| 709 | +** not a junction or symbolic link. This is important for some operations, | |
| 710 | +** e.g. removing directories via _wrmdir(), because its detection of empty | |
| 711 | +** directories will (apparently) not work right for junctions and symbolic | |
| 712 | +** links, etc. | |
| 713 | +*/ | |
| 714 | +int file_is_normal_dir(wchar_t *zName){ | |
| 715 | + /* | |
| 716 | + ** Mask off attributes, applicable to directories, that are harmless for | |
| 717 | + ** our purposes. This may need to be updated if other attributes should | |
| 718 | + ** be ignored by this function. | |
| 719 | + */ | |
| 720 | + DWORD dwAttributes = GetFileAttributesW(zName); | |
| 721 | + if( dwAttributes==INVALID_FILE_ATTRIBUTES ) return 0; | |
| 722 | + dwAttributes &= ~( | |
| 723 | + FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED | | |
| 724 | + FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_NORMAL | | |
| 725 | + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | |
| 726 | + ); | |
| 727 | + return dwAttributes==FILE_ATTRIBUTE_DIRECTORY; | |
| 728 | +} | |
| 729 | + | |
| 730 | +/* | |
| 731 | +** COMMAND: test-is-normal-dir | |
| 732 | +** | |
| 733 | +** Usage: %fossil test-is-normal-dir NAME... | |
| 734 | +** | |
| 735 | +** Returns non-zero if the specified names represent real directories, i.e. | |
| 736 | +** not junctions, symbolic links, etc. | |
| 737 | +*/ | |
| 738 | +void test_is_normal_dir(void){ | |
| 739 | + int i; | |
| 740 | + for(i=2; i<g.argc; i++){ | |
| 741 | + wchar_t *zMbcs = fossil_utf8_to_path(g.argv[i], 1); | |
| 742 | + fossil_print("ATTRS \"%s\" -> %lx\n", g.argv[i], GetFileAttributesW(zMbcs)); | |
| 743 | + fossil_print("ISDIR \"%s\" -> %d\n", g.argv[i], file_is_normal_dir(zMbcs)); | |
| 744 | + fossil_path_free(zMbcs); | |
| 745 | + } | |
| 746 | +} | |
| 747 | +#endif | |
| 748 | + | |
| 706 | 749 | /* |
| 707 | 750 | ** Removes the directory named in the argument, if it exists. The directory |
| 708 | 751 | ** must be empty and cannot be the current directory or the root directory. |
| 709 | 752 | ** |
| 710 | 753 | ** Returns zero upon success. |
| @@ -713,11 +756,15 @@ | ||
| 713 | 756 | int rc = file_isdir(zName, RepoFILE); |
| 714 | 757 | if( rc==2 ) return 1; /* cannot remove normal file */ |
| 715 | 758 | if( rc==1 ){ |
| 716 | 759 | #if defined(_WIN32) |
| 717 | 760 | wchar_t *zMbcs = fossil_utf8_to_path(zName, 1); |
| 718 | - rc = _wrmdir(zMbcs); | |
| 761 | + if( file_is_normal_dir(zMbcs) ){ | |
| 762 | + rc = _wrmdir(zMbcs); | |
| 763 | + }else{ | |
| 764 | + rc = ENOTDIR; /* junction, symbolic link, etc. */ | |
| 765 | + } | |
| 719 | 766 | #else |
| 720 | 767 | char *zMbcs = fossil_utf8_to_path(zName, 1); |
| 721 | 768 | rc = rmdir(zName); |
| 722 | 769 | #endif |
| 723 | 770 | fossil_path_free(zMbcs); |
| 724 | 771 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -701,10 +701,53 @@ | |
| 701 | } |
| 702 | free(zName); |
| 703 | return rc; |
| 704 | } |
| 705 | |
| 706 | /* |
| 707 | ** Removes the directory named in the argument, if it exists. The directory |
| 708 | ** must be empty and cannot be the current directory or the root directory. |
| 709 | ** |
| 710 | ** Returns zero upon success. |
| @@ -713,11 +756,15 @@ | |
| 713 | int rc = file_isdir(zName, RepoFILE); |
| 714 | if( rc==2 ) return 1; /* cannot remove normal file */ |
| 715 | if( rc==1 ){ |
| 716 | #if defined(_WIN32) |
| 717 | wchar_t *zMbcs = fossil_utf8_to_path(zName, 1); |
| 718 | rc = _wrmdir(zMbcs); |
| 719 | #else |
| 720 | char *zMbcs = fossil_utf8_to_path(zName, 1); |
| 721 | rc = rmdir(zName); |
| 722 | #endif |
| 723 | fossil_path_free(zMbcs); |
| 724 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -701,10 +701,53 @@ | |
| 701 | } |
| 702 | free(zName); |
| 703 | return rc; |
| 704 | } |
| 705 | |
| 706 | #if defined(_WIN32) |
| 707 | /* |
| 708 | ** Returns non-zero if the specified name represents a real directory, i.e. |
| 709 | ** not a junction or symbolic link. This is important for some operations, |
| 710 | ** e.g. removing directories via _wrmdir(), because its detection of empty |
| 711 | ** directories will (apparently) not work right for junctions and symbolic |
| 712 | ** links, etc. |
| 713 | */ |
| 714 | int file_is_normal_dir(wchar_t *zName){ |
| 715 | /* |
| 716 | ** Mask off attributes, applicable to directories, that are harmless for |
| 717 | ** our purposes. This may need to be updated if other attributes should |
| 718 | ** be ignored by this function. |
| 719 | */ |
| 720 | DWORD dwAttributes = GetFileAttributesW(zName); |
| 721 | if( dwAttributes==INVALID_FILE_ATTRIBUTES ) return 0; |
| 722 | dwAttributes &= ~( |
| 723 | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED | |
| 724 | FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_NORMAL | |
| 725 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
| 726 | ); |
| 727 | return dwAttributes==FILE_ATTRIBUTE_DIRECTORY; |
| 728 | } |
| 729 | |
| 730 | /* |
| 731 | ** COMMAND: test-is-normal-dir |
| 732 | ** |
| 733 | ** Usage: %fossil test-is-normal-dir NAME... |
| 734 | ** |
| 735 | ** Returns non-zero if the specified names represent real directories, i.e. |
| 736 | ** not junctions, symbolic links, etc. |
| 737 | */ |
| 738 | void test_is_normal_dir(void){ |
| 739 | int i; |
| 740 | for(i=2; i<g.argc; i++){ |
| 741 | wchar_t *zMbcs = fossil_utf8_to_path(g.argv[i], 1); |
| 742 | fossil_print("ATTRS \"%s\" -> %lx\n", g.argv[i], GetFileAttributesW(zMbcs)); |
| 743 | fossil_print("ISDIR \"%s\" -> %d\n", g.argv[i], file_is_normal_dir(zMbcs)); |
| 744 | fossil_path_free(zMbcs); |
| 745 | } |
| 746 | } |
| 747 | #endif |
| 748 | |
| 749 | /* |
| 750 | ** Removes the directory named in the argument, if it exists. The directory |
| 751 | ** must be empty and cannot be the current directory or the root directory. |
| 752 | ** |
| 753 | ** Returns zero upon success. |
| @@ -713,11 +756,15 @@ | |
| 756 | int rc = file_isdir(zName, RepoFILE); |
| 757 | if( rc==2 ) return 1; /* cannot remove normal file */ |
| 758 | if( rc==1 ){ |
| 759 | #if defined(_WIN32) |
| 760 | wchar_t *zMbcs = fossil_utf8_to_path(zName, 1); |
| 761 | if( file_is_normal_dir(zMbcs) ){ |
| 762 | rc = _wrmdir(zMbcs); |
| 763 | }else{ |
| 764 | rc = ENOTDIR; /* junction, symbolic link, etc. */ |
| 765 | } |
| 766 | #else |
| 767 | char *zMbcs = fossil_utf8_to_path(zName, 1); |
| 768 | rc = rmdir(zName); |
| 769 | #endif |
| 770 | fossil_path_free(zMbcs); |
| 771 |