From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 123411 invoked by alias); 14 Nov 2017 20:45:53 -0000 Mailing-List: contact newlib-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: newlib-cvs-owner@sourceware.org Received: (qmail 123375 invoked by uid 9078); 14 Nov 2017 20:45:53 -0000 Date: Tue, 14 Nov 2017 20:45:00 -0000 Message-ID: <20171114204553.123373.qmail@sourceware.org> Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Corinna Vinschen To: cygwin-cvs@sourceware.org, newlib-cvs@sourceware.org Subject: [newlib-cygwin] Cygwin: fcntl.h: Define O_TMPFILE and implement it X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: f94fe74aad9c69ed17e55468ce1044eafca34687 X-Git-Newrev: 0aa99373c1d01b19a7f8ba53e8c7749358480f3e X-SW-Source: 2017-q4/txt/msg00018.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=0aa99373c1d01b19a7f8ba53e8c7749358480f3e commit 0aa99373c1d01b19a7f8ba53e8c7749358480f3e Author: Corinna Vinschen 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 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 #include #include +#include #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 */