Cygwin: improve O_TMPFILE handling

Windows does not remove FILE_ATTRIBUTE_TEMPORARY by itself after a
file has been closed.  It's just some attribute which can be set or
removed at will, despite its purpose.

Apparently there are tools out there which use FILE_ATTRIBUTE_TEMPORARY
accidentally or wrongly, even Microsoft's own tools are affected.  In
the end, the filesystem is potentially full of files with this attribute
set.

Implement O_TMPFILE files with FILE_ATTRIBUTE_TEMPORARY and
FILE_ATTRIBUTE_HIDDEN set.  This combination is pretty unlikely.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2018-02-14 12:55:24 +01:00
parent 1188d308bf
commit 7ae73be141
3 changed files with 28 additions and 12 deletions

View File

@ -603,11 +603,14 @@ fhandler_base::open (int flags, mode_t mode)
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. */
to write to the disk at all.
Note that O_TMPFILE_FILE_ATTRS also sets the DOS HIDDEN attribute
to help telling Cygwin O_TMPFILE files apart from other files
accidentally setting FILE_ATTRIBUTE_TEMPORARY. */
if (flags & O_TMPFILE)
{
access |= DELETE;
file_attributes |= FILE_ATTRIBUTE_TEMPORARY;
file_attributes |= O_TMPFILE_FILE_ATTRS;
options |= FILE_DELETE_ON_CLOSE;
}

View File

@ -37,6 +37,8 @@ details. */
never be used in Cygwin for this function. */
#define PIPE_ADD_PID FILE_FLAG_FIRST_PIPE_INSTANCE
#define O_TMPFILE_FILE_ATTRS (FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN)
extern const char *windows_device_names[];
extern struct __cygwin_perfile *perfile_table;
#define __fmode (*(user_data->fmode_ptr))

View File

@ -1243,16 +1243,28 @@ fhandler_disk_file::link (const char *newpath)
__seterrno_from_nt_status (status);
return -1;
}
else if (pc.file_attributes () & FILE_ATTRIBUTE_TEMPORARY)
else if ((pc.file_attributes () & O_TMPFILE_FILE_ATTRS)
== O_TMPFILE_FILE_ATTRS)
{
/* 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. */
/* An O_TMPFILE file has FILE_ATTRIBUTE_TEMPORARY and
FILE_ATTRIBUTE_HIDDEN set. After a successful hardlink the file is
not temporary anymore in the usual sense. So we remove these
attributes here, even if this makes the original link (temporarily)
visible in directory enumeration.
Note that we don't create a reopen attribute for the original
link but rather a normal attribute for the just created link.
The reason is a curious behaviour of Windows: If we remove
the O_TMPFILE attributes on the original link, the new link
will not show up in file system listings, long after the original
link has been closed and removed. The file and its metadata will
be kept in memory only as long as Windows sees fit. By opening
the new link, we request the attribute changes on the new link,
so after closing it Windows will have an increased interest to
write back the metadata. */
OBJECT_ATTRIBUTES attr;
status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
pc.init_reopen_attr (attr, fh), &io,
newpc.get_object_attr (attr, sec_none_nih), &io,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
debug_printf ("Opening for removing TEMPORARY attrib failed, "
@ -1263,8 +1275,7 @@ fhandler_disk_file::link (const char *newpath)
fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart
= fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
fbi.FileAttributes = (pc.file_attributes ()
& ~FILE_ATTRIBUTE_TEMPORARY)
fbi.FileAttributes = (pc.file_attributes () & ~O_TMPFILE_FILE_ATTRS)
?: FILE_ATTRIBUTE_NORMAL;
status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
FileBasicInformation);
@ -2213,7 +2224,7 @@ go_ahead:
}
/* 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)
if ((FileAttributes & O_TMPFILE_FILE_ATTRS) == O_TMPFILE_FILE_ATTRS)
goto restart;
RtlInitCountedUnicodeString (&fname, FileName, FileNameLength);
d_mounts (dir)->check_mount (&fname);