This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] Cygwin: fcntl.h: Define O_TMPFILE and implement it


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

commit 0aa99373c1d01b19a7f8ba53e8c7749358480f3e
Author: Corinna Vinschen <corinna@vinschen.de>
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 <corinna@vinschen.de>

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 */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]