From af4a65a26d703cf150cd6d75336c19543aa014d8 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 25 Dec 2018 23:38:52 +0100 Subject: Cygwin: Add FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls Signed-off-by: Corinna Vinschen --- winsup/cygwin/autoload.cc | 2 + winsup/cygwin/fhandler.h | 3 + winsup/cygwin/fhandler_disk_file.cc | 247 ++++++++++++++++++++++++++++++++++++ winsup/cygwin/include/cygwin/fs.h | 27 ++++ 4 files changed, 279 insertions(+) diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 5a0e400aa..7978287cb 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -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) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 9e63867ab..07e8a1834 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index a8b7af44b..e0a196fae 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -25,6 +25,7 @@ details. */ #include "devices.h" #include "ldap.h" #include +#include #define _COMPILING_NEWLIB #include @@ -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 () { diff --git a/winsup/cygwin/include/cygwin/fs.h b/winsup/cygwin/include/cygwin/fs.h index 48b0cca45..9b4baf302 100644 --- a/winsup/cygwin/include/cygwin/fs.h +++ b/winsup/cygwin/include/cygwin/fs.h @@ -10,6 +10,8 @@ details. */ #ifndef _CYGWIN_FS_H_ #define _CYGWIN_FS_H_ +#include + #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) -- cgit v1.2.3