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);

Reply via email to