kernel32: Move SearchPath functions to kernelbase.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-10-04 09:44:29 +02:00
parent 15bf3eee2c
commit 8d25965e12
5 changed files with 249 additions and 299 deletions

View File

@ -1324,8 +1324,8 @@
@ stdcall -i386 -private -norelay SUnMapLS_IP_EBP_8() krnl386.exe16.SUnMapLS_IP_EBP_8
@ stdcall -import ScrollConsoleScreenBufferA(long ptr ptr ptr ptr)
@ stdcall -import ScrollConsoleScreenBufferW(long ptr ptr ptr ptr)
@ stdcall SearchPathA(str str str long ptr ptr)
@ stdcall SearchPathW(wstr wstr wstr long ptr ptr)
@ stdcall -import SearchPathA(str str str long ptr ptr)
@ stdcall -import SearchPathW(wstr wstr wstr long ptr ptr)
@ stdcall SetCPGlobal(long)
@ stdcall SetCalendarInfoA(long long long str)
@ stdcall SetCalendarInfoW(long long long wstr)

View File

@ -254,300 +254,6 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen
return copy_filename_WtoA( shortpathW, shortpath, shortlen );
}
/***********************************************************************
* 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 ../
*/
static inline 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] == '\\'));
}
/***********************************************************************
* find_actctx_dllpath
*
* Find the path (if any) of the dll from the activation context.
* Returned path doesn't include a name.
*/
static NTSTATUS find_actctx_dllpath(const WCHAR *libname, WCHAR **path)
{
static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
ACTCTX_SECTION_KEYED_DATA data;
UNICODE_STRING nameW;
NTSTATUS status;
SIZE_T needed, size = 1024;
WCHAR *p;
RtlInitUnicodeString( &nameW, libname );
data.cbSize = sizeof(data);
status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
&nameW, &data );
if (status != STATUS_SUCCESS) return status;
for (;;)
{
if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
{
status = STATUS_NO_MEMORY;
goto done;
}
status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
AssemblyDetailedInformationInActivationContext,
info, size, &needed );
if (status == STATUS_SUCCESS) break;
if (status != STATUS_BUFFER_TOO_SMALL) goto done;
HeapFree( GetProcessHeap(), 0, info );
size = needed;
/* restart with larger buffer */
}
if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
{
status = STATUS_SXS_KEY_NOT_FOUND;
goto done;
}
if ((p = strrchrW( info->lpAssemblyManifestPath, '\\' )))
{
DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
p++;
if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
{
/* manifest name does not match directory name, so it's not a global
* windows/winsxs manifest; use the manifest directory name instead */
dirlen = p - info->lpAssemblyManifestPath;
needed = (dirlen + 1) * sizeof(WCHAR);
if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
*(p + dirlen) = 0;
goto done;
}
}
needed = (strlenW( DIR_Windows ) * sizeof(WCHAR) +
sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + 2*sizeof(WCHAR));
if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
strcpyW( p, DIR_Windows );
p += strlenW(p);
memcpy( p, winsxsW, sizeof(winsxsW) );
p += ARRAY_SIZE( winsxsW );
memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
*p++ = '\\';
*p = 0;
done:
HeapFree( GetProcessHeap(), 0, info );
RtlReleaseActivationContext( data.hActCtx );
return status;
}
/***********************************************************************
* SearchPathW [KERNEL32.@]
*
* Searches for a specified file in the search path.
*
* PARAMS
* path [I] Path to search (NULL means default)
* 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 (!name || !name[0])
{
SetLastError(ERROR_INVALID_PARAMETER);
return 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 active context and default path */
{
WCHAR *dll_path = NULL, *search = NULL;
DWORD req_len, name_len;
req_len = name_len = strlenW(name);
if (strchrW( name, '.' )) ext = NULL;
if (ext)
{
DWORD ext_len = strlenW(ext);
req_len += ext_len;
name_len += ext_len;
search = HeapAlloc( GetProcessHeap(), 0, (name_len + ext_len + 1) * sizeof(WCHAR) );
if (!search)
{
SetLastError( ERROR_OUTOFMEMORY );
return 0;
}
strcpyW( search, name );
strcatW( search, ext );
name = search;
/* now that we have combined name we don't need extension any more */
}
/* When file is found with activation context no attempt is made
to check if it's really exist, path is returned only basing on context info. */
if (find_actctx_dllpath( name, &dll_path ) == STATUS_SUCCESS)
{
DWORD path_len;
path_len = strlenW(dll_path);
req_len += path_len;
if (lastpart) *lastpart = NULL;
/* count null termination char too */
if (req_len + 1 <= buflen)
{
memcpy( buffer, dll_path, path_len * sizeof(WCHAR) );
memcpy( &buffer[path_len], name, name_len * sizeof(WCHAR) );
buffer[req_len] = 0;
if (lastpart) *lastpart = buffer + path_len;
ret = req_len;
}
else
ret = req_len + 1;
HeapFree( GetProcessHeap(), 0, dll_path );
}
else if (!RtlGetSearchPath( &dll_path ))
{
ret = RtlDosSearchPath_U( dll_path, name, NULL, buflen * sizeof(WCHAR),
buffer, lastpart ) / sizeof(WCHAR);
RtlReleasePath( dll_path );
}
HeapFree( GetProcessHeap(), 0, search );
}
if (!ret) SetLastError( ERROR_FILE_NOT_FOUND );
else TRACE( "found %s\n", debugstr_w(buffer) );
return ret;
}
/***********************************************************************
* SearchPathA (KERNEL32.@)
*
* See SearchPathW.
*/
DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext,
DWORD buflen, LPSTR buffer, LPSTR *lastpart )
{
WCHAR *pathW = NULL, *nameW, *extW = NULL;
WCHAR bufferW[MAX_PATH];
DWORD ret;
if (!name)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (!(nameW = FILE_name_AtoW( name, FALSE ))) return 0;
if (path && !(pathW = FILE_name_AtoW( path, TRUE ))) return 0;
if (ext && !(extW = FILE_name_AtoW( ext, TRUE )))
{
HeapFree( GetProcessHeap(), 0, pathW );
return 0;
}
ret = SearchPathW(pathW, nameW, extW, MAX_PATH, bufferW, NULL);
HeapFree( GetProcessHeap(), 0, pathW );
HeapFree( GetProcessHeap(), 0, extW );
if (!ret) return 0;
if (ret > MAX_PATH)
{
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return 0;
}
ret = copy_filename_WtoA( bufferW, buffer, buflen );
if (buflen > ret && lastpart)
*lastpart = strrchr(buffer, '\\') + 1;
return ret;
}
static BOOL is_same_file(HANDLE h1, HANDLE h2)
{

View File

@ -63,6 +63,137 @@ static void WINAPI read_write_apc( void *apc_user, PIO_STATUS_BLOCK io, ULONG re
***********************************************************************/
/***********************************************************************
* contains_path
*
* Check if the file name contains a path; helper for SearchPathW.
* A relative path is not considered a path unless it starts with ./ or ../
*/
static inline BOOL contains_path( const WCHAR *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] == '\\'));
}
/***********************************************************************
* append_ext
*/
static WCHAR *append_ext( const WCHAR *name, const WCHAR *ext )
{
const WCHAR *p;
WCHAR *ret;
DWORD len;
if (!ext) return NULL;
p = wcsrchr( name, '.' );
if (p && !wcschr( p, '/' ) && !wcschr( p, '\\' )) return NULL;
len = lstrlenW( name ) + lstrlenW( ext );
if ((ret = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
{
lstrcpyW( ret, name );
lstrcatW( ret, ext );
}
return ret;
}
/***********************************************************************
* find_actctx_dllpath
*
* Find the path (if any) of the dll from the activation context.
* Returned path doesn't include a name.
*/
static NTSTATUS find_actctx_dllpath( const WCHAR *name, WCHAR **path )
{
static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
ACTCTX_SECTION_KEYED_DATA data;
UNICODE_STRING nameW;
NTSTATUS status;
SIZE_T needed, size = 1024;
WCHAR *p;
RtlInitUnicodeString( &nameW, name );
data.cbSize = sizeof(data);
status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
&nameW, &data );
if (status != STATUS_SUCCESS) return status;
for (;;)
{
if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
{
status = STATUS_NO_MEMORY;
goto done;
}
status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
AssemblyDetailedInformationInActivationContext,
info, size, &needed );
if (status == STATUS_SUCCESS) break;
if (status != STATUS_BUFFER_TOO_SMALL) goto done;
RtlFreeHeap( GetProcessHeap(), 0, info );
size = needed;
/* restart with larger buffer */
}
if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
{
status = STATUS_SXS_KEY_NOT_FOUND;
goto done;
}
if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
{
DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
p++;
if (wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || wcsicmp( p + dirlen, dotManifestW ))
{
/* manifest name does not match directory name, so it's not a global
* windows/winsxs manifest; use the manifest directory name instead */
dirlen = p - info->lpAssemblyManifestPath;
needed = (dirlen + 1) * sizeof(WCHAR);
if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
*(p + dirlen) = 0;
goto done;
}
}
needed = (lstrlenW( windows_dir ) * sizeof(WCHAR) +
sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + 2*sizeof(WCHAR));
if (!(*path = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
lstrcpyW( p, windows_dir );
p += lstrlenW(p);
memcpy( p, winsxsW, sizeof(winsxsW) );
p += ARRAY_SIZE( winsxsW );
memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
*p++ = '\\';
*p = 0;
done:
RtlFreeHeap( GetProcessHeap(), 0, info );
RtlReleaseActivationContext( data.hActCtx );
return status;
}
/***********************************************************************
* copy_filename_WtoA
*
@ -1321,6 +1452,119 @@ BOOL WINAPI DECLSPEC_HOTPATCH NeedCurrentDirectoryForExePathW( LPCWSTR name )
}
/***********************************************************************
* SearchPathA (kernelbase.@)
*/
DWORD WINAPI DECLSPEC_HOTPATCH SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext,
DWORD buflen, LPSTR buffer, LPSTR *lastpart )
{
WCHAR *pathW = NULL, *nameW, *extW = NULL;
WCHAR bufferW[MAX_PATH];
DWORD ret;
if (!name)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (!(nameW = file_name_AtoW( name, FALSE ))) return 0;
if (path && !(pathW = file_name_AtoW( path, TRUE ))) return 0;
if (ext && !(extW = file_name_AtoW( ext, TRUE )))
{
RtlFreeHeap( GetProcessHeap(), 0, pathW );
return 0;
}
ret = SearchPathW( pathW, nameW, extW, MAX_PATH, bufferW, NULL );
RtlFreeHeap( GetProcessHeap(), 0, pathW );
RtlFreeHeap( GetProcessHeap(), 0, extW );
if (!ret) return 0;
if (ret > MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return 0;
}
ret = copy_filename_WtoA( bufferW, buffer, buflen );
if (buflen > ret && lastpart) *lastpart = strrchr(buffer, '\\') + 1;
return ret;
}
/***********************************************************************
* SearchPathW (kernelbase.@)
*/
DWORD WINAPI DECLSPEC_HOTPATCH SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen,
LPWSTR buffer, LPWSTR *lastpart )
{
DWORD ret = 0;
WCHAR *name_ext;
if (!name || !name[0])
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
/* If the name contains an explicit path, ignore the path */
if (contains_path( name ))
{
/* try first without extension */
if (RtlDoesFileExists_U( name )) return GetFullPathNameW( name, buflen, buffer, lastpart );
if ((name_ext = append_ext( name, ext )))
{
if (RtlDoesFileExists_U( name_ext ))
ret = GetFullPathNameW( name_ext, buflen, buffer, lastpart );
RtlFreeHeap( GetProcessHeap(), 0, name_ext );
}
}
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 active context and default path */
{
WCHAR *dll_path = NULL, *name_ext = append_ext( name, ext );
if (name_ext) name = name_ext;
/* When file is found with activation context no attempt is made
to check if it's really exist, path is returned only basing on context info. */
if (find_actctx_dllpath( name, &dll_path ) == STATUS_SUCCESS)
{
ret = lstrlenW( dll_path ) + lstrlenW( name ) + 1;
/* count null termination char too */
if (ret <= buflen)
{
lstrcpyW( buffer, dll_path );
lstrcatW( buffer, name );
if (lastpart) *lastpart = buffer + lstrlenW( dll_path );
ret--;
}
else if (lastpart) *lastpart = NULL;
RtlFreeHeap( GetProcessHeap(), 0, dll_path );
}
else if (!RtlGetSearchPath( &dll_path ))
{
ret = RtlDosSearchPath_U( dll_path, name, NULL, buflen * sizeof(WCHAR),
buffer, lastpart ) / sizeof(WCHAR);
RtlReleasePath( dll_path );
}
RtlFreeHeap( GetProcessHeap(), 0, name_ext );
}
if (!ret) SetLastError( ERROR_FILE_NOT_FOUND );
else TRACE( "found %s\n", debugstr_w(buffer) );
return ret;
}
/***********************************************************************
* SetCurrentDirectoryA (kernelbase.@)
*/

View File

@ -1385,8 +1385,8 @@
# @ stub SaveStateRootFolderPath
@ stdcall ScrollConsoleScreenBufferA(long ptr ptr ptr ptr)
@ stdcall ScrollConsoleScreenBufferW(long ptr ptr ptr ptr)
@ stdcall SearchPathA(str str str long ptr ptr) kernel32.SearchPathA
@ stdcall SearchPathW(wstr wstr wstr long ptr ptr) kernel32.SearchPathW
@ stdcall SearchPathA(str str str long ptr ptr)
@ stdcall SearchPathW(wstr wstr wstr long ptr ptr)
@ stdcall SetAclInformation(ptr ptr long long)
# @ stub SetCachedSigningLevel
@ stdcall SetCalendarInfoW(long long long wstr) kernel32.SetCalendarInfoW

View File

@ -92,7 +92,7 @@ static BOOL load_library_as_datafile( LPCWSTR load_path, DWORD flags, LPCWSTR na
if (flags & LOAD_LIBRARY_AS_IMAGE_RESOURCE) protect |= SEC_IMAGE;
if (SearchPathW( load_path, name, dotDLL, ARRAY_SIZE( filenameW ), filenameW, NULL ))
if (SearchPathW( NULL, name, dotDLL, ARRAY_SIZE( filenameW ), filenameW, NULL ))
{
file = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, 0 );