Cygwin: Add FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user