#define _FNOFOLLOW 0x100000
#define _FDIRECTORY 0x200000
#define _FEXECSRCH 0x400000
+#define _FTMPFILE 0x800000
#define O_BINARY _FBINARY
#define O_TEXT _FTEXT
#define O_DIRECTORY _FDIRECTORY
#define O_EXEC _FEXECSRCH
#define O_SEARCH _FEXECSRCH
+#define O_TMPFILE _FTMPFILE
#endif
#if __MISC_VISIBLE
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 ())
/* 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;
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
&& 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;
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;
}
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))
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))
#include <unistd.h>
#include <sys/wait.h>
#include <dirent.h>
+#include <ntsecapi.h>
#include "ntdll.h"
#undef fstat
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 */