Cygwin: Add FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
4021509ba2
commit
af4a65a26d
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue