* 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.
This commit is contained in:
parent
8447bf9f9f
commit
32d86d2ab2
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue