emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master caf4a01: Fix deletion of symlinks to directories on


From: Eli Zaretskii
Subject: [Emacs-diffs] master caf4a01: Fix deletion of symlinks to directories on MS-Windows
Date: Mon, 07 Sep 2015 15:27:40 +0000

branch: master
commit caf4a0192621f49b677ad05fe86e358020a88b7e
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    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.
---
 src/w32.c |   33 +++++++++++++++++++++++++++++----
 1 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/w32.c b/src/w32.c
index cc55507..bb51496 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -4534,6 +4534,8 @@ sys_rmdir (const char * path)
 int
 sys_unlink (const char * path)
 {
+  int rmstatus, e;
+
   path = map_w32_filename (path, NULL);
 
   if (w32_unicode_filenames)
@@ -4541,9 +4543,18 @@ sys_unlink (const char * path)
       wchar_t path_w[MAX_PATH];
 
       filename_to_utf16 (path, path_w);
-      /* On Unix, unlink works without write permission. */
+      /* On Unix, unlink works without write permission.  */
       _wchmod (path_w, 0666);
-      return _wunlink (path_w);
+      rmstatus = _wunlink (path_w);
+      e = errno;
+      /* Symlinks to directories can only be deleted by _rmdir;
+        _unlink returns EACCES.  */
+      if (rmstatus != 0
+         && errno == EACCES
+         && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+       rmstatus = _wrmdir (path_w);
+      else
+       errno = e;
     }
   else
     {
@@ -4551,8 +4562,17 @@ sys_unlink (const char * path)
 
       filename_to_ansi (path, path_a);
       _chmod (path_a, 0666);
-      return _unlink (path_a);
+      rmstatus = _unlink (path_a);
+      e = errno;
+      if (rmstatus != 0
+         && errno == EACCES
+         && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
+       rmstatus = _rmdir (path_a);
+      else
+       errno = e;
     }
+
+  return rmstatus;
 }
 
 static FILETIME utc_base_ft;
@@ -5626,7 +5646,8 @@ symlink (char const *filename, char const *linkname)
 /* A quick inexpensive test of whether FILENAME identifies a file that
    is a symlink.  Returns non-zero if it is, zero otherwise.  FILENAME
    must already be in the normalized form returned by
-   map_w32_filename.
+   map_w32_filename.  If the symlink is to a directory, the
+   FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
 
    Note: for repeated operations on many files, it is best to test
    whether the underlying volume actually supports symlinks, by
@@ -5684,6 +5705,8 @@ is_symlink (const char *filename)
       attrs_mean_symlink =
        (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
        && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == 
IO_REPARSE_TAG_SYMLINK;
+      if (attrs_mean_symlink)
+       attrs_mean_symlink |= (wfdw.dwFileAttributes & 
FILE_ATTRIBUTE_DIRECTORY);
     }
   else if (_mbspbrk (filename_a, "?"))
     {
@@ -5697,6 +5720,8 @@ is_symlink (const char *filename)
       attrs_mean_symlink =
        (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
        && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == 
IO_REPARSE_TAG_SYMLINK;
+      if (attrs_mean_symlink)
+       attrs_mean_symlink |= (wfda.dwFileAttributes & 
FILE_ATTRIBUTE_DIRECTORY);
     }
   if (fh == INVALID_HANDLE_VALUE)
     return 0;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]