- Rewrite SearchPathW (based on Wine code). It fixes regression in mysql

svn path=/trunk/; revision=42003
This commit is contained in:
Dmitry Chapyshev 2009-07-17 13:24:07 +00:00
parent 6324272e80
commit f86de98c40
3 changed files with 85 additions and 163 deletions

View file

@ -954,183 +954,102 @@ Cleanup:
} }
/***********************************************************************
* ContainsPath (Wine name: 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
BOOL
ContainsPath(LPCWSTR name)
{
if (RtlDetermineDosPathNameType_U(name) != RtlPathTypeRelative) return TRUE;
if (name[0] != '.') return FALSE;
if (name[1] == '/' || name[1] == '\\') return TRUE;
return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
}
/* /*
* @implemented * @implemented
*/ */
DWORD DWORD
WINAPI WINAPI
SearchPathW ( SearchPathW(LPCWSTR lpPath,
LPCWSTR lpPath, LPCWSTR lpFileName,
LPCWSTR lpFileName, LPCWSTR lpExtension,
LPCWSTR lpExtension, DWORD nBufferLength,
DWORD nBufferLength, LPWSTR lpBuffer,
LPWSTR lpBuffer, LPWSTR *lpFilePart)
LPWSTR *lpFilePart
)
/*
* FUNCTION: Searches for the specified file
* ARGUMENTS:
* lpPath = Points to a null-terminated string that specified the
* path to be searched. If this parameters is NULL then
* the following directories are searched
* The directory from which the application loaded
* The current directory
* The system directory
* The 16-bit system directory
* The windows directory
* The directories listed in the PATH environment
* variable
* lpFileName = Specifies the filename to search for
* lpExtension = Points to the null-terminated string that specifies
* an extension to be added to the filename when
* searching for the file. The first character of the
* filename extension must be a period (.). The
* extension is only added if the specified filename
* doesn't end with an extension
*
* If the filename extension is not required or if the
* filename contains an extension, this parameters can be
* NULL
* nBufferLength = The length in characters of the buffer for output
* lpBuffer = Points to the buffer for the valid path and filename of
* file found
* lpFilePart = Points to the last component of the valid path and
* filename
* RETURNS: On success, the length, in characters, of the string copied to the
* buffer
* On failure, zero.
*/
{ {
DWORD retCode = 0; DWORD ret = 0;
ULONG pos, len;
PWCHAR EnvironmentBufferW = NULL;
PWCHAR AppPathW = NULL;
WCHAR Buffer;
BOOL HasExtension = FALSE, IsAbsolute = FALSE;
LPCWSTR p;
PWCHAR Name;
TRACE("SearchPath\n"); /* If the name contains an explicit path, ignore the path */
if (ContainsPath(lpFileName))
{
/* try first without extension */
if (RtlDoesFileExists_U(lpFileName))
return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
p = lpFileName + wcslen(lpFileName); if (lpExtension)
while (lpFileName < p &&
L'\\' != *(p - 1) &&
L'/' != *(p - 1))
{ {
HasExtension = HasExtension || L'.' == *(p - 1); LPCWSTR p = wcsrchr(lpFileName, '.');
if (p >= lpFileName && L'\\' == *(p-1)) if (p && !strchr((const char *)p, '/') && !wcschr( p, '\\' ))
{ lpExtension = NULL; /* Ignore the specified extension */
if (':' == *p)
IsAbsolute = TRUE;
}
p--;
} }
if (IsAbsolute)
/* Allocate a buffer for the file name and extension */
if (lpExtension)
{ {
if (HasExtension || NULL == lpExtension) LPWSTR tmp;
{ DWORD len = wcslen(lpFileName) + wcslen(lpExtension);
Name = (PWCHAR) lpFileName;
} if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR))))
else {
{ SetLastError(ERROR_OUTOFMEMORY);
Name = RtlAllocateHeap(RtlGetProcessHeap(), return 0;
HEAP_GENERATE_EXCEPTIONS, }
(wcslen(lpFileName) + wcslen(lpExtension) + 1) wcscpy(tmp, lpFileName);
* sizeof(WCHAR)); wcscat(tmp, lpExtension);
if (NULL == Name) if (RtlDoesFileExists_U(tmp))
{ ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart);
SetLastError(ERROR_OUTOFMEMORY); RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
return 0; }
} }
wcscat(wcscpy(Name, lpFileName), lpExtension); else if (lpPath && lpPath[0]) /* search in the specified path */
} {
if (RtlDoesFileExists_U(Name)) ret = RtlDosSearchPath_U(lpPath,
{ lpFileName,
retCode = RtlGetFullPathName_U (Name, lpExtension,
nBufferLength * sizeof(WCHAR), nBufferLength * sizeof(WCHAR),
lpBuffer, lpBuffer,
lpFilePart); lpFilePart) / sizeof(WCHAR);
} }
if (Name != lpFileName) else /* search in the default path */
{ {
RtlFreeHeap(GetProcessHeap(), 0, Name); WCHAR *DllPath = GetDllLoadPath(NULL);
}
if (DllPath)
{
ret = RtlDosSearchPath_U(DllPath,
lpFileName,
lpExtension,
nBufferLength * sizeof(WCHAR),
lpBuffer,
lpFilePart) / sizeof(WCHAR);
RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
} }
else else
{ {
if (lpPath == NULL) SetLastError(ERROR_OUTOFMEMORY);
{ return 0;
AppPathW = (PWCHAR) RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
MAX_PATH * sizeof(WCHAR));
if (AppPathW == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
wcscat (AppPathW, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
len = wcslen (AppPathW);
while (len && AppPathW[len - 1] != L'\\')
len--;
if (len) AppPathW[len-1] = L'\0';
len = GetEnvironmentVariableW(L"PATH", &Buffer, 0);
len += 1 + GetCurrentDirectoryW(0, &Buffer);
len += 1 + GetSystemDirectoryW(&Buffer, 0);
len += 1 + GetWindowsDirectoryW(&Buffer, 0);
len += 1 + wcslen(AppPathW) * sizeof(WCHAR);
EnvironmentBufferW = (PWCHAR) RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
len * sizeof(WCHAR));
if (EnvironmentBufferW == NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, AppPathW);
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
pos = GetCurrentDirectoryW(len, EnvironmentBufferW);
EnvironmentBufferW[pos++] = L';';
EnvironmentBufferW[pos] = 0;
pos += GetSystemDirectoryW(&EnvironmentBufferW[pos], len - pos);
EnvironmentBufferW[pos++] = L';';
EnvironmentBufferW[pos] = 0;
pos += GetWindowsDirectoryW(&EnvironmentBufferW[pos], len - pos);
EnvironmentBufferW[pos++] = L';';
EnvironmentBufferW[pos] = 0;
pos += GetEnvironmentVariableW(L"PATH", &EnvironmentBufferW[pos], len - pos);
EnvironmentBufferW[pos++] = L';';
EnvironmentBufferW[pos] = 0;
wcscat (EnvironmentBufferW, AppPathW);
RtlFreeHeap (RtlGetProcessHeap (),
0,
AppPathW);
lpPath = EnvironmentBufferW;
}
retCode = RtlDosSearchPath_U ((PWCHAR)lpPath, (PWCHAR)lpFileName, (PWCHAR)lpExtension,
nBufferLength * sizeof(WCHAR), lpBuffer, lpFilePart);
if (EnvironmentBufferW != NULL)
{
RtlFreeHeap(GetProcessHeap(), 0, EnvironmentBufferW);
}
if (retCode == 0)
{
SetLastError(ERROR_FILE_NOT_FOUND);
}
} }
return retCode / sizeof(WCHAR); }
if (!ret) SetLastError(ERROR_FILE_NOT_FOUND);
return ret;
} }
/* /*

View file

@ -189,5 +189,8 @@ BasepMapFile(IN LPCWSTR lpApplicationName,
PCODEPAGE_ENTRY FASTCALL PCODEPAGE_ENTRY FASTCALL
IntGetCodePageEntry(UINT CodePage); IntGetCodePageEntry(UINT CodePage);
LPWSTR
GetDllLoadPath(LPCWSTR lpModule);
#endif /* ndef _KERNEL32_INCLUDE_KERNEL32_H */ #endif /* ndef _KERNEL32_INCLUDE_KERNEL32_H */

View file

@ -31,7 +31,7 @@ extern BOOLEAN InWindows;
* @remarks Returned pointer must be freed by caller. * @remarks Returned pointer must be freed by caller.
*/ */
LPWSTR WINAPI LPWSTR
GetDllLoadPath(LPCWSTR lpModule) GetDllLoadPath(LPCWSTR lpModule)
{ {
ULONG Pos = 0, Length = 0; ULONG Pos = 0, Length = 0;