diff --git a/dlls/kernel/kernel_private.h b/dlls/kernel/kernel_private.h index ac460c9ec8a..5054cd70234 100644 --- a/dlls/kernel/kernel_private.h +++ b/dlls/kernel/kernel_private.h @@ -62,6 +62,8 @@ extern VOID SYSLEVEL_CheckNotLevel( INT level ); extern DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ); extern void INSTR_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum ); +extern WCHAR *MODULE_get_dll_load_path( LPCWSTR module ); + extern BOOL NLS_IsUnicodeOnlyLcid(LCID); extern WORD SELECTOR_AllocBlock( const void *base, DWORD size, unsigned char flags ); diff --git a/dlls/kernel/module.c b/dlls/kernel/module.c index 1bb41d827ec..ddb12a1b247 100644 --- a/dlls/kernel/module.c +++ b/dlls/kernel/module.c @@ -507,42 +507,35 @@ DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size */ static const WCHAR *get_dll_system_path(void) { - static WCHAR *path; + static WCHAR *cached_path; - if (!path) + if (!cached_path) { - WCHAR *p, *exe_name; + WCHAR *p, *path; int len = 3; - exe_name = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; - if (!(p = strrchrW( exe_name, '\\' ))) p = exe_name; - /* include trailing backslash only on drive root */ - if (p == exe_name + 2 && exe_name[1] == ':') p++; - len += p - exe_name; len += GetSystemDirectoryW( NULL, 0 ); len += GetWindowsDirectoryW( NULL, 0 ); - path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - memcpy( path, exe_name, (p - exe_name) * sizeof(WCHAR) ); - p = path + (p - exe_name); - *p++ = ';'; + p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); *p++ = '.'; *p++ = ';'; GetSystemDirectoryW( p, path + len - p); p += strlenW(p); *p++ = ';'; GetWindowsDirectoryW( p, path + len - p); + cached_path = path; } - return path; + return cached_path; } /****************************************************************** - * get_dll_load_path + * MODULE_get_dll_load_path * * Compute the load path to use for a given dll. * Returned pointer must be freed by caller. */ -static WCHAR *get_dll_load_path( LPCWSTR module ) +WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) { static const WCHAR pathW[] = {'P','A','T','H',0}; @@ -554,6 +547,7 @@ static WCHAR *get_dll_load_path( LPCWSTR module ) /* adjust length for module name */ + if (!module) module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; if (module) { mod_end = module; @@ -561,8 +555,7 @@ static WCHAR *get_dll_load_path( LPCWSTR module ) if ((p = strrchrW( mod_end, '/' ))) mod_end = p; if (mod_end == module + 2 && module[1] == ':') mod_end++; if (mod_end == module && module[0] && module[1] == ':') mod_end += 2; - len += (mod_end - module); - system_path = strchrW( system_path, ';' ); + len += (mod_end - module) + 1; } len += strlenW( system_path ) + 2; @@ -581,6 +574,7 @@ static WCHAR *get_dll_load_path( LPCWSTR module ) { memcpy( ret, module, (mod_end - module) * sizeof(WCHAR) ); p += (mod_end - module); + *p++ = ';'; } strcpyW( p, system_path ); p += strlenW(p); @@ -608,18 +602,6 @@ static WCHAR *get_dll_load_path( LPCWSTR module ) } -/****************************************************************** - * MODULE_InitLoadPath - * - * Create the initial dll load path. - */ -void MODULE_InitLoadPath(void) -{ - WCHAR *path = get_dll_load_path( NULL ); - RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath, path ); -} - - /****************************************************************** * load_library_as_datafile */ @@ -682,7 +664,7 @@ static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) /* Fallback to normal behaviour */ } - load_path = get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); + load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); nts = LdrLoadDll( load_path, flags, libname, &hModule ); HeapFree( GetProcessHeap(), 0, load_path ); if (nts != STATUS_SUCCESS) diff --git a/dlls/kernel/path.c b/dlls/kernel/path.c index 10299dcb7bb..a4c023dd83a 100644 --- a/dlls/kernel/path.c +++ b/dlls/kernel/path.c @@ -35,6 +35,7 @@ #include "winreg.h" #include "winternl.h" +#include "kernel_private.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -422,3 +423,156 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen RtlFreeUnicodeString(&longpathW); return ret; } + + +/*********************************************************************** + * contains_pathW + * + * Check if the file name contains a path; helper for SearchPathW. + * A relative path is not considered a path unless it starts with ./ or ../ + */ +inline static BOOL contains_pathW (LPCWSTR name) +{ + if (RtlDetermineDosPathNameType_U( name ) != RELATIVE_PATH) return TRUE; + if (name[0] != '.') return FALSE; + if (name[1] == '/' || name[1] == '\\') return TRUE; + return (name[1] == '.' && (name[2] == '/' || name[2] == '\\')); +} + + +/*********************************************************************** + * SearchPathW [KERNEL32.@] + * + * Searches for a specified file in the search path. + * + * PARAMS + * path [I] Path to search + * name [I] Filename to search for. + * ext [I] File extension to append to file name. The first + * character must be a period. This parameter is + * specified only if the filename given does not + * contain an extension. + * buflen [I] size of buffer, in characters + * buffer [O] buffer for found filename + * lastpart [O] address of pointer to last used character in + * buffer (the final '\') + * + * RETURNS + * Success: length of string copied into buffer, not including + * terminating null character. If the filename found is + * longer than the length of the buffer, the length of the + * filename is returned. + * Failure: Zero + * + * NOTES + * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND) + * (tested on NT 4.0) + */ +DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen, + LPWSTR buffer, LPWSTR *lastpart ) +{ + DWORD ret = 0; + + /* If the name contains an explicit path, ignore the path */ + + if (contains_pathW(name)) + { + /* try first without extension */ + if (RtlDoesFileExists_U( name )) + return GetFullPathNameW( name, buflen, buffer, lastpart ); + + if (ext) + { + LPCWSTR p = strrchrW( name, '.' ); + if (p && !strchrW( p, '/' ) && !strchrW( p, '\\' )) + ext = NULL; /* Ignore the specified extension */ + } + + /* Allocate a buffer for the file name and extension */ + if (ext) + { + LPWSTR tmp; + DWORD len = strlenW(name) + strlenW(ext); + + if (!(tmp = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + strcpyW( tmp, name ); + strcatW( tmp, ext ); + if (RtlDoesFileExists_U( tmp )) + ret = GetFullPathNameW( tmp, buflen, buffer, lastpart ); + HeapFree( GetProcessHeap(), 0, tmp ); + } + } + else if (path && path[0]) /* search in the specified path */ + { + ret = RtlDosSearchPath_U( path, name, ext, buflen * sizeof(WCHAR), + buffer, lastpart ) / sizeof(WCHAR); + } + else /* search in the default path */ + { + WCHAR *dll_path = MODULE_get_dll_load_path( NULL ); + + if (dll_path) + { + ret = RtlDosSearchPath_U( dll_path, name, ext, buflen * sizeof(WCHAR), + buffer, lastpart ) / sizeof(WCHAR); + HeapFree( GetProcessHeap(), 0, dll_path ); + } + else + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + } + + if (!ret) SetLastError( ERROR_FILE_NOT_FOUND ); + else TRACE( "found %s\n", debugstr_w(buffer) ); + return ret; +} + + +/*********************************************************************** + * SearchPathA (KERNEL32.@) + */ +DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, + DWORD buflen, LPSTR buffer, LPSTR *lastpart ) +{ + UNICODE_STRING pathW, nameW, extW; + WCHAR bufferW[MAX_PATH]; + DWORD ret, retW; + + if (path) RtlCreateUnicodeStringFromAsciiz(&pathW, path); + else pathW.Buffer = NULL; + if (name) RtlCreateUnicodeStringFromAsciiz(&nameW, name); + else nameW.Buffer = NULL; + if (ext) RtlCreateUnicodeStringFromAsciiz(&extW, ext); + else extW.Buffer = NULL; + + retW = SearchPathW(pathW.Buffer, nameW.Buffer, extW.Buffer, MAX_PATH, bufferW, NULL); + + if (!retW) + ret = 0; + else if (retW > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + ret = 0; + } + else + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); + if (buflen >= ret) + { + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buflen, NULL, NULL); + ret--; /* length without 0 */ + if (lastpart) *lastpart = strrchr(buffer, '\\') + 1; + } + } + + RtlFreeUnicodeString(&pathW); + RtlFreeUnicodeString(&nameW); + RtlFreeUnicodeString(&extW); + return ret; +} diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c index a8b24cadfe0..3bc7d3bf41d 100644 --- a/dlls/kernel/process.c +++ b/dlls/kernel/process.c @@ -84,7 +84,6 @@ static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0}; extern void SHELL_LoadRegistry(void); extern void VERSION_Init( const WCHAR *appname ); -extern void MODULE_InitLoadPath(void); extern void LOCALE_Init(void); /*********************************************************************** @@ -835,7 +834,8 @@ void __wine_kernel_init(void) TRACE( "starting process name=%s file=%p argv[0]=%s\n", debugstr_w(main_exe_name), main_exe_file, debugstr_a(__wine_main_argv[0]) ); - MODULE_InitLoadPath(); + RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath, + MODULE_get_dll_load_path(NULL) ); VERSION_Init( main_exe_name ); if (!main_exe_file) /* no file handle -> Winelib app */ diff --git a/files/directory.c b/files/directory.c index ca5464f5694..3bfc8cfce46 100644 --- a/files/directory.c +++ b/files/directory.c @@ -54,15 +54,6 @@ WINE_DECLARE_DEBUG_CHANNEL(file); static DOS_FULL_NAME DIR_Windows; static DOS_FULL_NAME DIR_System; -/*********************************************************************** - * FILE_contains_pathW - */ -inline static int FILE_contains_pathW (LPCWSTR name) -{ - return ((*name && (name[1] == ':')) || - strchrW (name, '/') || strchrW (name, '\\')); -} - /*********************************************************************** * DIR_GetPath * @@ -613,321 +604,3 @@ BOOL WINAPI RemoveDirectoryA( LPCSTR path ) SetLastError(ERROR_NOT_ENOUGH_MEMORY); return ret; } - - -/*********************************************************************** - * DIR_TryPath - * - * Helper function for DIR_SearchPath. - */ -static BOOL DIR_TryPath( const DOS_FULL_NAME *dir, LPCWSTR name, - DOS_FULL_NAME *full_name ) -{ - LPSTR p_l = full_name->long_name + strlen(dir->long_name) + 1; - LPWSTR p_s = full_name->short_name + strlenW(dir->short_name) + 1; - - if ((p_s >= full_name->short_name + sizeof(full_name->short_name)/sizeof(full_name->short_name[0]) - 14) || - (p_l >= full_name->long_name + sizeof(full_name->long_name) - 1)) - { - SetLastError( ERROR_PATH_NOT_FOUND ); - return FALSE; - } - if (!DOSFS_FindUnixName( dir, name, p_l, - sizeof(full_name->long_name) - (p_l - full_name->long_name), p_s )) - return FALSE; - - full_name->drive = dir->drive; - strcpy( full_name->long_name, dir->long_name ); - p_l[-1] = '/'; - strcpyW( full_name->short_name, dir->short_name ); - p_s[-1] = '\\'; - return TRUE; -} - -static BOOL DIR_SearchSemicolonedPaths(LPCWSTR name, DOS_FULL_NAME *full_name, LPWSTR pathlist) -{ - LPWSTR next, buffer = NULL; - INT len = strlenW(name), newlen, currlen = 0; - BOOL ret = FALSE; - - next = pathlist; - while (!ret && next) - { - static const WCHAR bkslashW[] = {'\\',0}; - LPWSTR cur = next; - while (*cur == ';') cur++; - if (!*cur) break; - next = strchrW( cur, ';' ); - if (next) *next++ = '\0'; - newlen = strlenW(cur) + len + 2; - - if (newlen > currlen) - { - if (buffer) - buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, newlen * sizeof(WCHAR)); - else - buffer = HeapAlloc( GetProcessHeap(), 0, newlen * sizeof(WCHAR)); - - if(!buffer) - goto done; - currlen = newlen; - } - - strcpyW( buffer, cur ); - strcatW( buffer, bkslashW ); - strcatW( buffer, name ); - ret = DOSFS_GetFullName( buffer, TRUE, full_name ); - } -done: - HeapFree( GetProcessHeap(), 0, buffer ); - return ret; -} - - -/*********************************************************************** - * DIR_TryEnvironmentPath - * - * Helper function for DIR_SearchPath. - * Search in the specified path, or in $PATH if NULL. - */ -static BOOL DIR_TryEnvironmentPath( LPCWSTR name, DOS_FULL_NAME *full_name, LPCWSTR envpath ) -{ - LPWSTR path; - BOOL ret = FALSE; - DWORD size; - static const WCHAR pathW[] = {'P','A','T','H',0}; - - size = envpath ? strlenW(envpath)+1 : GetEnvironmentVariableW( pathW, NULL, 0 ); - if (!size) return FALSE; - if (!(path = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; - if (envpath) strcpyW( path, envpath ); - else if (!GetEnvironmentVariableW( pathW, path, size )) goto done; - - ret = DIR_SearchSemicolonedPaths(name, full_name, path); - -done: - HeapFree( GetProcessHeap(), 0, path ); - return ret; -} - - -/*********************************************************************** - * DIR_TryModulePath - * - * Helper function for DIR_SearchPath. - */ -static BOOL DIR_TryModulePath( LPCWSTR name, DOS_FULL_NAME *full_name, BOOL win32 ) -{ - WCHAR bufferW[MAX_PATH]; - LPWSTR p; - - if (!win32) - { - char buffer[OFS_MAXPATHNAME]; - if (!GetCurrentTask()) return FALSE; - if (!GetModuleFileName16( GetCurrentTask(), buffer, sizeof(buffer) )) - return FALSE; - MultiByteToWideChar(CP_ACP, 0, buffer, -1, bufferW, MAX_PATH); - } else { - if (!GetModuleFileNameW( 0, bufferW, MAX_PATH ) ) - return FALSE; - } - if (!(p = strrchrW( bufferW, '\\' ))) return FALSE; - if (MAX_PATH - (++p - bufferW) <= strlenW(name)) return FALSE; - strcpyW( p, name ); - return DOSFS_GetFullName( bufferW, TRUE, full_name ); -} - - -/*********************************************************************** - * DIR_SearchPath - * - * Implementation of SearchPathA. 'win32' specifies whether the search - * order is Win16 (module path last) or Win32 (module path first). - * - * FIXME: should return long path names. - */ -DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext, - DOS_FULL_NAME *full_name, BOOL win32 ) -{ - LPCWSTR p; - LPWSTR tmp = NULL; - BOOL ret = TRUE; - - /* First check the supplied parameters */ - - p = strrchrW( name, '.' ); - if (p && !strchrW( p, '/' ) && !strchrW( p, '\\' )) - ext = NULL; /* Ignore the specified extension */ - if (FILE_contains_pathW (name)) - path = NULL; /* Ignore path if name already contains a path */ - if (path && !*path) path = NULL; /* Ignore empty path */ - - /* Allocate a buffer for the file name and extension */ - - if (ext) - { - DWORD len = strlenW(name) + strlenW(ext); - if (!(tmp = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) - { - SetLastError( ERROR_OUTOFMEMORY ); - return 0; - } - strcpyW( tmp, name ); - strcatW( tmp, ext ); - name = tmp; - } - - /* If the name contains an explicit path, everything's easy */ - - if (FILE_contains_pathW(name)) - { - ret = DOSFS_GetFullName( name, TRUE, full_name ); - goto done; - } - - /* Search in the specified path */ - - if (path) - { - ret = DIR_TryEnvironmentPath( name, full_name, path ); - goto done; - } - - /* Try the path of the current executable (for Win32 search order) */ - - if (win32 && DIR_TryModulePath( name, full_name, win32 )) goto done; - - /* Try the current directory */ - - if (DOSFS_GetFullName( name, TRUE, full_name )) goto done; - - /* Try the Windows system directory */ - - if (DIR_TryPath( &DIR_System, name, full_name )) - goto done; - - /* Try the Windows directory */ - - if (DIR_TryPath( &DIR_Windows, name, full_name )) - goto done; - - /* Try the path of the current executable (for Win16 search order) */ - - if (!win32 && DIR_TryModulePath( name, full_name, win32 )) goto done; - - /* Try all directories in path */ - - ret = DIR_TryEnvironmentPath( name, full_name, NULL ); - -done: - if (tmp) HeapFree( GetProcessHeap(), 0, tmp ); - return ret; -} - - -/*********************************************************************** - * SearchPathW [KERNEL32.@] - * - * Searches for a specified file in the search path. - * - * PARAMS - * path [I] Path to search - * name [I] Filename to search for. - * ext [I] File extension to append to file name. The first - * character must be a period. This parameter is - * specified only if the filename given does not - * contain an extension. - * buflen [I] size of buffer, in characters - * buffer [O] buffer for found filename - * lastpart [O] address of pointer to last used character in - * buffer (the final '\') - * - * RETURNS - * Success: length of string copied into buffer, not including - * terminating null character. If the filename found is - * longer than the length of the buffer, the length of the - * filename is returned. - * Failure: Zero - * - * NOTES - * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND) - * (tested on NT 4.0) - */ -DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen, - LPWSTR buffer, LPWSTR *lastpart ) -{ - LPSTR res; - DOS_FULL_NAME full_name; - - if (!DIR_SearchPath( path, name, ext, &full_name, TRUE )) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return 0; - } - -TRACE("found %s %s\n", full_name.long_name, debugstr_w(full_name.short_name)); -TRACE("drive %c: root %s\n", 'A' + full_name.drive, DRIVE_GetRoot(full_name.drive)); - - lstrcpynW( buffer, full_name.short_name, buflen ); - res = full_name.long_name + - strlen(DRIVE_GetRoot( full_name.drive )); - while (*res == '/') res++; - if (buflen) - { - LPWSTR p; - if (buflen > 3) - { - MultiByteToWideChar(CP_UNIXCP, 0, res, -1, buffer + 3, buflen - 3); - buffer[buflen - 1] = 0; - } - for (p = buffer; *p; p++) if (*p == '/') *p = '\\'; - if (lastpart) *lastpart = strrchrW( buffer, '\\' ) + 1; - } - TRACE("Returning %s\n", debugstr_w(buffer) ); - return strlenW(buffer); -} - - -/*********************************************************************** - * SearchPathA (KERNEL32.@) - */ -DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, - DWORD buflen, LPSTR buffer, LPSTR *lastpart ) -{ - UNICODE_STRING pathW, nameW, extW; - WCHAR bufferW[MAX_PATH]; - DWORD ret, retW; - - if (path) RtlCreateUnicodeStringFromAsciiz(&pathW, path); - else pathW.Buffer = NULL; - if (name) RtlCreateUnicodeStringFromAsciiz(&nameW, name); - else nameW.Buffer = NULL; - if (ext) RtlCreateUnicodeStringFromAsciiz(&extW, ext); - else extW.Buffer = NULL; - - retW = SearchPathW(pathW.Buffer, nameW.Buffer, extW.Buffer, MAX_PATH, bufferW, NULL); - - if (!retW) - ret = 0; - else if (retW > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - ret = 0; - } - else - { - ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); - if (buflen >= ret) - { - WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buflen, NULL, NULL); - ret--; /* length without 0 */ - if (lastpart) *lastpart = strrchr(buffer, '\\') + 1; - } - } - - RtlFreeUnicodeString(&pathW); - RtlFreeUnicodeString(&nameW); - RtlFreeUnicodeString(&extW); - return ret; -} diff --git a/include/file.h b/include/file.h index 51c75ba9ee8..831c8210267 100644 --- a/include/file.h +++ b/include/file.h @@ -46,8 +46,6 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, /* files/directory.c */ extern int DIR_Init(void); -extern DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext, - DOS_FULL_NAME *full_name, BOOL win32 ); /* files/dos_fs.c */ extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf,