* 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.
This commit is contained in:
Corinna Vinschen
2007-01-16 18:01:06 +00:00
parent c4c8d06b1a
commit cbe2437b28
4 changed files with 144 additions and 16 deletions

View File

@ -77,6 +77,7 @@ details. */
#include "cygtls.h"
#include "environ.h"
#include <assert.h>
#include <ntdll.h>
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);
}
}