]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: fcntl.h: Define O_TMPFILE and implement it
authorCorinna Vinschen <corinna@vinschen.de>
Tue, 14 Nov 2017 20:28:45 +0000 (21:28 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 14 Nov 2017 20:45:25 +0000 (21:45 +0100)
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 <corinna@vinschen.de>
newlib/libc/include/sys/_default_fcntl.h
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/syscalls.cc

index ede90c4bcd504d4d4e57e7c2aaf7f1dd8e9c2c12..09580754b26867dd89275e4060b449e510b3f088 100644 (file)
@@ -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
index 5b7d002bd87557503bff3f5240caa6d33dee20d3..7e8f509b8862d43e1a5b188268558e42bf7e2809 100644 (file)
@@ -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;
 
index 8f579520691fac976ae70e667447626732c7403d..2f96740e85a3f2f1d748fec7665dd1d1922c2da1 100644 (file)
@@ -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))
index aa796d3e80606d86017ef083102c1a007fdfea8a..c0bc3ccf41dcd329fd41d0f9697f123de8b4ff4b 100644 (file)
@@ -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 */
This page took 0.041517 seconds and 5 git commands to generate.