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
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2010-10-09 14:54:13 +0400
committerCorinna Vinschen <corinna@vinschen.de>2010-10-09 14:54:13 +0400
commit9c154abedb4cbf713808e2fbe625f6d80939dcc3 (patch)
tree7c35bfc394febeaa1c5e45b74ba941a290799662 /winsup
parentd8c5f616ef4f210853d558d14bde281aa43b150a (diff)
* cygheap.h (cwdstuff::override_win32_cwd): Declare.
* ntdll.h (struct _PEB): Add members accessed by the fast cwd method starting with Vista. (struct _KUSER_SHARED_DATA): Define with only the DismountCount. (RtlAllocateHeap): Declare. (RtlEnterCriticalSection): Declare. (RtlFreeHeap): Declare. (RtlLeaveCriticalSection): Declare. * path.cc (get_user_proc_parms): Remove. (struct _FAST_CWD): New structure. (fast_cwd_ptr): Define. (SharedUserData): Define. (peek32): Define. (find_fast_cwd_pointers): New function to find the global pointer to the current FAST_CWD structure. (copy_cwd_str): New helper function. (cwdstuff::override_win32_cwd): New method to set the Win32 CWD. (cwdstuff::init): Just call override_win32_cwd from here when started from native Win32 parent. (cwdstuff::set): Access Win32 CWD via PEB reference instead of using get_user_proc_parms function. Memorize old DismountCount before opening directory handle. Call override_win32_cwd to set up Win32 CWD. Be more verbose in comments. * wincap.h (wincaps::has_fast_cwd): New element. * wincap.cc: Implement has_fast_cwd element throughout.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog29
-rw-r--r--winsup/cygwin/cygheap.h2
-rw-r--r--winsup/cygwin/ntdll.h18
-rw-r--r--winsup/cygwin/path.cc316
-rw-r--r--winsup/cygwin/wincap.cc9
-rw-r--r--winsup/cygwin/wincap.h2
6 files changed, 354 insertions, 22 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 5f56837e3..3d803dd69 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,32 @@
+2010-09-08 John Carey <aeolus@electric-cloud.com>
+ Corinna Vinschen <corinna@vinschen.de>
+
+ * cygheap.h (cwdstuff::override_win32_cwd): Declare.
+ * ntdll.h (struct _PEB): Add members accessed by the fast cwd method
+ starting with Vista.
+ (struct _KUSER_SHARED_DATA): Define with only the DismountCount.
+ (RtlAllocateHeap): Declare.
+ (RtlEnterCriticalSection): Declare.
+ (RtlFreeHeap): Declare.
+ (RtlLeaveCriticalSection): Declare.
+ * path.cc (get_user_proc_parms): Remove.
+ (struct _FAST_CWD): New structure.
+ (fast_cwd_ptr): Define.
+ (SharedUserData): Define.
+ (peek32): Define.
+ (find_fast_cwd_pointers): New function to find the global pointer
+ to the current FAST_CWD structure.
+ (copy_cwd_str): New helper function.
+ (cwdstuff::override_win32_cwd): New method to set the Win32 CWD.
+ (cwdstuff::init): Just call override_win32_cwd from here when
+ started from native Win32 parent.
+ (cwdstuff::set): Access Win32 CWD via PEB reference instead of using
+ get_user_proc_parms function. Memorize old DismountCount before
+ opening directory handle. Call override_win32_cwd to set up Win32 CWD.
+ Be more verbose in comments.
+ * wincap.h (wincaps::has_fast_cwd): New element.
+ * wincap.cc: Implement has_fast_cwd element throughout.
+
2010-09-08 Marco Atzeri <marco_atzeri@yahoo.it>
Corinna Vinschen <corinna@vinschen.de>
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 46e3c711b..1096175fa 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -217,6 +217,8 @@ private:
a native Win32 application. See cwdstuff::set for
how it gets set. See spawn_guts for how it's
evaluated. */
+ void override_win32_cwd (bool, ULONG);
+
public:
UNICODE_STRING win32;
static muto cwd_lock;
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 41c84a2ce..54c56f027 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -584,7 +584,10 @@ typedef struct _PEB
BYTE Reserved2[9];
PVOID LoaderData;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
- BYTE Reserved3[448];
+ BYTE Reserved3[4];
+ PVOID ProcessHeap;
+ PRTL_CRITICAL_SECTION FastPebLock;
+ BYTE Reserved4[436];
ULONG SessionId;
} PEB, *PPEB;
@@ -596,6 +599,13 @@ typedef struct _TEB
/* A lot more follows... */
} TEB, *PTEB;
+typedef struct _KUSER_SHARED_DATA
+{
+ BYTE Reserved1[0x2dc];
+ ULONG DismountCount;
+ /* A lot more follows... */
+} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
+
typedef struct _PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
@@ -979,10 +989,11 @@ extern "C"
NTSTATUS NTAPI NtWriteFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER,
PULONG);
+ VOID NTAPI RtlAcquirePebLock ();
+ PVOID NTAPI RtlAllocateHeap (PVOID, ULONG, SIZE_T);
NTSTATUS NTAPI RtlAppendUnicodeToString (PUNICODE_STRING, PCWSTR);
NTSTATUS NTAPI RtlAppendUnicodeStringToString (PUNICODE_STRING,
PUNICODE_STRING);
- VOID NTAPI RtlAcquirePebLock ();
NTSTATUS NTAPI RtlAnsiStringToUnicodeString (PUNICODE_STRING, PANSI_STRING,
BOOLEAN);
LONG NTAPI RtlCompareUnicodeString (PUNICODE_STRING, PUNICODE_STRING,
@@ -992,9 +1003,11 @@ extern "C"
BOOLEAN NTAPI RtlCreateUnicodeStringFromAsciiz (PUNICODE_STRING, PCSTR);
NTSTATUS NTAPI RtlDowncaseUnicodeString (PUNICODE_STRING, PUNICODE_STRING,
BOOLEAN);
+ NTSTATUS NTAPI RtlEnterCriticalSection (PRTL_CRITICAL_SECTION);
BOOLEAN NTAPI RtlEqualUnicodeString (PUNICODE_STRING, PUNICODE_STRING,
BOOLEAN);
VOID NTAPI RtlFreeAnsiString (PANSI_STRING);
+ BOOLEAN NTAPI RtlFreeHeap (PVOID, ULONG, PVOID);
VOID NTAPI RtlFreeOemString (POEM_STRING);
VOID NTAPI RtlFreeUnicodeString (PUNICODE_STRING);
HANDLE NTAPI RtlGetCurrentTransaction ();
@@ -1002,6 +1015,7 @@ extern "C"
VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR);
NTSTATUS NTAPI RtlIntegerToUnicodeString (ULONG, ULONG, PUNICODE_STRING);
ULONG NTAPI RtlIsDosDeviceName_U (PCWSTR);
+ NTSTATUS NTAPI RtlLeaveCriticalSection (PRTL_CRITICAL_SECTION);
ULONG NTAPI RtlNtStatusToDosError (NTSTATUS);
NTSTATUS NTAPI RtlOemStringToUnicodeString (PUNICODE_STRING, POEM_STRING,
BOOLEAN);
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 02ec2b398..468570166 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -3353,10 +3353,282 @@ cygwin_split_path (const char *path, char *dir, char *file)
/*****************************************************************************/
-static inline PRTL_USER_PROCESS_PARAMETERS
-get_user_proc_parms ()
+/* The find_fast_cwd_pointers function and parts of the
+ cwdstuff::override_win32_cwd method are based on code using the
+ following license:
+
+ Copyright 2010 John Carey. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. */
+
+/* This structure is used to store the CWD starting with Windows Vista.
+ The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
+ an afterthought now. The actual CWD storage is a FAST_CWD structure
+ which is allocated on the process heap. The new method only requires
+ minimal locking and it's much more multi-thread friendly. Presumably
+ it minimizes contention when accessing the CWD. */
+typedef struct _FAST_CWD {
+ LONG ReferenceCount; /* Only release when this is 0. */
+ HANDLE DirectoryHandle;
+ ULONG OldDismountCount; /* Reflects the system DismountCount
+ at the time the CWD has been set. */
+ UNICODE_STRING Path; /* Path's Buffer member always refers
+ to the following Buffer array. */
+ WCHAR Buffer[MAX_PATH];
+} FAST_CWD, *PFAST_CWD;
+
+/* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
+ to the FAST_CWD structure which constitutes the CWD.
+
+ We put the pointer into the common shared DLL segment. This allows to
+ restrict the call to find_fast_cwd_pointers() to once per Cygwin session
+ per user session. This works, because ASLR randomizes the load address
+ of DLLs only once at boot time. */
+static PFAST_CWD *fast_cwd_ptr
+ __attribute__((section (".cygwin_dll_common"), shared)) = (PFAST_CWD *) -1;
+
+/* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
+ user address space. We need it here to access the current DismountCount. */
+static KUSER_SHARED_DATA &SharedUserData
+ = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
+
+#define peek32(x) (*(uint32_t *)(x))
+
+/* This function scans the code in ntdll.dll to find the address of the
+ global variable used to access the CWD starting with Vista. While the
+ pointer is global, it's not exported from the DLL, unfortunately.
+ Therefore we have to use some knowledge to figure out the address.
+
+ This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
+ Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
+ There's some hope that this will still work for Windows 8... */
+static void
+find_fast_cwd_pointers ()
{
- return NtCurrentTeb ()->Peb->ProcessParameters;
+ /* Note that we have been called. */
+ fast_cwd_ptr = NULL;
+ /* Fetch entry points of relevant functions in ntdll.dll. */
+ HMODULE ntdll = GetModuleHandle ("ntdll.dll");
+ if (!ntdll)
+ return;
+ const uint8_t *get_dir = (const uint8_t *)
+ GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
+ const uint8_t *ent_crit = (const uint8_t *)
+ GetProcAddress (ntdll, "RtlEnterCriticalSection");
+ if (!get_dir || !ent_crit)
+ return;
+ /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
+ const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
+ if (!rcall)
+ return;
+ /* Fetch offset from instruction and compute address of called function.
+ This function actually fetches the current FAST_CWD instance and
+ performs some other actions, not important to us. */
+ ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
+ const uint8_t *use_cwd = rcall + 5 + offset;
+ /* Find first "push edi" instruction. */
+ const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
+ /* ...which should be followed by "mov edi, crit-sect-addr" then
+ "push edi". */
+ const uint8_t *movedi = pushedi + 1;
+ if (movedi[0] != 0xbf || movedi[5] != 0x57)
+ return;
+ /* Compare the address used for the critical section with the known
+ PEB lock as stored in the PEB. */
+ if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
+ != NtCurrentTeb ()->Peb->FastPebLock)
+ return;
+ /* To check we are seeing the right code, we check our expectation that
+ the next instruction is a relative call into RtlEnterCriticalSection. */
+ rcall = movedi + 6;
+ if (rcall[0] != 0xe8)
+ return;
+ /* Check that this is a relative call to RtlEnterCriticalSection. */
+ offset = (ptrdiff_t) peek32 (rcall + 1);
+ if (rcall + 5 + offset != ent_crit)
+ return;
+ /* After locking the critical section, the code should read the global
+ PFAST_CWD * pointer that is guarded by that critical section. */
+ const uint8_t *movesi = rcall + 5;
+ if (movesi[0] != 0x8b)
+ return;
+ fast_cwd_ptr = (PFAST_CWD *) peek32 (movesi + 2);
+#ifdef DEBUGGING
+ system_printf ("fast_cwd_ptr: %p", fast_cwd_ptr);
+#endif
+}
+
+static inline void
+copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
+{
+ RtlCopyUnicodeString (tgt, src);
+ if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
+ {
+ tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
+ tgt->Length += sizeof (WCHAR);
+ }
+}
+
+void
+cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
+{
+ NTSTATUS status;
+ HANDLE h = NULL;
+
+ PEB &peb = *NtCurrentTeb ()->Peb;
+ UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
+ HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
+
+ if (wincap.has_fast_cwd ())
+ {
+ if (fast_cwd_ptr == (PFAST_CWD *) -1)
+ {
+ find_fast_cwd_pointers ();
+ if (!fast_cwd_ptr)
+ system_printf ("WARNING: Couldn't compute FAST_CWD pointer. "
+ "Please report this problem to\nthe public mailing "
+ "list cygwin@cygwin.com");
+ }
+ if (fast_cwd_ptr)
+ {
+ /* Default method starting with Vista. If we got a valid value for
+ 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. */
+ PFAST_CWD f_cwd = (PFAST_CWD)
+ RtlAllocateHeap (heap, 0, sizeof (FAST_CWD));
+ if (!f_cwd)
+ {
+ 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)
+ {
+ /* 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
+ {
+ /* This is more a hack, and it's only used on Vista and later if we
+ failed to find the fast_cwd_ptr value. What we do here is to call
+ RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
+ structure. Afterwards, compute the address of that structure
+ utilizing the fact that the buffer address in the user process
+ parameter block is actually pointing to the buffer in that
+ FAST_CWD structure. Then replace the directory handle in that
+ structure with our own handle and close the original one.
+
+ Note that the call to RtlSetCurrentDirectory_U also closes our
+ old dir handle, so there won't be any handle left open.
+
+ This method is prone to two race conditions:
+
+ - Due to the way RtlSetCurrentDirectory_U opens the directory
+ handle, the directory is locked against deletion or renaming
+ between the RtlSetCurrentDirectory_U and the subsequent NtClose
+ call.
+
+ - When another thread calls SetCurrentDirectory at exactly the
+ same time, a crash might occur, or worse, unrelated data could
+ be overwritten or NtClose could be called on an unrelated handle.
+
+ Therefore, use this *only* as a fallback. */
+ if (!init)
+ {
+ status = RtlSetCurrentDirectory_U (error ? &ro_u_pipedir
+ : &win32);
+ if (!NT_SUCCESS (status))
+ {
+ debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
+ error ? &ro_u_pipedir : &win32, status);
+ return;
+ }
+ }
+ RtlEnterCriticalSection (peb.FastPebLock);
+ PFAST_CWD f_cwd = (PFAST_CWD)
+ ((PBYTE) upp_cwd_str.Buffer
+ - __builtin_offsetof (struct _FAST_CWD, Buffer));
+ h = upp_cwd_hdl;
+ f_cwd->DirectoryHandle = 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
+ have to close it here. */
+ NtClose (h);
+ }
+ }
+ else
+ {
+ /* This method is used for all pre-Vista OSes. We simply set the values
+ for the CWD in the user process parameter block entirely by ourselves
+ under PEB lock condition. This is how RtlSetCurrentDirectory_U worked
+ in these older OSes, so we're safe.
+
+ Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
+ on pre-Vista. RtlAcquirePebLock was way more complicated back then. */
+ RtlAcquirePebLock ();
+ if (!init)
+ copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
+ h = upp_cwd_hdl;
+ upp_cwd_hdl = dir;
+ RtlReleasePebLock ();
+ /* Only on init, the handle is potentially a native handle. However,
+ if it's identical to dir, it's the inherited handle from a Cygwin
+ parent process and must not be closed. */
+ if (h && h != dir)
+ NtClose (h);
+ }
}
/* Initialize cygcwd 'muto' for serializing access to cwd info. */
@@ -3366,12 +3638,13 @@ cwdstuff::init ()
cwd_lock.init ("cwd_lock");
/* Cygwin processes inherit the cwd from their parent. If the win32 path
- buffer is not NULL, the cwd struct is already set up. */
+ buffer is not NULL, the cwd struct is already set up, and we only
+ have to override the Win32 CWD with ours. */
if (win32.Buffer)
- return;
-
- /* Initially re-open the cwd to allow POSIX semantics. */
- set (NULL, NULL);
+ override_win32_cwd (true, SharedUserData.DismountCount);
+ else
+ /* Initially re-open the cwd to allow POSIX semantics. */
+ set (NULL, NULL);
}
/* Chdir and fill out the elements of a cwdstuff struct. */
@@ -3380,6 +3653,7 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
{
NTSTATUS status;
UNICODE_STRING upath;
+ PEB &peb = *NtCurrentTeb ()->Peb;
bool virtual_path = false;
bool unc_path = false;
bool inaccessible_path = false;
@@ -3430,6 +3704,13 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
virtual_path = true;
}
+ /* Memorize old DismountCount before opening the dir. This value is
+ stored in the FAST_CWD structure on Vista and later. It would be
+ simpler to fetch the old DismountCount in override_win32_cwd, but
+ Windows also fetches it before opening the directory handle. It's
+ not quite clear if that's really required, but since we don't know
+ the side effects of this action, we better follow Windows' lead. */
+ ULONG old_dismount_count = SharedUserData.DismountCount;
/* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
sharing flags set. The handle is right now used in exceptions.cc only,
but that might change in future. */
@@ -3447,7 +3728,7 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
RtlInitUnicodeString (&upath, L"");
InitializeObjectAttributes (&attr, &upath,
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
- get_user_proc_parms ()->CurrentDirectoryHandle, NULL);
+ peb.ProcessParameters->CurrentDirectoryHandle, NULL);
}
else
InitializeObjectAttributes (&attr, &upath,
@@ -3477,9 +3758,10 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
return -1;
}
}
- /* Set new handle. It's only used when creating stackdumps so far. */
- if (dir)
- NtClose (dir);
+ /* Set new handle. Note that we simply overwrite the old handle here
+ without closing it. The handle is also used as Win32 CWD handle in
+ the user parameter block, and it will be closed in override_win32_cwd,
+ if required. */
dir = h;
if (!nat_cwd)
@@ -3487,7 +3769,7 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
/* On init, just fetch the Win32 dir from the PEB. We can access
the PEB without lock, because no other thread can change the CWD
at that time. */
- PUNICODE_STRING pdir = &get_user_proc_parms ()->CurrentDirectoryName;
+ PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
RtlInitEmptyUnicodeString (&win32,
(PWCHAR) crealloc_abort (win32.Buffer,
pdir->Length
@@ -3568,13 +3850,7 @@ cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
}
/* Keep the Win32 CWD in sync. Don't check for error, other than for
strace output. Try to keep overhead low. */
- if (nat_cwd)
- {
- status = RtlSetCurrentDirectory_U (error ? &ro_u_pipedir : &win32);
- if (!NT_SUCCESS (status))
- debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
- error ? &ro_u_pipedir : &win32, status);
- }
+ override_win32_cwd (!nat_cwd, old_dismount_count);
/* Eventually, create POSIX path if it's not set on entry. */
tmp_pathbuf tp;
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index 2cf562c57..7f1688516 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -60,6 +60,7 @@ wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) =
has_localenames:false,
has_mwmo_inputavailable:false,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -99,6 +100,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -138,6 +140,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) =
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -177,6 +180,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -216,6 +220,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -255,6 +260,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -294,6 +300,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:false,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:false,
};
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -333,6 +340,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:true,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:true,
+ has_fast_cwd:true,
};
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -372,6 +380,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_localenames:true,
has_mwmo_inputavailable:true,
has_buggy_thread_startup:false,
+ has_fast_cwd:true,
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 315d4d51e..decfc1e50 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -50,6 +50,7 @@ struct wincaps
unsigned has_localenames : 1;
unsigned has_mwmo_inputavailable : 1;
unsigned has_buggy_thread_startup : 1;
+ unsigned has_fast_cwd : 1;
};
class wincapc
@@ -105,6 +106,7 @@ public:
bool IMPLEMENT (has_localenames)
bool IMPLEMENT (has_mwmo_inputavailable)
bool IMPLEMENT (has_buggy_thread_startup)
+ bool IMPLEMENT (has_fast_cwd)
#undef IMPLEMENT
};