* ntdll.h: Reorder NT status flags. Fix a case difference. Add

STATUS_CANNOT_DELETE flag.
	* syscalls.cc (unlink_nt): Change initial NtOpenFile to request
	FILE_SHARE_DELETE sharing mode.  Change comment accordingly.
	If setting delete disposition failed with STATUS_CANNOT_DELETE, try
	to delete using delete-on-close.  Explain why.
	Rearrange setting R/O DOS attribute after trying to delete.  Simplify
	comment.
This commit is contained in:
Corinna Vinschen 2009-01-07 18:18:23 +00:00
parent 3bee7767a8
commit f4ad04049f
3 changed files with 57 additions and 15 deletions

View File

@ -1,3 +1,14 @@
2009-01-07 Corinna Vinschen <corinna@vinschen.de>
* ntdll.h: Reorder NT status flags. Fix a case difference. Add
STATUS_CANNOT_DELETE flag.
* syscalls.cc (unlink_nt): Change initial NtOpenFile to request
FILE_SHARE_DELETE sharing mode. Change comment accordingly.
If setting delete disposition failed with STATUS_CANNOT_DELETE, try
to delete using delete-on-close. Explain why.
Rearrange setting R/O DOS attribute after trying to delete. Simplify
comment.
2009-01-07 Corinna Vinschen <corinna@vinschen.de>
* fhandler_disk_file.cc (fhandler_disk_file::link): Only add .exe if

View File

@ -8,6 +8,7 @@
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106)
#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000)
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005)
#define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006)
@ -28,7 +29,7 @@
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A)
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
#define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004f)
#define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xc000004f)
#define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xc0000050)
#define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xc0000051)
#define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xc0000052)
@ -37,7 +38,7 @@
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
#define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xc00000bb)
#define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xc0000101)
#define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106)
#define STATUS_CANNOT_DELETE ((NTSTATUS) 0xc0000121)
#define STATUS_INVALID_LEVEL ((NTSTATUS) 0xc0000148)
#define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xc0000135)
#define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xc0000139)

View File

@ -405,14 +405,14 @@ unlink_nt (path_conv &pc)
flags |= FILE_OPEN_REPARSE_POINT;
pc.get_object_attr (attr, sec_none_nih);
/* First try to open the file with sharing not allowed. If the file
has an open handle on it, 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 by simply closing the handle
the file will disappear. */
/* 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. */
bool move_to_bin = false;
status = NtOpenFile (&fh, access, &attr, &io, 0, flags);
status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_DELETE, flags);
if (status == STATUS_SHARING_VIOLATION)
{
move_to_bin = true;
@ -470,16 +470,46 @@ unlink_nt (path_conv &pc)
FileDispositionInformation);
if (!NT_SUCCESS (status))
{
syscall_printf ("Setting delete disposition failed, status = %p", status);
/* Restore R/O attributes. */
if (access & FILE_WRITE_ATTRIBUTES)
NtSetAttributesFile (fh, pc.file_attributes ());
syscall_printf ("Setting delete disposition failed, status = %p",
status);
/* Trying to delete a hardlink to a file in use by the system in some
way (for instance, font files) by setting the delete disposition fails
with STATUS_CANNOT_DELETE. Strange enough, deleting these hardlinks
using delete-on-close semantic works.
Don't use delete-on-close on remote shares. If two processes
have open handles on a file and one of them calls unlink, the
file is removed from the remote share even though the other
process still has an open handle. That process than gets Win32
error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
Microsoft KB 837665 describes this problem as a bug in 2K3, but
I have reproduced it on other systems. */
if (status == STATUS_CANNOT_DELETE && !pc.isremote ())
{
HANDLE fh2;
UNICODE_STRING fname;
/* Re-open from handle so we open the correct file no matter if it
has been moved to the bin or not. */
RtlInitUnicodeString (&fname, L"");
InitializeObjectAttributes (&attr, &fname, 0, fh, NULL);
status = NtOpenFile (&fh2, DELETE, &attr, &io,
move_to_bin ? FILE_SHARE_VALID_FLAGS
: FILE_SHARE_DELETE,
flags | FILE_DELETE_ON_CLOSE);
if (!NT_SUCCESS (status))
syscall_printf ("Setting delete-on-close failed, status = %p",
status);
else
NtClose (fh2);
}
}
else if ((access & FILE_WRITE_ATTRIBUTES) && !pc.isdir ())
if ((access & FILE_WRITE_ATTRIBUTES)
&& (!NT_SUCCESS (status) || !pc.isdir ()))
{
/* Restore R/O attribute to accommodate hardlinks. Don't try this
with directories! For some reason the below NtSetInformationFile
changes the disposition for delete back to FALSE, at least on XP. */
changes the delete disposition back to FALSE, at least on XP. */
NtSetAttributesFile (fh, pc.file_attributes ());
}