https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=0aa99373c1d01b19a7f8ba53e8c7749358480f3e

commit 0aa99373c1d01b19a7f8ba53e8c7749358480f3e
Author: Corinna Vinschen <[email protected]>
Date:   Tue Nov 14 21:28:45 2017 +0100

    Cygwin: fcntl.h: Define O_TMPFILE and implement it
    
    Difference to Linux: We can't create files which don't show up
    in the filesystem due to OS restrictions.  As a kludge, make a
    (half-hearted) attempt to hide the file in the filesystem.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 newlib/libc/include/sys/_default_fcntl.h |  2 ++
 winsup/cygwin/fhandler.cc                | 21 +++++++++++++--
 winsup/cygwin/fhandler_disk_file.cc      | 39 +++++++++++++++++++++++++++-
 winsup/cygwin/syscalls.cc                | 44 ++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+), 3 deletions(-)

diff --git a/newlib/libc/include/sys/_default_fcntl.h 
b/newlib/libc/include/sys/_default_fcntl.h
index ede90c4..0958075 100644
--- a/newlib/libc/include/sys/_default_fcntl.h
+++ b/newlib/libc/include/sys/_default_fcntl.h
@@ -52,6 +52,7 @@ extern "C" {
 #define _FNOFOLLOW      0x100000
 #define _FDIRECTORY     0x200000
 #define _FEXECSRCH      0x400000
+#define _FTMPFILE       0x800000
 
 #define O_BINARY       _FBINARY
 #define O_TEXT         _FTEXT
@@ -63,6 +64,7 @@ extern "C" {
 #define O_DIRECTORY     _FDIRECTORY
 #define O_EXEC          _FEXECSRCH
 #define O_SEARCH        _FEXECSRCH
+#define O_TMPFILE      _FTMPFILE
 #endif
 
 #if __MISC_VISIBLE
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 5b7d002..7e8f509 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -137,6 +137,11 @@ fhandler_base::set_name (path_conv &in_pc)
 
 char *fhandler_base::get_proc_fd_name (char *buf)
 {
+  /* If the file had been opened with O_TMPFILE | O_EXCL, don't
+     expose the filename.  linkat is supposed to return ENOENT in this
+     case.  See man 2 open on Linux. */
+  if ((get_flags () & (O_TMPFILE | O_EXCL)) == (O_TMPFILE | O_EXCL))
+    return strcpy (buf, "");
   if (get_name ())
     return strcpy (buf, get_name ());
   if (dev ().name ())
@@ -582,7 +587,7 @@ fhandler_base::open (int flags, mode_t mode)
 
   /* Don't use the FILE_OVERWRITE{_IF} flags here.  See below for an
      explanation, why that's not such a good idea. */
-  if ((flags & O_EXCL) && (flags & O_CREAT))
+  if (((flags & O_EXCL) && (flags & O_CREAT)) || (flags & O_TMPFILE))
     create_disposition = FILE_CREATE;
   else
     create_disposition = (flags & O_CREAT) ? FILE_OPEN_IF : FILE_OPEN;
@@ -594,6 +599,18 @@ fhandler_base::open (int flags, mode_t mode)
       if (pc.is_rep_symlink ())
        options |= FILE_OPEN_REPARSE_POINT;
 
+      /* O_TMPFILE files are created with delete-on-close semantics, as well
+        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. */
+      if (flags & O_TMPFILE)
+       {
+         access |= DELETE;
+         file_attributes |= FILE_ATTRIBUTE_TEMPORARY;
+         options |= FILE_DELETE_ON_CLOSE;
+       }
+
       if (pc.fs_is_nfs ())
        {
          /* Make sure we can read EAs of files on an NFS share.  Also make
@@ -617,7 +634,7 @@ fhandler_base::open (int flags, mode_t mode)
          && has_attribute (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
        file_attributes |= pc.file_attributes ();
 
-      if (flags & O_CREAT)
+      if (flags & (O_CREAT | O_TMPFILE))
        {
          file_attributes |= FILE_ATTRIBUTE_NORMAL;
 
diff --git a/winsup/cygwin/fhandler_disk_file.cc 
b/winsup/cygwin/fhandler_disk_file.cc
index 8f57952..2f96740 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -1248,6 +1248,37 @@ fhandler_disk_file::link (const char *newpath)
          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. */
+      OBJECT_ATTRIBUTES attr;
+      status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
+                          pc.init_reopen_attr (attr, fh), &io,
+                          FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
+      if (!NT_SUCCESS (status))
+       debug_printf ("Opening for removing TEMPORARY attrib failed, "
+                     "status = %y", status);
+      else
+       {
+         FILE_BASIC_INFORMATION fbi;
+
+         fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart
+         = fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
+         fbi.FileAttributes = (pc.file_attributes ()
+                               & ~FILE_ATTRIBUTE_TEMPORARY)
+                              ?: FILE_ATTRIBUTE_NORMAL;
+         status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
+                                        FileBasicInformation);
+         if (!NT_SUCCESS (status))
+           debug_printf ("Removing the TEMPORARY attrib failed, status = %y",
+                         status);
+         NtClose (fh);
+       }
+    }
   return 0;
 }
 
@@ -2064,12 +2095,14 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
   PFILE_ID_BOTH_DIR_INFORMATION buf = NULL;
   PWCHAR FileName;
   ULONG FileNameLength;
-  ULONG FileAttributes = 0;
+  ULONG FileAttributes;
   IO_STATUS_BLOCK io;
   UNICODE_STRING fname;
 
   /* d_cachepos always refers to the next cache entry to use.  If it's 0
      we must reload the cache. */
+restart:
+  FileAttributes = 0;
   if (d_cachepos (dir) == 0)
     {
       if ((dir->__flags & dirent_get_d_ino))
@@ -2183,6 +2216,10 @@ go_ahead:
          FileAttributes =
                ((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes;
        }
+      /* 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)
+       goto restart;
       RtlInitCountedUnicodeString (&fname, FileName, FileNameLength);
       d_mounts (dir)->check_mount (&fname);
       if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index aa796d3..c0bc3cc 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -36,6 +36,7 @@ details. */
 #include <unistd.h>
 #include <sys/wait.h>
 #include <dirent.h>
+#include <ntsecapi.h>
 #include "ntdll.h"
 
 #undef fstat
@@ -1415,6 +1416,49 @@ open (const char *unix_path, int flags, ...)
          set_errno (EEXIST);
          __leave;
        }
+      if (flags & O_TMPFILE)
+       {
+         if ((flags & O_ACCMODE) != O_WRONLY && (flags & O_ACCMODE) != O_RDWR)
+           {
+             set_errno (EINVAL);
+             __leave;
+           }
+         if (!fh->pc.isdir ())
+           {
+             set_errno (fh->exists () ? ENOTDIR : ENOENT);
+             __leave;
+           }
+         /* Unfortunately Windows does not allow to create a nameless file.
+            So create unique filename instead.  It starts with ".cyg_tmp_",
+            followed by an 8 byte unique hex number, followed by an 8 byte
+            random hex number. */
+         int64_t rnd;
+         fhandler_base *fh_file;
+         char *new_path;
+
+         new_path = (char *) malloc (strlen (fh->get_name ())
+                                     + 1  /* slash */
+                                     + 10 /* prefix */
+                                     + 16 /* 64 bit unique id as hex*/
+                                     + 16 /* 64 bit random number as hex */
+                                     + 1  /* trailing NUL */);
+         if (!new_path)
+           __leave;
+         fh->set_unique_id ();
+         RtlGenRandom (&rnd, sizeof rnd);
+         __small_sprintf (new_path, "%s/%s%016X%016X",
+                          fh->get_name (), ".cyg_tmp_",
+                          fh->get_unique_id (), rnd);
+
+         if (!(fh_file = build_fh_name (new_path, opt, NULL)))
+           {
+             free (new_path);
+             __leave;          /* errno already set */
+           }
+         delete fh;
+         fh = fh_file;
+       }
+
       if ((fh->is_fs_special () && fh->device_access_denied (flags))
          || !fh->open_with_arch (flags, mode & 07777))
        __leave;                /* errno already set */

Reply via email to