Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-12-07 20:40:24 +0300
committerCorinna Vinschen <corinna@vinschen.de>2006-12-07 20:40:24 +0300
commit1c9b2968fa28635d23d1a855ea9dcd15967cbe44 (patch)
treed60cd4b203346ecc8d798c757b3e332e14c9c503 /winsup
parent07ec6541ab45f78adeb2fe2be969da5d2a8d0fb2 (diff)
* 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.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog9
-rw-r--r--winsup/cygwin/ntdll.h5
-rw-r--r--winsup/cygwin/syscalls.cc200
3 files changed, 124 insertions, 90 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 49e344333..5815dc1ca 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,14 @@
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.
* syscalls.cc (try_to_bin): New function trying to move a file to
the recycle bin.
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 0855a878e..a72965905 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -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;
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 3113ac6b3..1e23323e7 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -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;