* syscalls.cc (start_transaction): Make inline function. Move up to be
more generally available. (stop_transaction): Ditto. (unlink_nt): Potentially start transaction when trying to delete file with DOS R/O attribute set. If file is .lnk symlink, check for number of hardlinks. Add "out" label and only return via "out". Rearrange reversion of DOS R/O attribute and, on success, only revert R/O attribute if file is .lnk symlink with more than one hardlink. Add length comment to explain why.
This commit is contained in:
parent
2981e56e29
commit
18df393573
|
@ -1,3 +1,15 @@
|
||||||
|
2010-09-12 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* syscalls.cc (start_transaction): Make inline function. Move up to be
|
||||||
|
more generally available.
|
||||||
|
(stop_transaction): Ditto.
|
||||||
|
(unlink_nt): Potentially start transaction when trying to delete file
|
||||||
|
with DOS R/O attribute set. If file is .lnk symlink, check for number
|
||||||
|
of hardlinks. Add "out" label and only return via "out". Rearrange
|
||||||
|
reversion of DOS R/O attribute and, on success, only revert R/O
|
||||||
|
attribute if file is .lnk symlink with more than one hardlink. Add
|
||||||
|
length comment to explain why.
|
||||||
|
|
||||||
2010-09-11 Corinna Vinschen <corinna@vinschen.de>
|
2010-09-11 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* fhandler_disk_file.cc (fhandler_disk_file::rmdir): More thoroughly
|
* fhandler_disk_file.cc (fhandler_disk_file::rmdir): More thoroughly
|
||||||
|
|
|
@ -164,6 +164,36 @@ dup3 (int oldfd, int newfd, int flags)
|
||||||
return cygheap->fdtab.dup3 (oldfd, newfd, flags);
|
return cygheap->fdtab.dup3 (oldfd, newfd, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
start_transaction (HANDLE &old_trans, HANDLE &trans)
|
||||||
|
{
|
||||||
|
NTSTATUS status = NtCreateTransaction (&trans,
|
||||||
|
SYNCHRONIZE | TRANSACTION_ALL_ACCESS,
|
||||||
|
NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
old_trans = RtlGetCurrentTransaction ();
|
||||||
|
RtlSetCurrentTransaction (trans);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug_printf ("NtCreateTransaction failed, %p", status);
|
||||||
|
old_trans = trans = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline NTSTATUS
|
||||||
|
stop_transaction (NTSTATUS status, HANDLE old_trans, HANDLE trans)
|
||||||
|
{
|
||||||
|
RtlSetCurrentTransaction (old_trans);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
status = NtCommitTransaction (trans, TRUE);
|
||||||
|
else
|
||||||
|
status = NtRollbackTransaction (trans, TRUE);
|
||||||
|
NtClose (trans);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static char desktop_ini[] =
|
static char desktop_ini[] =
|
||||||
"[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
|
"[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
|
||||||
static BYTE info2[] =
|
static BYTE info2[] =
|
||||||
|
@ -503,6 +533,9 @@ unlink_nt (path_conv &pc)
|
||||||
HANDLE fh, fh_ro = NULL;
|
HANDLE fh, fh_ro = NULL;
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES attr;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
HANDLE old_trans = NULL, trans = NULL;
|
||||||
|
ULONG num_links = 1;
|
||||||
|
FILE_DISPOSITION_INFORMATION disp = { TRUE };
|
||||||
|
|
||||||
bin_status bin_stat = dont_move;
|
bin_status bin_stat = dont_move;
|
||||||
|
|
||||||
|
@ -522,7 +555,14 @@ unlink_nt (path_conv &pc)
|
||||||
attribute, just re-open the file for DELETE and go ahead. */
|
attribute, just re-open the file for DELETE and go ahead. */
|
||||||
if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
|
if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
|
||||||
{
|
{
|
||||||
access |= FILE_WRITE_ATTRIBUTES;
|
FILE_STANDARD_INFORMATION fsi;
|
||||||
|
|
||||||
|
/* If possible, hide the non-atomicity of the "remove R/O flag, remove
|
||||||
|
link to file" operation behind a transaction. */
|
||||||
|
if (wincap.has_transactions ()
|
||||||
|
&& (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
|
||||||
|
start_transaction (old_trans, trans);
|
||||||
|
|
||||||
status = NtOpenFile (&fh_ro, FILE_WRITE_ATTRIBUTES, &attr, &io,
|
status = NtOpenFile (&fh_ro, FILE_WRITE_ATTRIBUTES, &attr, &io,
|
||||||
FILE_SHARE_VALID_FLAGS, flags);
|
FILE_SHARE_VALID_FLAGS, flags);
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
|
@ -532,6 +572,14 @@ unlink_nt (path_conv &pc)
|
||||||
InitializeObjectAttributes (&attr, &ro_u_empty,
|
InitializeObjectAttributes (&attr, &ro_u_empty,
|
||||||
pc.objcaseinsensitive (), fh_ro, NULL);
|
pc.objcaseinsensitive (), fh_ro, NULL);
|
||||||
}
|
}
|
||||||
|
if (pc.is_lnk_symlink ())
|
||||||
|
{
|
||||||
|
status = NtQueryInformationFile (fh_ro, &io, &fsi, sizeof fsi,
|
||||||
|
FileStandardInformation);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
num_links = fsi.NumberOfLinks;
|
||||||
|
}
|
||||||
|
access |= FILE_WRITE_ATTRIBUTES;
|
||||||
}
|
}
|
||||||
/* First try to open the file with only allowing sharing for delete. If
|
/* 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
|
the file has an open handle on it, other than just for deletion, this
|
||||||
|
@ -589,7 +637,7 @@ unlink_nt (path_conv &pc)
|
||||||
NtClose (fh);
|
NtClose (fh);
|
||||||
if (fh_ro)
|
if (fh_ro)
|
||||||
NtClose (fh_ro);
|
NtClose (fh_ro);
|
||||||
return status;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,18 +649,21 @@ unlink_nt (path_conv &pc)
|
||||||
if (status == STATUS_DELETE_PENDING)
|
if (status == STATUS_DELETE_PENDING)
|
||||||
{
|
{
|
||||||
syscall_printf ("Delete already pending");
|
syscall_printf ("Delete already pending");
|
||||||
return 0;
|
status = 0;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
syscall_printf ("Opening file for delete failed, status = %p", status);
|
syscall_printf ("Opening file for delete failed, status = %p", status);
|
||||||
return status;
|
goto out;
|
||||||
}
|
}
|
||||||
/* Try to move to bin if a sharing violation occured. If that worked,
|
/* Try to move to bin if a sharing violation occured. If that worked,
|
||||||
we're done. */
|
we're done. */
|
||||||
if (bin_stat == move_to_bin
|
if (bin_stat == move_to_bin
|
||||||
&& (bin_stat = try_to_bin (pc, fh, access)) == has_been_moved)
|
&& (bin_stat = try_to_bin (pc, fh, access)) == has_been_moved)
|
||||||
return 0;
|
{
|
||||||
|
status = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
/* Try to set delete disposition. */
|
/* Try to set delete disposition. */
|
||||||
FILE_DISPOSITION_INFORMATION disp = { TRUE };
|
|
||||||
status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
|
status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
|
||||||
FileDispositionInformation);
|
FileDispositionInformation);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
|
@ -661,14 +712,36 @@ unlink_nt (path_conv &pc)
|
||||||
}
|
}
|
||||||
if (fh)
|
if (fh)
|
||||||
{
|
{
|
||||||
/* Restore R/O attribute to accommodate hardlinks. Don't try this
|
if (access & FILE_WRITE_ATTRIBUTES)
|
||||||
with directories! For some reason the below NtSetInformationFile
|
{
|
||||||
changes the delete disposition back to FALSE, at least on XP. */
|
/* Restore R/O attribute if setting the delete dispostion failed. */
|
||||||
if ((access & FILE_WRITE_ATTRIBUTES)
|
if (!NT_SUCCESS (status))
|
||||||
&& (!NT_SUCCESS (status) || !pc.isdir ()))
|
NtSetAttributesFile (fh, pc.file_attributes ());
|
||||||
|
/* If we succeeded, restore R/O attribute to accommodate hardlinks.
|
||||||
|
Only ever try to do this for our own winsymlinks, because there's
|
||||||
|
a problem with setting the delete disposition:
|
||||||
|
http://msdn.microsoft.com/en-us/library/ff545765%28VS.85%29.aspx
|
||||||
|
"Subsequently, the only legal operation by such a caller is
|
||||||
|
to close the open file handle."
|
||||||
|
|
||||||
|
FIXME? On Vista and later, we could use FILE_HARD_LINK_INFORMATION
|
||||||
|
to find all hardlinks and use one of them to restore the R/O bit,
|
||||||
|
after the NtClose, but before we stop the transaction. This
|
||||||
|
avoids the aforementioned problem entirely . */
|
||||||
|
else if (pc.is_lnk_symlink () && num_links > 1)
|
||||||
NtSetAttributesFile (fh, pc.file_attributes ());
|
NtSetAttributesFile (fh, pc.file_attributes ());
|
||||||
NtClose (fh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NtClose (fh);
|
||||||
|
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
/* Stop transaction if we started one. */
|
||||||
|
if ((access & FILE_WRITE_ATTRIBUTES)
|
||||||
|
&& wincap.has_transactions ()
|
||||||
|
&& (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
|
||||||
|
stop_transaction (status, old_trans, trans);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1658,36 +1731,6 @@ rename_append_suffix (path_conv &pc, const char *path, size_t len,
|
||||||
pc.check (buf, PC_SYM_NOFOLLOW);
|
pc.check (buf, PC_SYM_NOFOLLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
start_transaction (HANDLE &old_trans, HANDLE &trans)
|
|
||||||
{
|
|
||||||
NTSTATUS status = NtCreateTransaction (&trans,
|
|
||||||
SYNCHRONIZE | TRANSACTION_ALL_ACCESS,
|
|
||||||
NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
|
|
||||||
if (NT_SUCCESS (status))
|
|
||||||
{
|
|
||||||
old_trans = RtlGetCurrentTransaction ();
|
|
||||||
RtlSetCurrentTransaction (trans);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug_printf ("NtCreateTransaction failed, %p", status);
|
|
||||||
old_trans = trans = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS
|
|
||||||
stop_transaction (NTSTATUS status, HANDLE old_trans, HANDLE trans)
|
|
||||||
{
|
|
||||||
RtlSetCurrentTransaction (old_trans);
|
|
||||||
if (NT_SUCCESS (status))
|
|
||||||
status = NtCommitTransaction (trans, TRUE);
|
|
||||||
else
|
|
||||||
status = NtRollbackTransaction (trans, TRUE);
|
|
||||||
NtClose (trans);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function tests if a filename has one of the "approved" executable
|
/* This function tests if a filename has one of the "approved" executable
|
||||||
suffix. This list is probably not complete... */
|
suffix. This list is probably not complete... */
|
||||||
static inline bool
|
static inline bool
|
||||||
|
|
Loading…
Reference in New Issue