]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: try to avoid recalling offline files
authorCorinna Vinschen <corinna@vinschen.de>
Fri, 8 Mar 2024 19:57:06 +0000 (20:57 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Fri, 8 Mar 2024 19:57:06 +0000 (20:57 +0100)
Chances are high that Cygwin recalls offline files from remote
storage, even if the file is only accessed during stat(2) or
readdir(3).

To avoid this
- make sure Cygwin is placeholder-aware,
- open files in path_conv handling, as well as in stat(2)/readdir(3)
  scenarios with FILE_OPEN_NO_RECALL, and
- during symlink checking or testing for executablility, don't even
  try to open the file if one of the OFFLINE attributes is set.

Reported-by: Marcin Wisnicki <mwisnicki@gmail.com>
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
winsup/cygwin/autoload.cc
winsup/cygwin/dcrt0.cc
winsup/cygwin/fhandler/disk_file.cc
winsup/cygwin/local_includes/ntdll.h
winsup/cygwin/local_includes/path.h
winsup/cygwin/local_includes/winlean.h
winsup/cygwin/path.cc

index 65e906e8b9d0a65bf6f1967b45821c3a0dcdbae7..cc9dafe1b62173c9d00117d84491633b2b10d63a 100644 (file)
@@ -479,6 +479,7 @@ LoadDLLfuncEx (SetThreadDescription, KernelBase, 1)
 LoadDLLfunc (VirtualAlloc2, KernelBase)
 
 LoadDLLfunc (NtMapViewOfSectionEx, ntdll)
+LoadDLLfuncEx (RtlSetProcessPlaceholderCompatibilityMode, ntdll, 1)
 
 LoadDLLfunc (ldap_bind_s, wldap32)
 LoadDLLfunc (ldap_count_entries, wldap32)
index a40129c222328568a909a22ff5fe26def12a0746..7229377eb3fe47f0b030a2489d61b0d6d9d00684 100644 (file)
@@ -809,6 +809,9 @@ dll_crt0_1 (void *)
   if (dynamically_loaded)
     sigproc_init ();
 
+  /* Call this before accessing any files. */
+  RtlSetProcessPlaceholderCompatibilityMode (PHCM_EXPOSE_PLACEHOLDERS);
+
   check_sanity_and_sync (user_data);
 
   /* Initialize malloc and then call user_shared_initialize since it relies
index d08fe9160d350a5412ef5a2da8e37a1cc77bebf7..f3592148fc5b953d796a3936e995bd81b9161206 100644 (file)
@@ -176,7 +176,9 @@ readdir_check_reparse_point (POBJECT_ATTRIBUTES attr, bool remote)
   bool ret = false;
 
   status = NtOpenFile (&reph, READ_CONTROL, attr, &io, FILE_SHARE_VALID_FLAGS,
-                      FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
+                      FILE_OPEN_NO_RECALL
+                      | FILE_OPEN_FOR_BACKUP_INTENT
+                      | FILE_OPEN_REPARSE_POINT);
   if (NT_SUCCESS (status))
     {
       PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
@@ -328,6 +330,7 @@ fhandler_base::fstat_by_name (struct stat *buf)
       status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
                           &attr, &io, FILE_SHARE_VALID_FLAGS,
                           FILE_SYNCHRONOUS_IO_NONALERT
+                          | FILE_OPEN_NO_RECALL
                           | FILE_OPEN_FOR_BACKUP_INTENT
                           | FILE_DIRECTORY_FILE);
       if (!NT_SUCCESS (status))
@@ -616,7 +619,8 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
       opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL,
                                       pc.get_object_attr (attr, sec_none_nih),
                                       &io, FILE_SHARE_VALID_FLAGS,
-                                      FILE_OPEN_FOR_BACKUP_INTENT));
+                                      FILE_OPEN_NO_RECALL
+                                      | FILE_OPEN_FOR_BACKUP_INTENT));
       if (!opened)
        {
          /* Can't open file.  Try again with parent dir. */
@@ -625,7 +629,8 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
          attr.ObjectName = &dirname;
          opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL, &attr, &io,
                                           FILE_SHARE_VALID_FLAGS,
-                                          FILE_OPEN_FOR_BACKUP_INTENT));
+                                          FILE_OPEN_NO_RECALL
+                                          | FILE_OPEN_FOR_BACKUP_INTENT));
          if (!opened)
            goto out;
        }
@@ -2323,7 +2328,8 @@ readdir_get_ino (const char *path, bool dot_dot)
           || NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL,
                                      pc.get_object_attr (attr, sec_none_nih),
                                      &io, FILE_SHARE_VALID_FLAGS,
-                                     FILE_OPEN_FOR_BACKUP_INTENT
+                                     FILE_OPEN_NO_RECALL
+                                     | FILE_OPEN_FOR_BACKUP_INTENT
                                      | (pc.is_known_reparse_point ()
                                      ? FILE_OPEN_REPARSE_POINT : 0)))
          )
@@ -2372,8 +2378,9 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
      Mountpoints and unknown or unhandled reparse points will be treated
      as normal file/directory/unknown. In all cases, returning the INO of
      the reparse point (not of the target) matches behavior of posix systems.
+     Unless the file is OFFLINE. *.
      */
-  if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
+  if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) && !isoffline (attr))
     {
       OBJECT_ATTRIBUTES oattr;
 
@@ -2618,7 +2625,8 @@ go_ahead:
                                         &nfs_aol_ffei, sizeof nfs_aol_ffei)
                         : NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
                                       FILE_SHARE_VALID_FLAGS,
-                                      FILE_OPEN_FOR_BACKUP_INTENT
+                                      FILE_OPEN_NO_RECALL
+                                      | FILE_OPEN_FOR_BACKUP_INTENT
                                       | FILE_OPEN_REPARSE_POINT);
              if (NT_SUCCESS (f_status))
                {
index 9605784e32a8d7e91fc38abff8a8adf19f769d1f..7737ae503c1829db547f13351b13716bff60057c 100644 (file)
@@ -169,6 +169,13 @@ extern GUID __cygwin_socket_guid;
 #define FILE_VC_QUOTAS_REBUILDING       0x00000200
 #define FILE_VC_VALID_MASK              0x000003ff
 
+#define PHCM_APPLICATION_DEFAULT        0
+#define PHCM_DISGUISE_PLACEHOLDER       1
+#define PHCM_EXPOSE_PLACEHOLDERS        2
+#define PHCM_MAX                        2
+#define PHCM_ERROR_INVALID_PARAMETER   -1
+#define PHCM_ERROR_NO_TEB              -2
+
 /* IOCTL code to impersonate client of named pipe. */
 
 #define FSCTL_PIPE_DISCONNECT  CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, \
@@ -1639,6 +1646,7 @@ extern "C"
                                         BOOLEAN);
   NTSTATUS RtlSetGroupSecurityDescriptor (PSECURITY_DESCRIPTOR, PSID, BOOLEAN);
   NTSTATUS RtlSetOwnerSecurityDescriptor (PSECURITY_DESCRIPTOR, PSID, BOOLEAN);
+  CHAR RtlSetProcessPlaceholderCompatibilityMode (CHAR);
   PUCHAR RtlSubAuthorityCountSid (PSID);
   PULONG RtlSubAuthoritySid (PSID, ULONG);
   ULONG RtlUnicodeStringToAnsiSize (PUNICODE_STRING);
index 4e62287f6a6e38c5c64e938ac828e808643656c2..cb8c4ca9f4d6a449efcc86702f76e28a44055a26 100644 (file)
@@ -23,6 +23,14 @@ has_attribute (DWORD attributes, DWORD attribs_to_test)
         && (attributes & attribs_to_test);
 }
 
+extern inline bool
+isoffline (DWORD attributes)
+{
+  return has_attribute (attributes, FILE_ATTRIBUTE_OFFLINE
+                                   | FILE_ATTRIBUTE_RECALL_ON_OPEN
+                                   | FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS);
+}
+
 enum executable_states
 {
   is_executable,
@@ -235,6 +243,12 @@ class path_conv
   bool exists () const {return fileattr != INVALID_FILE_ATTRIBUTES;}
   bool has_attribute (DWORD x) const {return exists () && (fileattr & x);}
   int isdir () const {return has_attribute (FILE_ATTRIBUTE_DIRECTORY);}
+  bool isoffline () const
+  {
+    return has_attribute (FILE_ATTRIBUTE_OFFLINE
+                         | FILE_ATTRIBUTE_RECALL_ON_OPEN
+                         | FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS);
+  }
   executable_states exec_state ()
   {
     extern int _check_for_executable;
@@ -242,7 +256,7 @@ class path_conv
       return is_executable;
     if (mount_flags & MOUNT_NOTEXEC)
       return not_executable;
-    if (!_check_for_executable)
+    if (isoffline () || !_check_for_executable)
       return dont_care_if_executable;
     return dont_know_if_executable;
   }
index 113b2c6b0d3f31ace0a48665a59eb9403c2229d4..947109bdeee4fd2604bb52e54bdc2076d3700116 100644 (file)
@@ -97,6 +97,13 @@ details. */
 #define FILE_SUPPORTS_GHOSTING                  0x40000000
 #endif
 
+#ifndef FILE_ATTRIBUTE_RECALL_ON_OPEN
+#define FILE_ATTRIBUTE_RECALL_ON_OPEN          0x00040000
+#endif
+#ifndef FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
+#define FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS   0x00400000
+#endif
+
 /* So-called "Microsoft Account" SIDs (S-1-11-...) have a netbios domain name
    "MicrosoftAccounts".  The new "Application Container SIDs" (S-1-15-...)
    have a netbios domain name "APPLICATION PACKAGE AUTHORITY"
index 68639f323972b857cda87f0966cb93ec3565553c..ddea4b3889eb673fe0a2b48303b6f696a9ddfb9a 100644 (file)
@@ -608,6 +608,7 @@ getfileattr (const char *path, bool caseinsensitive) /* path has to be always ab
       status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
                           &attr, &io, FILE_SHARE_VALID_FLAGS,
                           FILE_SYNCHRONOUS_IO_NONALERT
+                          | FILE_OPEN_NO_RECALL
                           | FILE_OPEN_FOR_BACKUP_INTENT
                           | FILE_DIRECTORY_FILE);
       if (NT_SUCCESS (status))
@@ -3208,7 +3209,8 @@ restart:
            }
          status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
                               &attr, &io, FILE_SHARE_VALID_FLAGS,
-                              FILE_OPEN_REPARSE_POINT
+                              FILE_OPEN_NO_RECALL
+                              | FILE_OPEN_REPARSE_POINT
                               | FILE_OPEN_FOR_BACKUP_INTENT);
          debug_printf ("%y = NtOpenFile (no-EAs %S)", status, &upath);
        }
@@ -3336,6 +3338,7 @@ restart:
              status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
                                   &dattr, &io, FILE_SHARE_VALID_FLAGS,
                                   FILE_SYNCHRONOUS_IO_NONALERT
+                                  | FILE_OPEN_NO_RECALL
                                   | FILE_OPEN_FOR_BACKUP_INTENT
                                   | FILE_DIRECTORY_FILE);
              if (!NT_SUCCESS (status))
@@ -3426,12 +3429,16 @@ restart:
         directory using a relative path, symlink evaluation goes totally
         awry.  We never want a virtual drive evaluated as symlink. */
       if (upath.Length <= 14)
-         goto file_not_symlink;
+       goto file_not_symlink;
+
+      /* Offline files, even if reparse points, are not symlinks. */
+      if (isoffline (fileattr ()))
+       goto file_not_symlink;
 
       /* Reparse points are potentially symlinks.  This check must be
         performed before checking the SYSTEM attribute for sysfile
         symlinks, since reparse points can have this flag set, too. */
-      if ((fileattr () & FILE_ATTRIBUTE_REPARSE_POINT))
+      if (fileattr () & FILE_ATTRIBUTE_REPARSE_POINT)
        {
          res = check_reparse_point (h, fs.is_remote_drive ());
          if (res > 0)
@@ -3474,7 +3481,8 @@ restart:
 
          status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
                               FILE_SHARE_VALID_FLAGS,
-                              FILE_OPEN_FOR_BACKUP_INTENT
+                              FILE_OPEN_NO_RECALL
+                              | FILE_OPEN_FOR_BACKUP_INTENT
                               | FILE_SYNCHRONOUS_IO_NONALERT);
          if (!NT_SUCCESS (status))
            res = 0;
@@ -3529,7 +3537,8 @@ restart:
 
          status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
                               FILE_SHARE_VALID_FLAGS,
-                              FILE_OPEN_FOR_BACKUP_INTENT
+                              FILE_OPEN_NO_RECALL
+                              | FILE_OPEN_FOR_BACKUP_INTENT
                               | FILE_SYNCHRONOUS_IO_NONALERT);
 
          if (!NT_SUCCESS (status))
This page took 0.046016 seconds and 5 git commands to generate.