Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2011-02-13 18:43:00 +0300
committerCorinna Vinschen <corinna@vinschen.de>2011-02-13 18:43:00 +0300
commit32d86d2ab210d143c4440179f79ab7f9ae511792 (patch)
treea0d74b240357e6b209c173f20abbeee0ed4943bb
parent8447bf9f9f971b6b20564bb6f9df37c316b01c6e (diff)
* 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.
-rw-r--r--winsup/cygwin/ChangeLog8
-rw-r--r--winsup/cygwin/path.cc130
2 files changed, 107 insertions, 31 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ba0f2227e..afd9cd1e9 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index e4075410f..a1f36b7cd 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -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