OSDN Git Service

* syscalls.cc (unlink_nt): First remove the R/O DOS attribute with
authorcorinna <corinna>
Thu, 16 Jul 2009 16:55:25 +0000 (16:55 +0000)
committercorinna <corinna>
Thu, 16 Jul 2009 16:55:25 +0000 (16:55 +0000)
FILE_WRITE_ATTRIBUTES access only, then re-open the file for DELETE.
Explain why.

winsup/cygwin/ChangeLog
winsup/cygwin/syscalls.cc

index ec9228a..3fd808e 100644 (file)
@@ -1,5 +1,11 @@
 2009-07-16  Corinna Vinschen  <corinna@vinschen.de>
 
+       * syscalls.cc (unlink_nt): First remove the R/O DOS attribute with
+       FILE_WRITE_ATTRIBUTES access only, then re-open the file for DELETE.
+       Explain why.
+
+2009-07-16  Corinna Vinschen  <corinna@vinschen.de>
+
        * fhandler_disk_file.cc (fhandler_disk_file::fchmod): Remove file
        attribute check already done in NtSetAttributesFile.
 
index 1bb6007..14dd884 100644 (file)
@@ -445,17 +445,13 @@ NTSTATUS
 unlink_nt (path_conv &pc)
 {
   NTSTATUS status;
-  HANDLE fh;
+  HANDLE fh, fh_ro = NULL;
   OBJECT_ATTRIBUTES attr;
   IO_STATUS_BLOCK io;
 
-  ACCESS_MASK access = DELETE;
-  /* If the R/O attribute is set, we have to open the file with
-     FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
-     to delete it. */
-  if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
-    access |= FILE_WRITE_ATTRIBUTES;
+  bin_status bin_stat = dont_move;
 
+  ACCESS_MASK access = DELETE;
   ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
   /* Add the reparse point flag to native symlinks, otherwise we remove the
      target, not the symlink. */
@@ -463,13 +459,31 @@ unlink_nt (path_conv &pc)
     flags |= FILE_OPEN_REPARSE_POINT;
 
   pc.get_object_attr (attr, sec_none_nih);
+  /* If the R/O attribute is set, we have to open the file with
+     FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
+     to delete it.  We do this separately because there are filesystems
+     out there (MVFS), which refuse a request to open a file for DELETE
+     if the DOS R/O attribute is set for the file.  After removing the R/O
+     attribute, just re-open the file for DELETE and go ahead. */
+  if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
+    {
+      access |= FILE_WRITE_ATTRIBUTES;
+      status = NtOpenFile (&fh_ro, FILE_WRITE_ATTRIBUTES, &attr, &io,
+                          FILE_SHARE_VALID_FLAGS, flags);
+      if (NT_SUCCESS (status))
+       {
+         NtSetAttributesFile (fh_ro, pc.file_attributes ()
+                                     & ~FILE_ATTRIBUTE_READONLY);
+         InitializeObjectAttributes (&attr, &ro_u_empty,
+                                     pc.objcaseinsensitive (), fh_ro, NULL);
+       }
+    }
   /* First try to open the file with only allowing sharing for delete.  If
      the file has an open handle on it, other than just for deletion, this
      will fail.  That indicates that the file has to be moved to the recycle
      bin so that it actually disappears from its directory even though its
      in use.  Otherwise, if opening doesn't fail, the file is not in use and
      we can go straight to setting the delete disposition flag. */
-  bin_status bin_stat = dont_move;
   status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_DELETE, flags);
   if (status == STATUS_SHARING_VIOLATION || status == STATUS_LOCK_NOT_GRANTED)
     {
@@ -512,11 +526,15 @@ unlink_nt (path_conv &pc)
              if (!NT_SUCCESS (status))
                {
                  NtClose (fh);
+                 if (fh_ro)
+                   NtClose (fh_ro);
                  return status;
                }
            }
        }
     }
+  if (fh_ro)
+    NtClose (fh_ro);
   if (!NT_SUCCESS (status))
     {
       if (status == STATUS_DELETE_PENDING)
@@ -527,9 +545,6 @@ unlink_nt (path_conv &pc)
       syscall_printf ("Opening file for delete failed, status = %p", status);
       return status;
     }
-  /* Get rid of read-only attribute. */
-  if (access & FILE_WRITE_ATTRIBUTES)
-    NtSetAttributesFile (fh, pc.file_attributes () & ~FILE_ATTRIBUTE_READONLY);
   /* Try to move to bin if a sharing violation occured.  If that worked,
      we're done. */
   if (bin_stat == move_to_bin