aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2017-11-14 21:28:45 +0100
committerCorinna Vinschen <corinna@vinschen.de>2017-11-14 21:45:25 +0100
commit0aa99373c1d01b19a7f8ba53e8c7749358480f3e (patch)
tree9a9707136776c5995c01781b1f3587e1ada5a134
parentf94fe74aad9c69ed17e55468ce1044eafca34687 (diff)
downloadnewlib-0aa99373c1d01b19a7f8ba53e8c7749358480f3e.zip
newlib-0aa99373c1d01b19a7f8ba53e8c7749358480f3e.tar.gz
newlib-0aa99373c1d01b19a7f8ba53e8c7749358480f3e.tar.bz2
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>
-rw-r--r--newlib/libc/include/sys/_default_fcntl.h2
-rw-r--r--winsup/cygwin/fhandler.cc21
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc39
-rw-r--r--winsup/cygwin/syscalls.cc44
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 */