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>
This commit is contained in:
parent
f94fe74aad
commit
0aa99373c1
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue