https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=7ae73be14194ccadc9a7557be33c3940ca4667cb
commit 7ae73be14194ccadc9a7557be33c3940ca4667cb Author: Corinna Vinschen <cori...@vinschen.de> Date: Wed Feb 14 12:55:24 2018 +0100 Cygwin: improve O_TMPFILE handling Windows does not remove FILE_ATTRIBUTE_TEMPORARY by itself after a file has been closed. It's just some attribute which can be set or removed at will, despite its purpose. Apparently there are tools out there which use FILE_ATTRIBUTE_TEMPORARY accidentally or wrongly, even Microsoft's own tools are affected. In the end, the filesystem is potentially full of files with this attribute set. Implement O_TMPFILE files with FILE_ATTRIBUTE_TEMPORARY and FILE_ATTRIBUTE_HIDDEN set. This combination is pretty unlikely. Signed-off-by: Corinna Vinschen <cori...@vinschen.de> Diff: --- winsup/cygwin/fhandler.cc | 7 +++++-- winsup/cygwin/fhandler.h | 2 ++ winsup/cygwin/fhandler_disk_file.cc | 33 ++++++++++++++++++++++----------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 7da1c4e..086be73 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -603,11 +603,14 @@ fhandler_base::open (int flags, mode_t mode) as with FILE_ATTRIBUTE_TEMPORARY. The latter speeds up file access, because the OS tries to keep the file in memory as much as possible. In conjunction with FILE_DELETE_ON_CLOSE, ideally the OS never has - to write to the disk at all. */ + to write to the disk at all. + Note that O_TMPFILE_FILE_ATTRS also sets the DOS HIDDEN attribute + to help telling Cygwin O_TMPFILE files apart from other files + accidentally setting FILE_ATTRIBUTE_TEMPORARY. */ if (flags & O_TMPFILE) { access |= DELETE; - file_attributes |= FILE_ATTRIBUTE_TEMPORARY; + file_attributes |= O_TMPFILE_FILE_ATTRS; options |= FILE_DELETE_ON_CLOSE; } diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index a446e75..9d2b263 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -37,6 +37,8 @@ details. */ never be used in Cygwin for this function. */ #define PIPE_ADD_PID FILE_FLAG_FIRST_PIPE_INSTANCE +#define O_TMPFILE_FILE_ATTRS (FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN) + extern const char *windows_device_names[]; extern struct __cygwin_perfile *perfile_table; #define __fmode (*(user_data->fmode_ptr)) diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index f079965..cb6be25 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1243,16 +1243,28 @@ fhandler_disk_file::link (const char *newpath) __seterrno_from_nt_status (status); return -1; } - else if (pc.file_attributes () & FILE_ATTRIBUTE_TEMPORARY) - { - /* If the original file has been opened with O_TMPFILE the file has - FILE_ATTRIBUTE_TEMPORARY set. After a successful hardlink the - file is not temporary anymore in the usual sense. So we remove - FILE_ATTRIBUTE_TEMPORARY here, even if this makes the original file - visible in directory enumeration. */ + else if ((pc.file_attributes () & O_TMPFILE_FILE_ATTRS) + == O_TMPFILE_FILE_ATTRS) + { + /* An O_TMPFILE file has FILE_ATTRIBUTE_TEMPORARY and + FILE_ATTRIBUTE_HIDDEN set. After a successful hardlink the file is + not temporary anymore in the usual sense. So we remove these + attributes here, even if this makes the original link (temporarily) + visible in directory enumeration. + + Note that we don't create a reopen attribute for the original + link but rather a normal attribute for the just created link. + The reason is a curious behaviour of Windows: If we remove + the O_TMPFILE attributes on the original link, the new link + will not show up in file system listings, long after the original + link has been closed and removed. The file and its metadata will + be kept in memory only as long as Windows sees fit. By opening + the new link, we request the attribute changes on the new link, + so after closing it Windows will have an increased interest to + write back the metadata. */ OBJECT_ATTRIBUTES attr; status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES, - pc.init_reopen_attr (attr, fh), &io, + newpc.get_object_attr (attr, sec_none_nih), &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); if (!NT_SUCCESS (status)) debug_printf ("Opening for removing TEMPORARY attrib failed, " @@ -1263,8 +1275,7 @@ fhandler_disk_file::link (const char *newpath) fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart = fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL; - fbi.FileAttributes = (pc.file_attributes () - & ~FILE_ATTRIBUTE_TEMPORARY) + fbi.FileAttributes = (pc.file_attributes () & ~O_TMPFILE_FILE_ATTRS) ?: FILE_ATTRIBUTE_NORMAL; status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi, FileBasicInformation); @@ -2213,7 +2224,7 @@ go_ahead: } /* We don't show O_TMPFILE files in the filesystem. This is a kludge, so we may end up removing this snippet again. */ - if (FileAttributes & FILE_ATTRIBUTE_TEMPORARY) + if ((FileAttributes & O_TMPFILE_FILE_ATTRS) == O_TMPFILE_FILE_ATTRS) goto restart; RtlInitCountedUnicodeString (&fname, FileName, FileNameLength); d_mounts (dir)->check_mount (&fname);