OSDN Git Service

* path.cc (struct _FAST_CWD): Redefine to new layout used since patch
authorcorinna <corinna>
Mon, 14 Feb 2011 00:43:00 +0000 (00:43 +0000)
committercorinna <corinna>
Mon, 14 Feb 2011 00:43:00 +0000 (00:43 +0000)
for KB 2393802.  Adjust comments throughout.
(struct _FAST_CWD_OLD): Rename former definition.
(cwdstuff::override_win32_cwd): Check if the OS is using the old or the
new FAST_CWD structure layout and handle accordingly.

winsup/cygwin/ChangeLog
winsup/cygwin/path.cc

index ba0f222..afd9cd1 100644 (file)
@@ -1,3 +1,11 @@
+2011-02-13  Corinna Vinschen  <corinna@vinschen.de>
+
+       * path.cc (struct _FAST_CWD): Redefine to new layout used since patch
+       for KB 2393802.  Adjust comments throughout.
+       (struct _FAST_CWD_OLD): Rename former definition.
+       (cwdstuff::override_win32_cwd): Check if the OS is using the old or the
+       new FAST_CWD structure layout and handle accordingly.
+
 2011-02-11  Christopher Faylor  <me+cygwin@cgf.cx>
 
        * mkstatic: Make sure that we are not cd'ed to temporary directory on
index e407541..a1f36b7 100644 (file)
@@ -3432,6 +3432,20 @@ cygwin_split_path (const char *path, char *dir, char *file)
    minimal locking and it's much more multi-thread friendly.  Presumably
    it minimizes contention when accessing the CWD. */
 typedef struct _FAST_CWD {
+  UNICODE_STRING Path;                 /* Path's Buffer member always refers
+                                          to the following Buffer array. */
+  HANDLE         DirectoryHandle;
+  LONG           FSCharacteristics;    /* Taken from FileFsDeviceInformation */
+  LONG           ReferenceCount;       /* Only release when this is 0. */
+  ULONG          OldDismountCount;     /* Reflects the system DismountCount
+                                          at the time the CWD has been set. */
+  WCHAR          Buffer[MAX_PATH];
+} FAST_CWD, *PFAST_CWD;
+
+/* This is the old FAST_CWD structure up to the patch from KB 2393802,
+   release in February 2011.  Hopefully it's not used for long anymore,
+   but for quite some time we can't rely on this fact. */
+typedef struct _FAST_CWD_OLD {
   LONG           ReferenceCount;       /* Only release when this is 0. */
   HANDLE         DirectoryHandle;
   ULONG          OldDismountCount;     /* Reflects the system DismountCount
@@ -3439,7 +3453,7 @@ typedef struct _FAST_CWD {
   UNICODE_STRING Path;                 /* Path's Buffer member always refers
                                           to the following Buffer array. */
   WCHAR          Buffer[MAX_PATH];
-} FAST_CWD, *PFAST_CWD;
+} FAST_CWD_OLD, *PFAST_CWD_OLD;
 
 /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
    to the FAST_CWD structure which constitutes the CWD.
@@ -3556,7 +3570,10 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
             fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
             function entirely, just as on pre-Vista. */
          PVOID heap = peb.ProcessHeap;
-         /* First allocate a new FAST_CWD strcuture on the heap. */
+         /* First allocate a new FAST_CWD structure on the heap.
+            The new FAST_CWD structure is 4 byte bigger than the old one,
+            but we simply don't care, so we allocate always room for the
+            new one. */
          PFAST_CWD f_cwd = (PFAST_CWD)
                            RtlAllocateHeap (heap, 0, sizeof (FAST_CWD));
          if (!f_cwd)
@@ -3564,35 +3581,82 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
              debug_printf ("RtlAllocateHeap failed");
              return;
            }
-         /* Fill in the values. */
-         f_cwd->ReferenceCount = 1;
-         f_cwd->DirectoryHandle = dir;
-         f_cwd->OldDismountCount = old_dismount_count;
-         RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
-                                    MAX_PATH * sizeof (WCHAR));
-         copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32);
-         /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
-            structure and writing the CWD to the user process parameter
-            block.  This is equivalent to calling RtlAcquirePebLock/
-            RtlReleasePebLock, but without having to go through the FS
-            selector again. */
-         RtlEnterCriticalSection (peb.FastPebLock);
-         PFAST_CWD old_cwd = *fast_cwd_ptr;
-         *fast_cwd_ptr = f_cwd;
-         upp_cwd_str = f_cwd->Path;
-         upp_cwd_hdl = dir;
-         RtlLeaveCriticalSection (peb.FastPebLock);
-         /* Decrement the reference count.  If it's down to 0, free structure
-            from heap. */
-         if (old_cwd && InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
+         /* Fill in the values.  Fortunately it's simple to check for the
+            new structure.  Path.MaximumLength takes the same space as the
+            high word of the old ReferenceCount.  We know that MaximumLength
+            is always MAX_PATH.  For the ref count this would account for a
+            pratically impossible value between 34078720 and 34079240. */
+         if ((*fast_cwd_ptr)->Path.MaximumLength == MAX_PATH * sizeof (WCHAR))
            {
-             /* In contrast to pre-Vista, the handle on init is always a fresh
-                one and not the handle inherited from the parent process.  So
-                we always have to close it here.  However, the handle could
-                be NULL, if we cd'ed into a virtual dir. */
-             if (old_cwd->DirectoryHandle)
-               NtClose (old_cwd->DirectoryHandle);
-             RtlFreeHeap (heap, 0, old_cwd);
+             /* New FAST_CWD structure. */
+             IO_STATUS_BLOCK io;
+             FILE_FS_DEVICE_INFORMATION ffdi;
+
+             RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
+                                        MAX_PATH * sizeof (WCHAR));
+             f_cwd->DirectoryHandle = dir;
+             /* The new structure stores the device characteristics of the
+                volume holding the dir.  RtlGetCurrentDirectory_U checks
+                if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
+                the volume is still the same as the one used when opening
+                the directory handle.
+                We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
+                though.  It just returns STATUS_INVALID_HANDLE anyway. */
+             f_cwd->FSCharacteristics = 
+               (!error
+                && NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi,
+                                      sizeof ffdi, FileFsDeviceInformation)))
+               ? ffdi.Characteristics : 0;
+             f_cwd->ReferenceCount = 1;
+             f_cwd->OldDismountCount = old_dismount_count;
+             copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32);
+             /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
+                structure and writing the CWD to the user process parameter
+                block.  This is equivalent to calling RtlAcquirePebLock/
+                RtlReleasePebLock, but without having to go through the FS
+                selector again. */
+             RtlEnterCriticalSection (peb.FastPebLock);
+             PFAST_CWD old_cwd = *fast_cwd_ptr;
+             *fast_cwd_ptr = f_cwd;
+             upp_cwd_str = f_cwd->Path;
+             upp_cwd_hdl = dir;
+             RtlLeaveCriticalSection (peb.FastPebLock);
+             /* Decrement the reference count.  If it's down to 0, free
+                structure from heap. */
+             if (InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
+               {
+                 /* In contrast to pre-Vista, the handle on init is always a
+                    fresh one and not the handle inherited from the parent
+                    process.  So we always have to close it here.  However, the
+                    handle could be NULL, if we cd'ed into a virtual dir. */
+                 if (old_cwd->DirectoryHandle)
+                   NtClose (old_cwd->DirectoryHandle);
+                 RtlFreeHeap (heap, 0, old_cwd);
+               }
+           }
+         else
+           {
+             /* Old FAST_CWD structure.  Otherwise same procedure as above,
+                except for the non-existant FSCharacteristics member. */
+             PFAST_CWD_OLD f_cwd_old = (PFAST_CWD_OLD) f_cwd;
+             f_cwd_old->ReferenceCount = 1;
+             f_cwd_old->DirectoryHandle = dir;
+             f_cwd_old->OldDismountCount = old_dismount_count;
+             RtlInitEmptyUnicodeString (&f_cwd_old->Path, f_cwd_old->Buffer,
+                                        MAX_PATH * sizeof (WCHAR));
+             copy_cwd_str (&f_cwd_old->Path, error ? &ro_u_pipedir : &win32);
+             RtlEnterCriticalSection (peb.FastPebLock);
+             PFAST_CWD_OLD old_cwd = (PFAST_CWD_OLD) *fast_cwd_ptr;
+             *fast_cwd_ptr = (PFAST_CWD) f_cwd_old;
+             upp_cwd_str = f_cwd_old->Path;
+             upp_cwd_hdl = dir;
+             RtlLeaveCriticalSection (peb.FastPebLock);
+             if (InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
+               {
+                 if (old_cwd->DirectoryHandle)
+                   NtClose (old_cwd->DirectoryHandle);
+                 RtlFreeHeap (heap, 0, old_cwd);
+               }
            }
        }
       else
@@ -3636,8 +3700,12 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
          PFAST_CWD f_cwd = (PFAST_CWD)
                            ((PBYTE) upp_cwd_str.Buffer
                             - __builtin_offsetof (struct _FAST_CWD, Buffer));
+         if (f_cwd->Path.MaximumLength == MAX_PATH * sizeof (WCHAR))
+           f_cwd->DirectoryHandle = dir;
+         else
+           ((PFAST_CWD_OLD) f_cwd)->DirectoryHandle = dir;
          h = upp_cwd_hdl;
-         f_cwd->DirectoryHandle = upp_cwd_hdl = dir;
+         upp_cwd_hdl = dir;
          RtlLeaveCriticalSection (peb.FastPebLock);
          /* In contrast to pre-Vista, the handle on init is always a fresh one
             and not the handle inherited from the parent process.  So we always