summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2018-12-23 21:36:42 +0100
committerCorinna Vinschen <corinna@vinschen.de>2018-12-23 21:36:42 +0100
commita7f392686b5b2091e8f555ff2a2d63443e1fcb1c (patch)
treed37ead53abc737b5758193f734f1789180ed121e
parent0c25ca40ce7897e3951a91986b6381ebe6ea7d23 (diff)
downloadcygnal-a7f392686b5b2091e8f555ff2a2d63443e1fcb1c.tar.gz
cygnal-a7f392686b5b2091e8f555ff2a2d63443e1fcb1c.tar.bz2
cygnal-a7f392686b5b2091e8f555ff2a2d63443e1fcb1c.zip
Cygwin: utilize FILE_DISPOSITION_POSIX_SEMANTICS
- short-circuit most code in unlink_nt since it's not necessary anymore if FILE_DISPOSITION_POSIX_SEMANTICS is supported. - Immediately remove O_TMPFILE from filesystem after creation. Disable code for now because we have to implement /proc/self/fd opening by handle first, lest linkat fails. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r--winsup/cygwin/syscalls.cc79
1 files changed, 76 insertions, 3 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 6d1085539..c1a3ed418 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -658,23 +658,64 @@ unlink_nt (path_conv &pc)
HANDLE fh, fh_ro = NULL;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
+ ACCESS_MASK access = DELETE;
+ ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
HANDLE old_trans = NULL, trans = NULL;
ULONG num_links = 1;
FILE_DISPOSITION_INFORMATION disp = { TRUE };
int reopened = 0;
-
bin_status bin_stat = dont_move;
syscall_printf ("Trying to delete %S, isdir = %d",
pc.get_nt_native_path (), pc.isdir ());
- ACCESS_MASK access = DELETE;
- ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
+
/* Add the reparse point flag to known reparse points, otherwise we remove
the target, not the reparse point. */
if (pc.is_known_reparse_point ())
flags |= FILE_OPEN_REPARSE_POINT;
pc.get_object_attr (attr, sec_none_nih);
+
+ /* First check if we can use POSIX unlink semantics: W10 1709++, local NTFS.
+ With POSIX unlink semantics the entire job gets MUCH easier and faster.
+ Just try to do it and if it fails, it fails. */
+ if (wincap.has_posix_file_info () && !pc.isremote () && pc.fs_is_ntfs ())
+ {
+ FILE_DISPOSITION_INFORMATION_EX fdie;
+
+ if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
+ access |= FILE_WRITE_ATTRIBUTES;
+ status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_VALID_FLAGS,
+ flags);
+ if (!NT_SUCCESS (status))
+ goto out;
+ /* Why didn't the devs add a FILE_DELETE_IGNORE_READONLY_ATTRIBUTE
+ flag just like they did with FILE_LINK_IGNORE_READONLY_ATTRIBUTE
+ and FILE_LINK_IGNORE_READONLY_ATTRIBUTE???
+
+ POSIX unlink semantics are nice, but they still fail if the file
+ has the R/O attribute set. Removing the file is very much a safe
+ bet afterwards, so, no transaction. */
+ if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
+ {
+ status = NtSetAttributesFile (fh, pc.file_attributes ()
+ & ~FILE_ATTRIBUTE_READONLY);
+ if (!NT_SUCCESS (status))
+ {
+ NtClose (fh);
+ goto out;
+ }
+ }
+ fdie.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS;
+ status = NtSetInformationFile (fh, &io, &fdie, sizeof fdie,
+ FileDispositionInformationEx);
+ /* Restore R/O attribute in case we have multiple hardlinks. */
+ if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
+ NtSetAttributesFile (fh, pc.file_attributes ());
+ NtClose (fh);
+ goto out;
+ }
+
/* 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
@@ -1426,7 +1467,39 @@ open (const char *unix_path, int flags, ...)
if ((fh->is_fs_special () && fh->device_access_denied (flags))
|| !fh->open_with_arch (flags, mode & 07777))
__leave; /* errno already set */
+#if 0
+ /* W10 1709 POSIX unlink semantics:
+ TODO: Works nicely for O_TEMPFILE but using linkat requires that
+ we first fix /proc/self/fd handling to allow opening by handle
+ rather than by symlinked filename only. */
+ if ((flags & O_TMPFILE) && wincap.has_posix_file_info ()
+ && fh->pc.fs_is_ntfs ())
+ {
+ HANDLE del_h;
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ FILE_DISPOSITION_INFORMATION_EX fdie;
+
+ status = NtOpenFile (&del_h, DELETE,
+ fh->pc.init_reopen_attr (attr, fh->get_handle ()), &io,
+ FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS (status))
+ debug_printf ("reopening tmpfile handle failed, status %y", status);
+ else
+ {
+ fdie.Flags = FILE_DISPOSITION_DELETE
+ | FILE_DISPOSITION_POSIX_SEMANTICS;
+ status = NtSetInformationFile (del_h, &io, &fdie, sizeof fdie,
+ FileDispositionInformationEx);
+ if (!NT_SUCCESS (status))
+ debug_printf ("Setting POSIX delete disposition on tmpfile "
+ "failed, status = %y", status);
+ NtClose (del_h);
+ }
+ }
+#endif
fd = fh;
if (fd <= 2)
set_std_handle (fd);