From cbe2437b281270f1647ba63fb16aa4d6ed07298d Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 16 Jan 2007 18:01:06 +0000 Subject: * autoload.cc (RtlAnsiStringToUnicodeString): Define. (RtlOemStringToUnicodeString): Define. * ntdll.h (struct _RTL_USER_PROCESS_PARAMETERS): Define. (struct _PEB): Redefine with a bit of content. (RtlAnsiStringToUnicodeString): Declare. (RtlOemStringToUnicodeString): Declare. * path.cc: Include ntdll.h. (_upp): New global variable pointing to user process parameter block. (get_user_proc_parms): New static function to retrieve user process parameter block. (close_user_proc_parms_cwd_handle): New function to close handle to current working directory in user process parameter block. (cwdstuff::init): Drop redundant declaration of dynamically_loaded. Set current dir only on 9x. Call close_user_proc_parms_cwd_handle on NT instead. (cwdstuff::keep_in_sync): Only on 9x. (cwdstuff::set): Keep behaviour on 9x. On NT write cwd path into user process parameter block and set cwd handle to NULL. Fix comments to reflect new behaviour. --- winsup/cygwin/path.cc | 89 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 15 deletions(-) (limited to 'winsup/cygwin/path.cc') diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index bbc023968..287c6f69b 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -77,6 +77,7 @@ details. */ #include "cygtls.h" #include "environ.h" #include +#include bool dos_file_warning = true; static int normalize_win32_path (const char *, char *, char *&); @@ -4153,18 +4154,50 @@ cwdstuff::get_hash () extern char windows_system_directory[]; +static PRTL_USER_PROCESS_PARAMETERS _upp NO_COPY; + +static PRTL_USER_PROCESS_PARAMETERS +get_user_proc_parms () +{ + if (!_upp) + { + NTSTATUS stat; + PROCESS_BASIC_INFORMATION pbi; + stat = NtQueryInformationProcess (GetCurrentProcess (), + ProcessBasicInformation, + &pbi, sizeof pbi, NULL); + if (!NT_SUCCESS (stat)) + api_fatal ("Can't retrieve process parameters, status %p", stat); + _upp = pbi.PebBaseAddress->ProcessParameters; + } + return _upp; +} + +static void +close_user_proc_parms_cwd_handle () +{ + PHANDLE phdl = &get_user_proc_parms ()->CurrentDirectoryHandle; + if (*phdl) + { + NtClose (*phdl); + *phdl = NULL; + } +} + /* Initialize cygcwd 'muto' for serializing access to cwd info. */ void cwdstuff::init () { - extern int dynamically_loaded; cwd_lock.init ("cwd_lock"); get_initial (); if (!dynamically_loaded && !keep_in_sync ()) { - /* Actually chdir into the system dir to avoid cwd problems. See comment - in cwdstuff::set below. */ - SetCurrentDirectory (windows_system_directory); + /* Actually chdir into the system dir to avoid cwd problems on 9x. + See comment in cwdstuff::set below. */ + if (!wincap.can_open_directories ()) + SetCurrentDirectory (windows_system_directory); + else + close_user_proc_parms_cwd_handle (); } cwd_lock.release (); } @@ -4172,12 +4205,14 @@ cwdstuff::init () void cwdstuff::keep_in_sync (bool val) { - sync = val; - SetCurrentDirectory (val ? win32 : windows_system_directory); + if (!wincap.can_open_directories ()) + { + sync = val; + SetCurrentDirectory (val ? win32 : windows_system_directory); + } } -/* Get initial cwd. Should only be called once in a - process tree. */ +/* Get initial cwd. Should only be called once in a process tree. */ bool cwdstuff::get_initial () { @@ -4209,7 +4244,7 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd, bool doit) /* If a Cygwin application called cygwin_internal(CW_SYNC_WINENV), then it's about to call native Windows functions. This also sets the keep_in_sync flag so that we actually chdir into the - native directory to avoid confusion. */ + native directory on 9x to avoid confusion. */ if (!SetCurrentDirectory (win32_cwd)) { __seterrno (); @@ -4218,13 +4253,20 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd, bool doit) } else { - /* Check if we *could* chdir, if we actually would. - - Why don't we actually chdir? For two reasons: + /* We don't actually chdir on 9x but stay in the system dir. + + On NT we utilize the user parameter block. The directory is + stored manually, but the handle to the directory is always + closed and set to NULL. This way the directory isn't blocked + even if it's the cwd of a Cygwin process. + + Why the hassle? + - A process has always an open handle to the current working directory which disallows manipulating this directory. - POSIX allows to remove a directory if the permissions are - ok. The fact that its the cwd of some process doesn't matter. + POSIX allows to remove a directory if the permissions are ok. + The fact that its the cwd of some process doesn't matter. + - SetCurrentDirectory fails for directories with strict permissions even for processes with the SE_BACKUP_NAME privilege enabled. The reason is apparently that @@ -4243,7 +4285,7 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd, bool doit) } if (wincap.can_open_directories ()) { - HANDLE h = CreateFile (win32_cwd, GENERIC_READ, + HANDLE h = CreateFile (win32_cwd, FILE_TRAVERSE, wincap.shared (), NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) @@ -4251,6 +4293,23 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd, bool doit) __seterrno (); goto out; } + ULONG len = strlen (win32_cwd); + ANSI_STRING as = {len, len + 2, (PCHAR) alloca (len + 2)}; + strcpy (as.Buffer, win32_cwd); + if (as.Buffer[len - 1] != '\\') + { + strcpy (as.Buffer + len, "\\"); + ++as.Length; + } + if (current_codepage == ansi_cp) + RtlAnsiStringToUnicodeString ( + &get_user_proc_parms ()->CurrentDirectoryName, + &as, FALSE); + else + RtlOemStringToUnicodeString ( + &get_user_proc_parms ()->CurrentDirectoryName, + &as, FALSE); + close_user_proc_parms_cwd_handle (); CloseHandle (h); } } -- cgit v1.2.3