diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2007-10-23 20:26:28 +0400 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2007-10-23 20:26:28 +0400 |
commit | 09ecdc85044c736c25ac58c0f37b3fb5394c2733 (patch) | |
tree | 158a991568397076fdbcca8e4f659241a4ef44d8 /winsup | |
parent | 5b9de9d9563f4fc14ab3982a61c51cb56fb75946 (diff) |
* cygheap.h (struct cwdstuff): Drop hash member. Drop get_hash,
get_initial, and fixup_after_exec declarations.
Convert win32 to UNICODE_STRING.
(cwdstuff::get_drive): Convert win32 path in current codepage.
(cwdstuff::set): Take native NT path.
* ntdll.h (struct _TEB): Typedef.
* path.cc (mount_info::conv_to_posix_path): Add variant taking
wide char DOS paths.
(symlink_info::posixify): Simplify concatenating cwd and relative path.
(hash_path_name): Drop special relative path handling.
(chdir): Drop special "drive only" handling. Call cwdstuff::set with
native path.
(cwdstuff::get_hash): Remove.
(windows_system_directory): Remove.
(_upp): Remove.
(get_user_proc_parms): Make inline. Get PEB pointer by calling
NtCurrentTeb.
(cwdstuff::init): Simplify.
(cwdstuff::set): Rework to handle incoming native NT path. Workaround
a Vista problem with CWD handle in the user process parameter block.
(cwdstuff::get): Simplify locking. Accommodate type change of win32.
* shared_info.h (mount_info): Add declaration for new conv_to_posix_path
method.
* strfuncs.cc (sys_wcstombs): Return correct length of created
multi-byte string.
Diffstat (limited to 'winsup')
-rw-r--r-- | winsup/cygwin/ChangeLog | 28 | ||||
-rw-r--r-- | winsup/cygwin/cygheap.h | 14 | ||||
-rw-r--r-- | winsup/cygwin/ntdll.h | 8 | ||||
-rw-r--r-- | winsup/cygwin/path.cc | 374 | ||||
-rw-r--r-- | winsup/cygwin/shared_info.h | 2 | ||||
-rw-r--r-- | winsup/cygwin/strfuncs.cc | 5 |
6 files changed, 245 insertions, 186 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a6a26e72c..ea5d69aad 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2007-10-22 Corinna Vinschen <corinna@vinschen.de> + + * cygheap.h (struct cwdstuff): Drop hash member. Drop get_hash, + get_initial, and fixup_after_exec declarations. + Convert win32 to UNICODE_STRING. + (cwdstuff::get_drive): Convert win32 path in current codepage. + (cwdstuff::set): Take native NT path. + * ntdll.h (struct _TEB): Typedef. + * path.cc (mount_info::conv_to_posix_path): Add variant taking + wide char DOS paths. + (symlink_info::posixify): Simplify concatenating cwd and relative path. + (hash_path_name): Drop special relative path handling. + (chdir): Drop special "drive only" handling. Call cwdstuff::set with + native path. + (cwdstuff::get_hash): Remove. + (windows_system_directory): Remove. + (_upp): Remove. + (get_user_proc_parms): Make inline. Get PEB pointer by calling + NtCurrentTeb. + (cwdstuff::init): Simplify. + (cwdstuff::set): Rework to handle incoming native NT path. Workaround + a Vista problem with CWD handle in the user process parameter block. + (cwdstuff::get): Simplify locking. Accommodate type change of win32. + * shared_info.h (mount_info): Add declaration for new conv_to_posix_path + method. + * strfuncs.cc (sys_wcstombs): Return correct length of created + multi-byte string. + 2007-10-19 Corinna Vinschen <corinna@vinschen.de> * fhandler_disk_file.cc (__DIR_mounts::eval_ino): Make fname big enough diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 212578612..bf93e4633 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -222,23 +222,19 @@ class muto; struct cwdstuff { char *posix; - char *win32; - DWORD hash; + UNICODE_STRING win32; DWORD drive_length; static muto cwd_lock; char *get (char *, int = 1, int = 0, unsigned = CYG_MAX_PATH); - DWORD get_hash (); DWORD get_drive (char * dst) { - get_initial (); - memcpy (dst, win32, drive_length); + cwd_lock.acquire (); + DWORD ret = sys_wcstombs (dst, PATH_MAX, win32.Buffer, drive_length); cwd_lock.release (); - return drive_length; + return ret; } void init (); - void fixup_after_exec (char *, char *, DWORD); - bool get_initial (); - int set (const char *, const char *, bool); + int set (PUNICODE_STRING, const char *, bool); }; #ifdef DEBUGGING diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index d74095a57..60651e82c 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -527,6 +527,14 @@ typedef struct _PEB ULONG SessionId; } PEB, *PPEB; +/* Simplifed definition, just to get the PEB pointer. */ +typedef struct _TEB +{ + PVOID dummy[12]; + PPEB Peb; + /* A lot more follows... */ +} TEB, *PTEB; + typedef struct _PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 108ac67e7..6720f1d6b 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1947,6 +1947,32 @@ mount_info::cygdrive_win32_path (const char *src, char *dst, int& unit) posix_path must have sufficient space (i.e. CYG_MAX_PATH bytes). If keep_rel_p is non-zero, relative paths stay that way. */ +/* TODO: Change conv_to_posix_path to work with native paths. */ + +/* src_path is a wide Win32 path. */ +int +mount_info::conv_to_posix_path (PWCHAR src_path, char *posix_path, + int keep_rel_p) +{ + bool changed = false; + if (!wcsncmp (src_path, L"\\\\?\\", 4)) + { + src_path += 4; + if (!wcsncmp (src_path, L"UNC\\", 4)) + { + src_path += 2; + src_path[0] = L'\\'; + changed = true; + } + } + char buf[PATH_MAX]; + sys_wcstombs (buf, PATH_MAX, src_path, 0); + int ret = conv_to_posix_path (buf, posix_path, keep_rel_p); + if (changed) + src_path[0] = L'C'; + return ret; +} + int mount_info::conv_to_posix_path (const char *src_path, char *posix_path, int keep_rel_p) @@ -3357,8 +3383,7 @@ symlink_info::posixify (char *srcbuf) { char cvtbuf[SYMLINK_MAX + 1]; - strncpy (cvtbuf, cygheap->cwd.win32, 2); - strcpy (cvtbuf + 2, srcbuf); + stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf); mount_table->conv_to_posix_path (cvtbuf, contents, 0); } } @@ -3868,18 +3893,6 @@ hash_path_name (__ino64_t hash, PUNICODE_STRING name) if (name->Length == 0) return hash; - /* Fill out the hashed path name with the current working directory if - this is not an absolute path and there is no pre-specified hash value. - Otherwise the inodes same will differ depending on whether a file is - referenced with an absolute value or relatively. */ - if (!hash && !isabspath_u (name)) - { - hash = cygheap->cwd.get_hash (); - if (name->Length == sizeof (WCHAR) && name->Buffer[0] == L'.') - return hash; - hash = L'\\' + (hash << 6) + (hash << 16) - hash; - } - /* Build up hash. Name is already normalized */ USHORT len = name->Length / sizeof (WCHAR); for (USHORT idx = 0; idx < len; ++idx) @@ -3954,19 +3967,10 @@ chdir (const char *in_dir) int res = -1; bool doit = false; - const char *native_dir = path.get_win32 (), *posix_cwd = NULL; + const char *posix_cwd = NULL; int devn = path.get_devn (); if (!isvirtual_dev (devn)) { - /* Check to see if path translates to something like C:. - If it does, append a \ to the native directory specification to - defeat the Windows 95 (i.e. MS-DOS) tendency of returning to - the last directory visited on the given drive. */ - if (isdrive (native_dir) && !native_dir[2]) - { - path.get_win32 ()[2] = '\\'; - path.get_win32 ()[3] = '\0'; - } /* The sequence chdir("xx"); chdir(".."); must be a noop if xx is not a symlink. This is exploited by find.exe. The posix_cwd is just path.normalized_path. @@ -3988,12 +3992,12 @@ chdir (const char *in_dir) } if (!res) - res = cygheap->cwd.set (native_dir, posix_cwd, doit); + res = cygheap->cwd.set (path.get_nt_native_path (), posix_cwd, doit); /* Note that we're accessing cwd.posix without a lock here. I didn't think it was worth locking just for strace. */ - syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%s'", res, - cygheap->cwd.posix, native_dir); + syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%S'", res, + cygheap->cwd.posix, path.get_nt_native_path ()); MALLOC_CHECK; return res; } @@ -4339,37 +4343,10 @@ cygwin_split_path (const char *path, char *dir, char *file) /*****************************************************************************/ -/* Return the hash value for the current win32 value. - This is used when constructing inodes. */ -DWORD -cwdstuff::get_hash () -{ - DWORD hashnow; - cwd_lock.acquire (); - hashnow = hash; - cwd_lock.release (); - return hashnow; -} - -extern char windows_system_directory[]; - -static PRTL_USER_PROCESS_PARAMETERS _upp NO_COPY; - -static PRTL_USER_PROCESS_PARAMETERS +static inline 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; + return NtCurrentTeb ()->Peb->ProcessParameters; } /* Initialize cygcwd 'muto' for serializing access to cwd info. */ @@ -4377,146 +4354,189 @@ void cwdstuff::init () { cwd_lock.init ("cwd_lock"); - get_initial (); /* Initially re-open the cwd to allow POSIX semantics. */ - set (win32, posix, true); - cwd_lock.release (); + set (NULL, NULL, true); } -/* Get initial cwd. Should only be called once in a process tree. */ -bool -cwdstuff::get_initial () +/* Chdir and fill out the elements of a cwdstuff struct. */ +int +cwdstuff::set (PUNICODE_STRING nat_cwd, const char *posix_cwd, bool doit) { + int res = 0; + UNICODE_STRING upath; + size_t len = 0; + cwd_lock.acquire (); - if (win32) - return 1; + if (nat_cwd) + { + upath = *nat_cwd; + if (upath.Buffer[0] == L'/') /* Virtual path. Never use in PEB. */ + doit = false; + else + { + len = upath.Length / sizeof (WCHAR) - 4; + if (RtlEqualUnicodePathPrefix (&upath, L"\\??\\UNC\\", TRUE)) + len -= 2; + } + } - /* Leaves cwd lock unreleased, if success */ - return !set (NULL, NULL, false); -} + if (doit) + { + /* We utilize the user parameter block. The directory is + stored manually there. Why the hassle? -/* Chdir and fill out the elements of a cwdstuff struct. - It is assumed that the lock for the cwd is acquired if - win32_cwd == NULL. */ -int -cwdstuff::set (const char *win32_cwd, const char *posix_cwd, bool doit) -{ - char pathbuf[2 * CYG_MAX_PATH]; - int res = -1; + - SetCurrentDirectory fails for directories with strict + permissions even for processes with the SE_BACKUP_NAME + privilege enabled. The reason is apparently that + SetCurrentDirectory calls NtOpenFile without the + FILE_OPEN_FOR_BACKUP_INTENT flag set. - if (win32_cwd) - { - cwd_lock.acquire (); - if (doit) + - Unlinking a cwd fails because SetCurrentDirectory seems to + open directories so that deleting the directory is disallowed. + The below code opens with *all* sharing flags set. */ + HANDLE h; + NTSTATUS status; + IO_STATUS_BLOCK io; + OBJECT_ATTRIBUTES attr; + PHANDLE phdl; + + RtlAcquirePebLock (); + phdl = &get_user_proc_parms ()->CurrentDirectoryHandle; + if (!nat_cwd) /* On init, just reopen CWD with desired access flags. */ + RtlInitUnicodeString (&upath, L""); + else { - /* We utilize the user parameter block. The directory is - stored manually there. Why the hassle? - - - SetCurrentDirectory fails for directories with strict - permissions even for processes with the SE_BACKUP_NAME - privilege enabled. The reason is apparently that - SetCurrentDirectory calls NtOpenFile without the - FILE_OPEN_FOR_BACKUP_INTENT flag set. - - - Unlinking a cwd fails because SetCurrentDirectory seems to - open directories so that deleting the directory is disallowed. - The below code opens with *all* sharing flags set. */ - HANDLE h; - DWORD attr = GetFileAttributes (win32_cwd); - if (attr == INVALID_FILE_ATTRIBUTES) - { - set_errno (ENOENT); - goto out; - } - if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) - { - set_errno (ENOTDIR); - goto out; - } - h = CreateFile (win32_cwd, FILE_TRAVERSE, FILE_SHARE_VALID_FLAGS, - &sec_none, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, - NULL); - if (h == INVALID_HANDLE_VALUE) - { - __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] != '\\') + /* TODO: + Check the length of the new CWD. Windows can only handle + CWDs of up to MAX_PATH length, including a trailing backslash. + If the path is longer, it's not an error condition for Cygwin, + so we don't fail. Windows on the other hand has a problem now. + For now, we just don't store the path in the PEB and proceed as + usual. */ + if (len > MAX_PATH - (nat_cwd->Buffer[len - 1] == L'\\' ? 1 : 2)) + goto skip_peb_storing; + } + InitializeObjectAttributes (&attr, &upath, + OBJ_CASE_INSENSITIVE | OBJ_INHERIT, + nat_cwd ? NULL : *phdl, NULL); + status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_DIRECTORY_FILE + | FILE_SYNCHRONOUS_IO_NONALERT + | FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) + { + RtlReleasePebLock (); + __seterrno_from_nt_status (status); + res = -1; + goto out; + } + + if (nat_cwd) /* No need to set path on init. */ + { + /* Convert to a Win32 path. */ + upath.Buffer += upath.Length / sizeof (WCHAR) - len; + if (upath.Buffer[1] == L'\\') /* UNC path */ + upath.Buffer[0] = L'\\'; + upath.Length = len * sizeof (WCHAR); + /* Append backslash if necessary. */ + if (upath.Buffer[len - 1] != L'\\') { - strcpy (as.Buffer + len, "\\"); - ++as.Length; + upath.Buffer[len] = L'\\'; + upath.Length += sizeof (WCHAR); } - RtlAcquirePebLock (); - if (current_codepage == ansi_cp) - RtlAnsiStringToUnicodeString ( - &get_user_proc_parms ()->CurrentDirectoryName, - &as, FALSE); - else - RtlOemStringToUnicodeString ( - &get_user_proc_parms ()->CurrentDirectoryName, - &as, FALSE); - PHANDLE phdl = &get_user_proc_parms ()->CurrentDirectoryHandle; - if (*phdl) - CloseHandle (*phdl); - *phdl = h; - RtlReleasePebLock (); + RtlCopyUnicodeString (&get_user_proc_parms ()->CurrentDirectoryName, + &upath); } + NtClose (*phdl); + /* Workaround a problem in Vista which fails in subsequent calls to + CreateFile with ERROR_INVALID_HANDLE if the handle in + CurrentDirectoryHandle changes without calling SetCurrentDirectory, + and the filename given to CreateFile is a relative path. It looks + like Vista stores a copy of the CWD handle in some other undocumented + place. The NtClose/DuplicateHandle reuses the original handle for + the copy of the new handle and the next CreateFile works. + Note that this is not thread-safe (yet?) */ + if (DuplicateHandle (GetCurrentProcess (), h, GetCurrentProcess (), phdl, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + NtClose (h); + else + *phdl = h; + +skip_peb_storing: + + RtlReleasePebLock (); } - /* If there is no win32 path or it has the form c:xxx, get the value */ - if (!win32_cwd || (isdrive (win32_cwd) && win32_cwd[2] != '\\')) + + if (nat_cwd || !win32.Buffer) { - int i; - DWORD len, dlen; - for (i = 0, dlen = CYG_MAX_PATH/3; i < 2; i++, dlen = len) + /* If there is no win32 path */ + if (!nat_cwd) { - win32 = (char *) crealloc (win32, dlen); - if ((len = GetCurrentDirectoryA (dlen, win32)) < dlen) - break; + PUNICODE_STRING pdir; + + RtlAcquirePebLock (); + pdir = &get_user_proc_parms ()->CurrentDirectoryName; + RtlInitEmptyUnicodeString (&win32, + (PWCHAR) crealloc (win32.Buffer, + pdir->Length + 2), + pdir->Length + 2); + RtlCopyUnicodeString (&win32, pdir); + RtlReleasePebLock (); + /* Remove trailing slash. */ + if (win32.Length > 3 * sizeof (WCHAR)) + win32.Length -= sizeof (WCHAR); + posix_cwd = NULL; } - if (len == 0) + else { - __seterrno (); - debug_printf ("GetCurrentDirectory, %E"); - win32_cwd = pathbuf; /* Force lock release */ - goto out; + if (upath.Buffer[0] == L'/') /* Virtual path, don't mangle. */ + ; + else if (!doit) + { + /* Convert to a Win32 path. */ + upath.Buffer += upath.Length / sizeof (WCHAR) - len; + if (upath.Buffer[1] == L'\\') /* UNC path */ + upath.Buffer[0] = L'\\'; + upath.Length = len * sizeof (WCHAR); + } + else if (upath.Length > 3 * sizeof (WCHAR)) + upath.Length -= sizeof (WCHAR); /* Strip trailing backslash */ + RtlInitEmptyUnicodeString (&win32, + (PWCHAR) crealloc (win32.Buffer, + upath.Length + 2), + upath.Length + 2); + RtlCopyUnicodeString (&win32, &upath); } - posix_cwd = NULL; - } - else - { - win32 = (char *) crealloc (win32, strlen (win32_cwd) + 1); - strcpy (win32, win32_cwd); - } - if (win32[1] == ':') - drive_length = 2; - else if (win32[1] == '\\') - { - char * ptr = strechr (win32 + 2, '\\'); - if (*ptr) - ptr = strechr (ptr + 1, '\\'); - drive_length = ptr - win32; - } - else - drive_length = 0; + /* Make sure it's NUL-termniated. */ + win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0'; + if (win32.Buffer[1] == L':') + drive_length = 2; + else if (win32.Buffer[1] == L'\\') + { + PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\'); + if (*ptr) + ptr = wcschr (ptr + 1, L'\\'); + if (ptr) + drive_length = ptr - win32.Buffer; + else + drive_length = win32.Length / sizeof (WCHAR); + } + else + drive_length = 0; - if (!posix_cwd) - { - mount_table->conv_to_posix_path (win32, pathbuf, 0); - posix_cwd = pathbuf; + if (!posix_cwd) + { + posix_cwd = (const char *) alloca (PATH_MAX); + mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0); + } + posix = (char *) crealloc (posix, strlen (posix_cwd) + 1); + stpcpy (posix, posix_cwd); } - posix = (char *) crealloc (posix, strlen (posix_cwd) + 1); - strcpy (posix, posix_cwd); - hash = hash_path_name (0, win32); - - res = 0; out: - if (win32_cwd) - cwd_lock.release (); + cwd_lock.release (); return res; } @@ -4536,12 +4556,14 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen) goto out; } - if (!get_initial ()) /* Get initial cwd and set cwd lock */ - return NULL; + cwd_lock.acquire (); char *tocopy; if (!need_posix) - tocopy = win32; + { + tocopy = (char *) alloca (PATH_MAX); + sys_wcstombs (tocopy, PATH_MAX, win32.Buffer, win32.Length); + } else tocopy = posix; diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index fc5bc8625..dc345d30f 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -82,6 +82,8 @@ class mount_info unsigned set_flags_from_win32_path (const char *path); int conv_to_win32_path (const char *src_path, char *dst, device&, unsigned *flags = NULL); + int conv_to_posix_path (PWCHAR src_path, char *posix_path, + int keep_rel_p); int conv_to_posix_path (const char *src_path, char *posix_path, int keep_rel_p); struct mntent *getmntent (int x); diff --git a/winsup/cygwin/strfuncs.cc b/winsup/cygwin/strfuncs.cc index 91ed160c3..9d0e3ec08 100644 --- a/winsup/cygwin/strfuncs.cc +++ b/winsup/cygwin/strfuncs.cc @@ -32,7 +32,10 @@ sys_wcstombs (char *tgt, int tlen, const WCHAR *src, int slen) ret = WideCharToMultiByte (get_cp (), 0, src, slen, tgt, tlen, NULL, NULL); if (ret) - tgt[ret < tlen ? ret : tlen - 1] = '\0'; + { + ret = (ret < tlen) ? ret : tlen - 1; + tgt[ret] = '\0'; + } return ret; } |