Cygwin: Add FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2018-12-25 23:38:52 +01:00
parent 4021509ba2
commit af4a65a26d
4 changed files with 279 additions and 0 deletions

View File

@ -534,6 +534,8 @@ LoadDLLprime (ws2_32, _wsock_init, 0)
LoadDLLfunc (CheckTokenMembership, 12, advapi32)
LoadDLLfunc (CreateProcessAsUserW, 44, advapi32)
LoadDLLfunc (DeregisterEventSource, 4, advapi32)
LoadDLLfunc (DecryptFileW, 8, advapi32)
LoadDLLfunc (EncryptFileW, 4, advapi32)
LoadDLLfunc (LogonUserW, 24, advapi32)
LoadDLLfunc (LookupAccountNameW, 28, advapi32)
LoadDLLfunc (LookupAccountSidW, 28, advapi32)

View File

@ -1437,6 +1437,8 @@ class fhandler_disk_file: public fhandler_base
int __reg3 readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname);
int prw_open (bool, void *);
uint64_t fs_ioc_getflags ();
int fs_ioc_setflags (uint64_t);
public:
fhandler_disk_file ();
@ -1462,6 +1464,7 @@ class fhandler_disk_file: public fhandler_base
int __reg2 link (const char *);
int __reg2 utimens (const struct timespec *);
int __reg2 fstatvfs (struct statvfs *buf);
int ioctl (unsigned int cmd, void *buf);
HANDLE mmap (caddr_t *addr, size_t len, int prot, int flags, off_t off);
int munmap (HANDLE h, caddr_t addr, size_t len);

View File

@ -25,6 +25,7 @@ details. */
#include "devices.h"
#include "ldap.h"
#include <aio.h>
#include <cygwin/fs.h>
#define _COMPILING_NEWLIB
#include <dirent.h>
@ -2437,6 +2438,252 @@ fhandler_disk_file::closedir (DIR *dir)
return res;
}
uint64_t
fhandler_disk_file::fs_ioc_getflags ()
{
NTSTATUS status;
IO_STATUS_BLOCK io;
FILE_BASIC_INFORMATION fbi;
FILE_CASE_SENSITIVE_INFORMATION fcsi;
uint64_t flags = 0;
status = NtQueryInformationFile (get_handle (), &io, &fbi, sizeof fbi,
FileBasicInformation);
if (NT_SUCCESS (status))
{
flags = (uint64_t) fbi.FileAttributes & FS_FL_USER_VISIBLE;
pc.file_attributes (fbi.FileAttributes);
}
else
flags = (uint64_t) pc.file_attributes () & FS_FL_USER_VISIBLE;
if (pc.isdir () && wincap.has_case_sensitive_dirs ()
&& !pc.isremote () && pc.fs_is_ntfs ())
{
fcsi.Flags = 0;
status = NtQueryInformationFile (get_handle (), &io,
&fcsi, sizeof fcsi,
FileCaseSensitiveInformation);
if (NT_SUCCESS (status)
&& (fcsi.Flags & FILE_CS_FLAG_CASE_SENSITIVE_DIR))
flags |= FS_CASESENS_FL;
}
return flags;
}
/* Settable DOS attributes */
#define FS_FL_SETATTRIBS (FS_READONLY_FL \
| FS_HIDDEN_FL \
| FS_SYSTEM_FL \
| FS_ARCHIVE_FL \
| FS_TEMP_FL \
| FS_NOTINDEXED_FL)
int
fhandler_disk_file::fs_ioc_setflags (uint64_t flags)
{
int ret = -1;
uint64_t old_flags;
HANDLE fh;
NTSTATUS status;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
FILE_BASIC_INFORMATION fbi;
FILE_SET_SPARSE_BUFFER fssb;
USHORT comp;
FILE_CASE_SENSITIVE_INFORMATION fcsi;
if ((get_access () & (GENERIC_WRITE | FILE_WRITE_ATTRIBUTES)) != 0)
fh = get_handle ();
else
{
status = NtOpenFile (&fh, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
pc.init_reopen_attr (attr, get_handle ()), &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
fh = get_handle ();
__seterrno_from_nt_status (status);
goto out;
}
}
old_flags = fs_ioc_getflags ();
if ((old_flags & FS_FL_SETATTRIBS) != (flags & FS_FL_SETATTRIBS))
{
fbi.CreationTime.QuadPart
= fbi.LastAccessTime.QuadPart
= fbi.LastWriteTime.QuadPart
= fbi.ChangeTime.QuadPart = 0LL;
fbi.FileAttributes = (ULONG) old_flags;
fbi.FileAttributes &= ~FS_FL_SETATTRIBS;
fbi.FileAttributes |= (flags & FS_FL_SETATTRIBS);
if (fbi.FileAttributes == 0)
fbi.FileAttributes = FILE_ATTRIBUTE_NORMAL;
status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
FileBasicInformation);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto out;
}
}
if (!pc.isdir() && (flags & FS_SPARSE_FL) != (old_flags & FS_SPARSE_FL))
{
fssb.SetSparse = (flags & FS_SPARSE_FL) ? TRUE : FALSE;
status = NtFsControlFile (fh, NULL, NULL, NULL, &io,
FSCTL_SET_SPARSE, &fssb, sizeof fssb, NULL, 0);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto out;
}
}
if (pc.isdir () && (flags & FS_CASESENS_FL) != (old_flags & FS_CASESENS_FL))
{
if (wincap.has_case_sensitive_dirs ()
&& !pc.isremote () && pc.fs_is_ntfs ())
{
fcsi.Flags = (flags & FS_CASESENS_FL)
? FILE_CS_FLAG_CASE_SENSITIVE_DIR : 0;
status = NtSetInformationFile (fh, &io, &fcsi, sizeof fcsi,
FileCaseSensitiveInformation);
if (!NT_SUCCESS (status))
{
/* Special case: The directory contains files which only
differ in case. NtSetInformationFile refuses to change
back to case insensitivity and returns status 0xc00004b3.
There's no STATUS_xyz macro assigned to that value yet,
nor does it map to a useful Win32 error value. */
if (status == (NTSTATUS) 0xc00004b3)
set_errno (EINVAL); /* Does that make sense? */
else
__seterrno_from_nt_status (status);
goto out;
}
}
else
{
set_errno (ENOTSUP);
goto out;
}
}
if ((flags & FS_COMPRESSED_FL) != (old_flags & FS_COMPRESSED_FL))
{
if (fh != get_handle ())
NtClose (fh);
fh = NULL;
if ((get_access () & (GENERIC_WRITE | GENERIC_READ))
!= (GENERIC_WRITE | GENERIC_READ))
{
status = NtOpenFile (&fh, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
pc.init_reopen_attr (attr, get_handle ()), &io,
FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
fh = get_handle ();
__seterrno_from_nt_status (status);
goto out;
}
}
comp = (flags & FS_COMPRESSED_FL)
? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
status = NtFsControlFile (fh, NULL, NULL, NULL, &io,
FSCTL_SET_COMPRESSION, &comp, sizeof comp,
NULL, 0);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto out;
}
}
if (!pc.isdir() && (flags & FS_ENCRYPT_FL) != (old_flags & FS_ENCRYPT_FL))
{
tmp_pathbuf tp;
PWCHAR path = tp.w_get ();
BOOL cret;
/* EncryptFileW/DecryptFileW needs exclusive access. */
if (fh != get_handle ())
NtClose (fh);
NtClose (get_handle ());
set_io_handle (NULL);
pc.get_wide_win32_path (path);
cret = (flags & FS_ENCRYPT_FL)
? EncryptFileW (path) : DecryptFileW (path, 0);
status = NtOpenFile (&fh, get_access (),
pc.get_object_attr (attr, sec_none_nih), &io,
FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return -1;
}
set_io_handle (fh);
if (!cret)
{
__seterrno ();
goto out;
}
}
ret = 0;
out:
status = NtQueryInformationFile (fh, &io, &fbi, sizeof fbi,
FileBasicInformation);
if (NT_SUCCESS (status))
pc.file_attributes (fbi.FileAttributes);
if (fh != get_handle ())
NtClose (fh);
return ret;
}
int
fhandler_disk_file::ioctl (unsigned int cmd, void *p)
{
int ret = -1;
uint64_t flags = 0;
switch (cmd)
{
case FS_IOC_GETFLAGS:
__try
{
uint64_t *fp = (uint64_t *) p;
*fp = fs_ioc_getflags ();
ret = 0;
}
__except (EFAULT) {}
__endtry
break;
case FS_IOC_SETFLAGS:
__try
{
flags = *(__uint64_t *) p;
}
__except (EFAULT)
{
break;
}
__endtry
if (flags & ~FS_FL_USER_MODIFIABLE)
{
set_errno (EINVAL);
break;
}
ret = fs_ioc_setflags (flags);
break;
default:
ret = fhandler_base::ioctl (cmd, p);
break;
}
syscall_printf ("%d = ioctl_file(%x, %p)", ret, cmd, p);
return ret;
}
fhandler_cygdrive::fhandler_cygdrive () :
fhandler_disk_file ()
{

View File

@ -10,6 +10,8 @@ details. */
#ifndef _CYGWIN_FS_H_
#define _CYGWIN_FS_H_
#include <asm/socket.h>
#define BLKRRPART 0x0000125f
#define BLKGETSIZE 0x00001260
#define BLKSSZGET 0x00001268
@ -19,6 +21,31 @@ details. */
#define BLKPBSZGET 0x0000127b
#define BLKGETSIZE64 0x00041268
/* Get/Set file attributes */
#define FS_IOC_GETFLAGS _IOR('f', 1, __uint64_t)
#define FS_IOC_SETFLAGS _IOW('f', 2, __uint64_t)
/* Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
This is loosely following the Linux inode flags. Basically it's just
a convenient way to handle certain aspects of files on Windows which
are not covered by POSIX calls, mostly connected to DOS attributes. */
#define FS_READONLY_FL 0x000000001ULL /* DOS R/O */
#define FS_HIDDEN_FL 0x000000002ULL /* DOS Hidden */
#define FS_SYSTEM_FL 0x000000004ULL /* DOS System */
#define FS_ARCHIVE_FL 0x000000020ULL /* DOS Archive */
#define FS_TEMP_FL 0x000000100ULL /* DOS Temporary */
#define FS_SPARSE_FL 0x000000200ULL /* Sparse file */
#define FS_REPARSE_FL 0x000000400ULL /* Reparse point */
#define FS_COMPRESSED_FL 0x000000800ULL /* Compressed file */
#define FS_OFFLINE_FL 0x000001000ULL /* DOS Offline */
#define FS_NOTINDEXED_FL 0x000002000ULL /* DOS Not context indexed */
#define FS_ENCRYPT_FL 0x000004000ULL /* Encrypted file */
#define FS_CASESENS_FL 0x100000000ULL /* Case sensitive dir */
#define FS_FL_USER_VISIBLE 0x100007f27ULL /* User visible flags */
#define FS_FL_USER_MODIFIABLE 0x100006b27ULL /* User modifiable flags */
/* Flags for renameat2, from /usr/include/linux/fs.h. For now we
support only RENAME_NOREPLACE. */
#define RENAME_NOREPLACE (1 << 0)