mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 22:52:54 +00:00
[KERNEL32] Part 2 of the Path patch: rewrite SearchPathW to use the RtlDosSearchPath_UStr function implemented last week. No (visible) regressions seen... let's see what Testbot says.
svn path=/trunk/; revision=54713
This commit is contained in:
parent
2397b92402
commit
f714427f9a
1 changed files with 131 additions and 176 deletions
|
@ -1285,206 +1285,161 @@ Quickie:
|
||||||
return PathSize;
|
return PathSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* 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] == '\\' || name[1] == '\0') return TRUE;
|
|
||||||
return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name GetDllLoadPath
|
|
||||||
*
|
|
||||||
* Internal function to compute the load path to use for a given dll.
|
|
||||||
*
|
|
||||||
* @remarks Returned pointer must be freed by caller.
|
|
||||||
*/
|
|
||||||
|
|
||||||
LPWSTR
|
|
||||||
GetDllLoadPath(LPCWSTR lpModule)
|
|
||||||
{
|
|
||||||
ULONG Pos = 0, Length = 4, Tmp;
|
|
||||||
PWCHAR EnvironmentBufferW = NULL;
|
|
||||||
LPCWSTR lpModuleEnd = NULL;
|
|
||||||
UNICODE_STRING ModuleName;
|
|
||||||
DWORD LastError = GetLastError(); /* GetEnvironmentVariable changes LastError */
|
|
||||||
|
|
||||||
// FIXME: This function is used only by SearchPathW, and is deprecated and will be deleted ASAP.
|
|
||||||
|
|
||||||
if (lpModule != NULL && wcslen(lpModule) > 2 && lpModule[1] == ':')
|
|
||||||
{
|
|
||||||
lpModuleEnd = lpModule + wcslen(lpModule);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModuleName = NtCurrentPeb()->ProcessParameters->ImagePathName;
|
|
||||||
lpModule = ModuleName.Buffer;
|
|
||||||
lpModuleEnd = lpModule + (ModuleName.Length / sizeof(WCHAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpModule != NULL)
|
|
||||||
{
|
|
||||||
while (lpModuleEnd > lpModule && *lpModuleEnd != L'/' &&
|
|
||||||
*lpModuleEnd != L'\\' && *lpModuleEnd != L':')
|
|
||||||
{
|
|
||||||
--lpModuleEnd;
|
|
||||||
}
|
|
||||||
Length = (lpModuleEnd - lpModule) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Length += GetCurrentDirectoryW(0, NULL);
|
|
||||||
Length += GetDllDirectoryW(0, NULL);
|
|
||||||
Length += GetSystemDirectoryW(NULL, 0);
|
|
||||||
Length += GetWindowsDirectoryW(NULL, 0);
|
|
||||||
Length += GetEnvironmentVariableW(L"PATH", NULL, 0);
|
|
||||||
|
|
||||||
EnvironmentBufferW = RtlAllocateHeap(RtlGetProcessHeap(), 0,
|
|
||||||
(Length + 1) * sizeof(WCHAR));
|
|
||||||
if (EnvironmentBufferW == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpModule)
|
|
||||||
{
|
|
||||||
RtlCopyMemory(EnvironmentBufferW, lpModule,
|
|
||||||
(lpModuleEnd - lpModule) * sizeof(WCHAR));
|
|
||||||
Pos += lpModuleEnd - lpModule;
|
|
||||||
EnvironmentBufferW[Pos++] = L';';
|
|
||||||
}
|
|
||||||
|
|
||||||
Tmp = GetCurrentDirectoryW(Length, EnvironmentBufferW + Pos);
|
|
||||||
if(Tmp > 0 && Tmp < Length - Pos)
|
|
||||||
{
|
|
||||||
Pos += Tmp;
|
|
||||||
if(Pos < Length) EnvironmentBufferW[Pos++] = L';';
|
|
||||||
}
|
|
||||||
|
|
||||||
Tmp = GetDllDirectoryW(Length - Pos, EnvironmentBufferW + Pos);
|
|
||||||
if(Tmp > 0 && Tmp < Length - Pos)
|
|
||||||
{
|
|
||||||
Pos += Tmp;
|
|
||||||
if(Pos < Length) EnvironmentBufferW[Pos++] = L';';
|
|
||||||
}
|
|
||||||
|
|
||||||
Tmp = GetSystemDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
|
|
||||||
if(Tmp > 0 && Tmp < Length - Pos)
|
|
||||||
{
|
|
||||||
Pos += Tmp;
|
|
||||||
if(Pos < Length) EnvironmentBufferW[Pos++] = L';';
|
|
||||||
}
|
|
||||||
|
|
||||||
Tmp = GetWindowsDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
|
|
||||||
if(Tmp > 0 && Tmp < Length - Pos)
|
|
||||||
{
|
|
||||||
Pos += Tmp;
|
|
||||||
if(Pos < Length) EnvironmentBufferW[Pos++] = L';';
|
|
||||||
}
|
|
||||||
|
|
||||||
Tmp = GetEnvironmentVariableW(L"PATH", EnvironmentBufferW + Pos, Length - Pos);
|
|
||||||
|
|
||||||
/* Make sure buffer is null terminated */
|
|
||||||
EnvironmentBufferW[Pos++] = UNICODE_NULL;
|
|
||||||
|
|
||||||
|
|
||||||
SetLastError(LastError);
|
|
||||||
return EnvironmentBufferW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
DWORD
|
DWORD
|
||||||
WINAPI
|
WINAPI
|
||||||
SearchPathW(LPCWSTR lpPath,
|
SearchPathW(IN LPCWSTR lpPath,
|
||||||
LPCWSTR lpFileName,
|
IN LPCWSTR lpFileName,
|
||||||
LPCWSTR lpExtension,
|
IN LPCWSTR lpExtension,
|
||||||
DWORD nBufferLength,
|
IN DWORD nBufferLength,
|
||||||
LPWSTR lpBuffer,
|
IN LPWSTR lpBuffer,
|
||||||
LPWSTR *lpFilePart)
|
OUT LPWSTR *lpFilePart)
|
||||||
{
|
{
|
||||||
DWORD ret = 0;
|
UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer;
|
||||||
|
ULONG Flags, LengthNeeded, FilePartSize;
|
||||||
|
NTSTATUS Status;
|
||||||
|
DWORD Result = 0;
|
||||||
|
|
||||||
if (!lpFileName || !lpFileName[0])
|
/* Default flags for RtlDosSearchPath_Ustr */
|
||||||
|
Flags = 6;
|
||||||
|
|
||||||
|
/* Clear file part in case we fail */
|
||||||
|
if (lpFilePart) *lpFilePart = NULL;
|
||||||
|
|
||||||
|
/* Initialize path buffer for free later */
|
||||||
|
PathString.Buffer = NULL;
|
||||||
|
|
||||||
|
/* Convert filename to a unicode string and eliminate trailing spaces */
|
||||||
|
RtlInitUnicodeString(&FileNameString, lpFileName);
|
||||||
|
while ((FileNameString.Length >= sizeof(WCHAR)) &&
|
||||||
|
(FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' '))
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
FileNameString.Length -= sizeof(WCHAR);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the name contains an explicit path, ignore the path */
|
/* Was it all just spaces? */
|
||||||
if (ContainsPath(lpFileName))
|
if (!FileNameString.Length)
|
||||||
{
|
{
|
||||||
/* try first without extension */
|
/* Fail out */
|
||||||
if (RtlDoesFileExists_U(lpFileName))
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||||||
return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart);
|
goto Quickie;
|
||||||
|
|
||||||
if (lpExtension)
|
|
||||||
{
|
|
||||||
LPCWSTR p = wcsrchr(lpFileName, '.');
|
|
||||||
if (p && !strchr((const char *)p, '/') && !wcschr( p, '\\' ))
|
|
||||||
lpExtension = NULL; /* Ignore the specified extension */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a buffer for the file name and extension */
|
/* Convert extension to a unicode string */
|
||||||
if (lpExtension)
|
RtlInitUnicodeString(&ExtensionString, lpExtension);
|
||||||
{
|
|
||||||
LPWSTR tmp;
|
|
||||||
DWORD len = wcslen(lpFileName) + wcslen(lpExtension);
|
|
||||||
|
|
||||||
if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR))))
|
/* Check if the user sent a path */
|
||||||
|
if (lpPath)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
/* Convert it to a unicode string too */
|
||||||
return 0;
|
Status = RtlInitUnicodeStringEx(&PathString, lpPath);
|
||||||
}
|
if (NT_ERROR(Status))
|
||||||
wcscpy(tmp, lpFileName);
|
|
||||||
wcscat(tmp, lpExtension);
|
|
||||||
if (RtlDoesFileExists_U(tmp))
|
|
||||||
ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart);
|
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (lpPath && lpPath[0]) /* search in the specified path */
|
|
||||||
{
|
{
|
||||||
ret = RtlDosSearchPath_U(lpPath,
|
/* Fail if it was too long */
|
||||||
lpFileName,
|
BaseSetLastNTError(Status);
|
||||||
lpExtension,
|
goto Quickie;
|
||||||
nBufferLength * sizeof(WCHAR),
|
|
||||||
lpBuffer,
|
|
||||||
lpFilePart) / sizeof(WCHAR);
|
|
||||||
}
|
}
|
||||||
else /* search in the default path */
|
|
||||||
{
|
|
||||||
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
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_OUTOFMEMORY);
|
/* A path wasn't sent, so compute it ourselves */
|
||||||
return 0;
|
PathString.Buffer = BaseComputeProcessSearchPath();
|
||||||
}
|
if (!PathString.Buffer)
|
||||||
|
{
|
||||||
|
/* Fail if we couldn't compute it */
|
||||||
|
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||||||
|
goto Quickie;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) SetLastError(ERROR_FILE_NOT_FOUND);
|
/* See how big the computed path is */
|
||||||
|
LengthNeeded = lstrlenW(PathString.Buffer);
|
||||||
|
if (LengthNeeded > UNICODE_STRING_MAX_CHARS)
|
||||||
|
{
|
||||||
|
/* Fail if it's too long */
|
||||||
|
BaseSetLastNTError(STATUS_NAME_TOO_LONG);
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
/* Set the path size now that we have it */
|
||||||
|
PathString.MaximumLength = PathString.Length = LengthNeeded * sizeof(WCHAR);
|
||||||
|
|
||||||
|
/* Request SxS isolation from RtlDosSearchPath_Ustr */
|
||||||
|
Flags |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the string that describes the output buffer from the caller */
|
||||||
|
CallerBuffer.Length = 0;
|
||||||
|
CallerBuffer.Buffer = lpBuffer;
|
||||||
|
|
||||||
|
/* How much space does the caller have? */
|
||||||
|
if (nBufferLength <= UNICODE_STRING_MAX_CHARS)
|
||||||
|
{
|
||||||
|
/* Add it into the string */
|
||||||
|
CallerBuffer.MaximumLength = nBufferLength * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Caller wants too much, limit it to the maximum length of a string */
|
||||||
|
CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call Rtl to do the work */
|
||||||
|
Status = RtlDosSearchPath_Ustr(Flags,
|
||||||
|
&PathString,
|
||||||
|
&FileNameString,
|
||||||
|
&ExtensionString,
|
||||||
|
&CallerBuffer,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&FilePartSize,
|
||||||
|
&LengthNeeded);
|
||||||
|
if (NT_ERROR(Status))
|
||||||
|
{
|
||||||
|
/* Check for unusual status codes */
|
||||||
|
if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
|
||||||
|
{
|
||||||
|
/* Print them out since maybe an app needs fixing */
|
||||||
|
DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
&FileNameString,
|
||||||
|
Status);
|
||||||
|
DbgPrint(" Path = %wZ\n", &PathString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the failure was due to a small buffer */
|
||||||
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
/* Check if the length was actually too big for Rtl to work with */
|
||||||
|
Result = LengthNeeded / sizeof(WCHAR);
|
||||||
|
if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Some other error, set the error code */
|
||||||
|
BaseSetLastNTError(Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* It worked! Write the file part now */
|
||||||
|
if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize];
|
||||||
|
|
||||||
|
/* Convert the final result length */
|
||||||
|
Result = CallerBuffer.Length / sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Quickie:
|
||||||
|
/* Check if there was a dynamic path stirng to free */
|
||||||
|
if ((PathString.Buffer != lpPath) && (PathString.Buffer))
|
||||||
|
{
|
||||||
|
/* And free it */
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the final result lenght */
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue