]> sourceware.org Git - newlib-cygwin.git/commitdiff
* ntdll.h (STATUS_DELETE_PENDING): Define.
authorCorinna Vinschen <corinna@vinschen.de>
Thu, 7 Dec 2006 17:40:24 +0000 (17:40 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Thu, 7 Dec 2006 17:40:24 +0000 (17:40 +0000)
(struct _FILE_DISPOSITION_INFORMATION): Define.
* syscalls.cc (unlink_9x): new function to delete file on 9x.
* syscalls.cc (unlink_nt): new function to delete file on NT.
(unlink): Simplify.  Move OS dependent stuff into aforementioned
functions.  Also handle FILE_ATTRIBUTE_HIDDEN as R/O-like flag.

winsup/cygwin/ChangeLog
winsup/cygwin/ntdll.h
winsup/cygwin/syscalls.cc

index 49e3443331a3793b0b8e7c207e5df67d29002468..5815dc1cad0e6d167a0d7b5496c6e8fb333a70bf 100644 (file)
@@ -1,3 +1,12 @@
+2006-12-07  Corinna Vinschen  <corinna@vinschen.de>
+
+       * ntdll.h (STATUS_DELETE_PENDING): Define.
+       (struct _FILE_DISPOSITION_INFORMATION): Define.
+       * syscalls.cc (unlink_9x): new function to delete file on 9x.
+       * syscalls.cc (unlink_nt): new function to delete file on NT.
+       (unlink): Simplify.  Move OS dependent stuff into aforementioned
+       functions.  Also handle FILE_ATTRIBUTE_HIDDEN as R/O-like flag.
+
 2006-12-07  Corinna Vinschen  <corinna@vinschen.de>
 
        * autoload.cc (SHFileOperationA): Define.
index 0855a878e3f7636852a8e679c89560921d4a1cbf..a7296590566795faafbbc0bf03ab16075b97a169 100644 (file)
@@ -16,6 +16,7 @@
 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
 #define STATUS_INVALID_PARAMETER    ((NTSTATUS) 0xc000000d)
 #define STATUS_BUFFER_TOO_SMALL     ((NTSTATUS) 0xc0000023)
+#define STATUS_DELETE_PENDING       ((NTSTATUS) 0xc0000056)
 #define STATUS_WORKING_SET_QUOTA    ((NTSTATUS) 0xc00000a1L)
 #define STATUS_INVALID_LEVEL        ((NTSTATUS) 0xc0000148)
 #define STATUS_NO_MORE_FILES       ((NTSTATUS)0x80000006L)
@@ -480,6 +481,10 @@ typedef struct _FILE_ACCESS_INFORMATION {
   ACCESS_MASK AccessFlags;
 } FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
 
+typedef struct _FILE_DISPOSITION_INFORMATION {
+  BOOLEAN DeleteFile;
+} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
+
 typedef struct _FILE_POSITION_INFORMATION {
   LARGE_INTEGER CurrentByteOffset;
 } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
index 3113ac6b3dd4a65ed6767831c763683d3505c0ac..1e23323e7c2bb94985982d510c575297efafda4e 100644 (file)
@@ -46,6 +46,8 @@ details. */
 #include <lmcons.h> /* for UNLEN */
 #include <rpc.h>
 #include <shellapi.h>
+#include <ntdef.h>
+#include "ntdll.h"
 
 #undef fstat
 #undef lstat
@@ -173,6 +175,89 @@ try_to_bin (const char *win32_path)
   debug_printf ("SHFileOperation (%s) = %d\n", win32_path, ret);
 }
 
+static DWORD
+unlink_9x (path_conv &win32_name)
+{
+  BOOL ret = DeleteFile (win32_name);
+  syscall_printf ("DeleteFile %s", ret ? "succeeded" : "failed");
+  return GetLastError ();
+}
+
+static DWORD
+unlink_nt (path_conv &win32_name, bool setattrs)
+{
+  WCHAR wpath[CYG_MAX_PATH + 10];
+  UNICODE_STRING upath = {0, sizeof (wpath), wpath};
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  NTSTATUS status;
+  HANDLE h;
+
+  ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
+  /* Don't try "delete on close" if the file is on a remote share.  If two
+     processes have open handles on a file and one of them calls unlink,
+     then it happens that the file is remove from the remote share even
+     though the other process still has an open handle.  This other process
+     than gets Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the
+     file.
+     That does not happen when using DeleteFile, which nicely succeeds but
+     still, the file is available for the other process.
+     Microsoft KB 837665 describes this problem as a bug in 2K3, but I have
+     reproduced it on shares on Samba 2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and
+     2K3 and in all cases, DeleteFile works, "delete on close" does not. */
+  if (!win32_name.isremote ())
+    flags |= FILE_DELETE_ON_CLOSE;
+
+  win32_name.get_nt_native_path (upath);
+  InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+                             NULL, sec_none_nih.lpSecurityDescriptor);
+  status = NtOpenFile (&h, DELETE, &attr, &io, wincap.shared (), flags);
+  if (!NT_SUCCESS (status))
+    {
+      if (status == STATUS_DELETE_PENDING)
+       {
+         syscall_printf ("Delete already pending, status = %p", status);
+         return 0;
+       }
+      syscall_printf ("Opening file for delete failed, status = %p", status);
+      return RtlNtStatusToDosError (status);
+    }
+
+  if (setattrs)
+    SetFileAttributes (win32_name, (DWORD) win32_name);
+
+  if (!win32_name.isremote ())
+    try_to_bin (win32_name.get_win32 ());
+
+  DWORD lasterr = 0;
+
+  if (win32_name.isremote ())
+    {
+      FILE_DISPOSITION_INFORMATION disp = { TRUE };
+      status = NtSetInformationFile (h, &io, &disp, sizeof disp,
+                                    FileDispositionInformation);
+      if (!NT_SUCCESS (status))
+       {
+         syscall_printf ("Setting delete disposition failed, status = %p",
+                         status);
+         lasterr = RtlNtStatusToDosError (status);
+       }
+    }
+
+  status = NtClose (h);
+  if (!NT_SUCCESS (status))
+    {
+      /* Maybe that's really paranoid, but not being able to close the file
+        also means that deleting fails. */
+      syscall_printf ("%p = NtClose (%p)", status, h);
+      if (!lasterr)
+        RtlNtStatusToDosError (status);
+    }
+
+  syscall_printf ("Deleting succeeded");
+  return lasterr;
+}
+
 extern "C" int
 unlink (const char *ourname)
 {
@@ -211,7 +296,9 @@ unlink (const char *ourname)
     }
 
   bool setattrs;
-  if (!((DWORD) win32_name & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
+  if (!((DWORD) win32_name & (FILE_ATTRIBUTE_READONLY
+                             | FILE_ATTRIBUTE_SYSTEM
+                             | FILE_ATTRIBUTE_HIDDEN)))
     setattrs = false;
   else
     {
@@ -219,101 +306,34 @@ unlink (const char *ourname)
       setattrs = SetFileAttributes (win32_name,
                                    (DWORD) win32_name
                                    & ~(FILE_ATTRIBUTE_READONLY
-                                       | FILE_ATTRIBUTE_SYSTEM));
+                                       | FILE_ATTRIBUTE_SYSTEM
+                                       | FILE_ATTRIBUTE_HIDDEN));
     }
-  /* Attempt to use "delete on close" semantics to handle removing
-     a file which may be open.
 
-     CV 2004-09-17: Not if the file is on a remote share.  If two processes
-     have open handles on a file and one of them calls unlink, then it
-     happens that the file is remove from the remote share even though the
-     other process still has an open handle.  This other process than gets
-     Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
-
-     For some reason, that does not happen when using DeleteFile, which
-     nicely succeeds but still, the file is available for the other process.
-     To reproduce, mount /tmp on a remote share and call
-
-       bash -c "cat << EOF"
+  DWORD lasterr;
+  lasterr = wincap.is_winnt () ? unlink_nt (win32_name, setattrs)
+                              : unlink_9x (win32_name);
+  if (!lasterr)
+    res = 0;
+  else
+    {
+      SetFileAttributes (win32_name, (DWORD) win32_name);
 
-     Microsoft KB 837665 describes this problem as a bug in 2K3, but I have
-     reproduced it on shares on Samba 2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and
-     2K3 and in all cases, DeleteFile works, "delete on close" does not. */
-  if (!win32_name.isremote () && wincap.has_delete_on_close ())
-    {
-      HANDLE h;
-      DWORD flags = FILE_FLAG_DELETE_ON_CLOSE;
-      if (win32_name.is_rep_symlink ())
-        flags |= FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS;
-      h = CreateFile (win32_name, DELETE, wincap.shared (), &sec_none_nih,
-                     OPEN_EXISTING, flags, 0);
-      if (h != INVALID_HANDLE_VALUE)
-       {
-         if (wincap.has_hard_links () && setattrs)
-           SetFileAttributes (win32_name, (DWORD) win32_name);
-         try_to_bin (win32_name.get_win32 ());
-         BOOL res = CloseHandle (h);
-         syscall_printf ("%d = CloseHandle (%p)", res, h);
-         if (GetFileAttributes (win32_name) == INVALID_FILE_ATTRIBUTES
-             || !win32_name.isremote ())
-           {
-             syscall_printf ("CreateFile (FILE_FLAG_DELETE_ON_CLOSE) succeeded");
-             goto ok;
-           }
-         else
-           {
-             syscall_printf ("CreateFile (FILE_FLAG_DELETE_ON_CLOSE) failed");
-             if (setattrs)
-               SetFileAttributes (win32_name, (DWORD) win32_name & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM));
-           }
+      /* Windows 9x seems to report ERROR_ACCESS_DENIED rather than sharing
+        violation. */
+      if ((wincap.access_denied_on_delete () && lasterr == ERROR_ACCESS_DENIED
+          && !win32_name.isremote ())
+         || lasterr == ERROR_SHARING_VIOLATION)
+        {
+         /* Add file to the "to be deleted" queue. */
+         syscall_printf ("Sharing violation, couldn't delete file");
+         user_shared->delqueue.queue_file (win32_name);
+         res = 0;
        }
+      else
+       __seterrno_from_win_error (lasterr);
     }
 
-  /* Try a delete with attributes reset */
-  if (win32_name.is_rep_symlink () && RemoveDirectory (win32_name))
-    {
-      syscall_printf ("RemoveDirectory after CreateFile/CloseHandle succeeded");
-      goto ok;
-    }
-  else if (DeleteFile (win32_name))
-    {
-      syscall_printf ("DeleteFile after CreateFile/CloseHandle succeeded");
-      goto ok;
-    }
-
-  DWORD lasterr;
-  lasterr = GetLastError ();
-
-  SetFileAttributes (win32_name, (DWORD) win32_name);
-
-  /* Windows 9x seems to report ERROR_ACCESS_DENIED rather than sharing
-     violation.  So, set lasterr to ERROR_SHARING_VIOLATION in this case
-     to simplify tests. */
-  if (wincap.access_denied_on_delete () && lasterr == ERROR_ACCESS_DENIED
-      && !win32_name.isremote ())
-    lasterr = ERROR_SHARING_VIOLATION;
-
-  /* FILE_FLAGS_DELETE_ON_CLOSE was a bust.  If this is a sharing
-     violation, then queue the file for deletion when the process
-     exits.  Otherwise, punt. */
-  if (lasterr != ERROR_SHARING_VIOLATION)
-    goto err;
-
-  syscall_printf ("couldn't delete file, err %d", lasterr);
-
-  /* Add file to the "to be deleted" queue. */
-  user_shared->delqueue.queue_file (win32_name);
-
- /* Success condition. */
- ok:
-  res = 0;
-  goto done;
-
- /* Error condition. */
- err:
-  __seterrno ();
-  res = -1;
-
  done:
   syscall_printf ("%d = unlink (%s)", res, ourname);
   return res;
This page took 0.047293 seconds and 5 git commands to generate.