diff options
Diffstat (limited to 'winsup/cygwin/fhandler_disk_file.cc')
-rw-r--r-- | winsup/cygwin/fhandler_disk_file.cc | 247 |
1 files changed, 247 insertions, 0 deletions
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 <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 () { |