]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: Add FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls
authorCorinna Vinschen <corinna@vinschen.de>
Tue, 25 Dec 2018 22:38:52 +0000 (23:38 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 25 Dec 2018 22:38:52 +0000 (23:38 +0100)
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
winsup/cygwin/autoload.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/include/cygwin/fs.h

index 5a0e400aa4baeee054df99c0f6dd949ffeca021d..7978287cb14194fe2b45b733c5d75c819d51f244 100644 (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)
index 9e63867ab575283c23c13ccf6560c5156e3784f6..07e8a183404bd6732e2398f0858154d2d58ae98e 100644 (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);
index a8b7af44b438241f9bcb65af8b550d21489fe739..e0a196fae00f39e03f81a55e3814698f5eda0ea0 100644 (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 ()
 {
index 48b0cca45c1ed4e01f134df5f63cf657d7624b18..9b4baf30227ad7eb661a4d3d35cc4974ba67885a 100644 (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)
This page took 0.046049 seconds and 5 git commands to generate.