Author: ion Date: Tue Dec 20 19:09:13 2011 New Revision: 54713
URL: http://svn.reactos.org/svn/reactos?rev=54713&view=rev Log: [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.
Modified: trunk/reactos/dll/win32/kernel32/client/path.c
Modified: trunk/reactos/dll/win32/kernel32/client/path.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/p... ============================================================================== --- trunk/reactos/dll/win32/kernel32/client/path.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/client/path.c [iso-8859-1] Tue Dec 20 19:09:13 2011 @@ -1285,206 +1285,161 @@ 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 */ DWORD WINAPI -SearchPathW(LPCWSTR lpPath, - LPCWSTR lpFileName, - LPCWSTR lpExtension, - DWORD nBufferLength, - LPWSTR lpBuffer, - LPWSTR *lpFilePart) -{ - DWORD ret = 0; - - if (!lpFileName || !lpFileName[0]) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - /* 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); - - 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 */ - if (lpExtension) - { - LPWSTR tmp; - DWORD len = wcslen(lpFileName) + wcslen(lpExtension); - - if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) - { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - 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, - lpFileName, - lpExtension, - 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); +SearchPathW(IN LPCWSTR lpPath, + IN LPCWSTR lpFileName, + IN LPCWSTR lpExtension, + IN DWORD nBufferLength, + IN LPWSTR lpBuffer, + OUT LPWSTR *lpFilePart) +{ + UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer; + ULONG Flags, LengthNeeded, FilePartSize; + NTSTATUS Status; + DWORD Result = 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' ')) + { + FileNameString.Length -= sizeof(WCHAR); + } + + /* Was it all just spaces? */ + if (!FileNameString.Length) + { + /* Fail out */ + BaseSetLastNTError(STATUS_INVALID_PARAMETER); + goto Quickie; + } + + /* Convert extension to a unicode string */ + RtlInitUnicodeString(&ExtensionString, lpExtension); + + /* Check if the user sent a path */ + if (lpPath) + { + /* Convert it to a unicode string too */ + Status = RtlInitUnicodeStringEx(&PathString, lpPath); + if (NT_ERROR(Status)) + { + /* Fail if it was too long */ + BaseSetLastNTError(Status); + goto Quickie; + } + } + else + { + /* A path wasn't sent, so compute it ourselves */ + PathString.Buffer = BaseComputeProcessSearchPath(); + if (!PathString.Buffer) + { + /* Fail if we couldn't compute it */ + BaseSetLastNTError(STATUS_NO_MEMORY); + goto Quickie; + } + + /* 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; + } + + /* 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 { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - } - - if (!ret) SetLastError(ERROR_FILE_NOT_FOUND); - - return ret; + /* 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; }
/*