Author: ion Date: Sun Nov 6 22:46:31 2011 New Revision: 54322
URL: http://svn.reactos.org/svn/reactos?rev=54322&view=rev Log: [KERNEL32]: Give the same treatement to SearchPathA. Also add a comment on why exactly the A<->W conversion has to be more complex than what Wine was attempting.
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] Sun Nov 6 22:46:31 2011 @@ -28,7 +28,7 @@ 0x10000000 // 7C not allowed };
-/* FUNCTIONS ******************************************************************/ +/* PRIVATE FUNCTIONS **********************************************************/
/* * Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is @@ -267,6 +267,8 @@ return !NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL; }
+/* PUBLIC FUNCTIONS ***********************************************************/ + /* * @implemented */ @@ -450,6 +452,18 @@
/* * @implemented + * + * NOTE: Many of these A functions may seem to do rather complex A<->W mapping + * beyond what you would usually expect. There are two main reasons: + * + * First, these APIs are subject to the ANSI/OEM File API selection status that + * the caller has chosen, so we must use the "8BitString" internal Base APIs. + * + * Secondly, the Wide APIs (coming from the 9x world) are coded to return the + * length of the paths in "ANSI" by dividing their internal Wide character count + * by two... this is usually correct when dealing with pure-ASCII codepages but + * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports + * for CJK, for example. */ DWORD WINAPI @@ -545,7 +559,7 @@ /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */ RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1); RtlFreeAnsiString(&AnsiString); - + /* And finally, did the caller request file part information? */ if (lpFilePart) { @@ -583,149 +597,175 @@ */ DWORD WINAPI -SearchPathA ( - LPCSTR lpPath, - LPCSTR lpFileName, - LPCSTR lpExtension, - DWORD nBufferLength, - LPSTR lpBuffer, - LPSTR *lpFilePart - ) -{ - UNICODE_STRING PathU = { 0, 0, NULL }; - UNICODE_STRING FileNameU = { 0, 0, NULL }; - UNICODE_STRING ExtensionU = { 0, 0, NULL }; - UNICODE_STRING BufferU = { 0, 0, NULL }; - ANSI_STRING Path; - ANSI_STRING FileName; - ANSI_STRING Extension; - ANSI_STRING Buffer; - PWCHAR FilePartW; - DWORD RetValue = 0; - NTSTATUS Status = STATUS_SUCCESS; - - if (!lpFileName) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - RtlInitAnsiString (&Path, - (LPSTR)lpPath); - RtlInitAnsiString (&FileName, - (LPSTR)lpFileName); - RtlInitAnsiString (&Extension, - (LPSTR)lpExtension); - - /* convert ansi (or oem) strings to unicode */ - if (bIsFileApiAnsi) - { - Status = RtlAnsiStringToUnicodeString (&PathU, - &Path, - TRUE); +SearchPathA(IN LPCSTR lpPath, + IN LPCSTR lpFileName, + IN LPCSTR lpExtension, + IN DWORD nBufferLength, + IN LPSTR lpBuffer, + OUT LPSTR *lpFilePart) +{ + PUNICODE_STRING FileNameString; + UNICODE_STRING PathString, ExtensionString; + NTSTATUS Status; + ULONG PathSize, FilePartSize, AnsiLength; + PWCHAR LocalFilePart, Buffer; + PWCHAR* FilePart; + + /* If the caller wants filepart, use a local wide buffer since this is A */ + FilePart = lpFilePart != NULL ? &LocalFilePart : NULL; + + /* Initialize stuff for Quickie */ + PathSize = 0; + Buffer = NULL; + ExtensionString.Buffer = PathString.Buffer = NULL; + + /* Get the UNICODE_STRING file name */ + FileNameString = Basep8BitStringToStaticUnicodeString(lpFileName); + if (!FileNameString) return 0; + + /* Did the caller specify an extension */ + if (lpExtension) + { + /* Yup, convert it into UNICODE_STRING */ + Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString, + lpExtension); + if (!NT_SUCCESS(Status)) goto Quickie; + } + + /* Did the caller specify a path */ + if (lpPath) + { + /* Yup, convert it into UNICODE_STRING */ + Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath); + if (!NT_SUCCESS(Status)) goto Quickie; + } + + /* Allocate our output buffer */ + Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * sizeof(WCHAR)); + if (!Buffer) + { + /* It failed, bail out */ + BaseSetLastNTError(STATUS_NO_MEMORY); + goto Quickie; + } + + /* Now run the Wide search with the input buffer lengths */ + PathSize = SearchPathW(PathString.Buffer, + FileNameString->Buffer, + ExtensionString.Buffer, + nBufferLength, + Buffer, + FilePart); + if (PathSize <= nBufferLength) + { + /* It fits, but is it empty? If so, bail out */ + if (!PathSize) goto Quickie; + + /* The length above is inexact, we need it in ANSI */ + Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + /* Conversion failed, fail the call */ + PathSize = 0; + BaseSetLastNTError(Status); + goto Quickie; + } + + /* If the correct ANSI size is too big, return requird length plus a NULL */ + if (AnsiLength >= nBufferLength) + { + PathSize = AnsiLength + 1; + goto Quickie; + } + + /* Now apply the final conversion to ANSI */ + Status = RtlUnicodeToMultiByteN(lpBuffer, + nBufferLength - 1, + &AnsiLength, + Buffer, + PathSize * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + /* Conversion failed, fail the whole call */ + PathSize = 0; + BaseSetLastNTError(STATUS_NO_MEMORY); + goto Quickie; + } + + /* NULL-terminate and return the real ANSI length */ + lpBuffer[AnsiLength] = ANSI_NULL; + PathSize = AnsiLength; + + /* Now check if the user wanted file part size as well */ + if (lpFilePart) + { + /* If we didn't get a file part, clear the caller's */ + if (!LocalFilePart) + { + *lpFilePart = NULL; + } + else + { + /* Yep, so in this case get the length of the file part too */ + Status = RtlUnicodeToMultiByteSize(&FilePartSize, + Buffer, + (LocalFilePart - Buffer) * + sizeof(WCHAR)); if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlAnsiStringToUnicodeString (&FileNameU, - &FileName, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlAnsiStringToUnicodeString (&ExtensionU, - &Extension, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; + { + /* We failed to do that, so fail the whole call */ + BaseSetLastNTError(Status); + PathSize = 0; + } + + /* Return the file part buffer */ + *lpFilePart = lpBuffer + FilePartSize; + } + } + } + else + { + /* Our initial buffer guess was too small, allocate a bigger one */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * sizeof(WCHAR)); + if (!Buffer) + { + /* Out of memory, fail everything */ + BaseSetLastNTError(STATUS_NO_MEMORY); + goto Quickie; + } + + /* Do the search again -- it will fail, we just want the path size */ + PathSize = SearchPathW(PathString.Buffer, + FileNameString->Buffer, + ExtensionString.Buffer, + PathSize, + Buffer, + FilePart); + if (!PathSize) goto Quickie; + + /* Convert it to a correct size */ + Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * sizeof(WCHAR)); + if (NT_SUCCESS(Status)) + { + /* Make space for the NULL-char */ + PathSize++; } else { - Status = RtlOemStringToUnicodeString (&PathU, - &Path, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - Status = RtlOemStringToUnicodeString (&FileNameU, - &FileName, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlOemStringToUnicodeString (&ExtensionU, - &Extension, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - } - - BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX); - BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), - 0, - BufferU.MaximumLength); - if (BufferU.Buffer == NULL) - { - Status = STATUS_NO_MEMORY; - goto Cleanup; - } - - Buffer.MaximumLength = min(nBufferLength, USHRT_MAX); - Buffer.Buffer = lpBuffer; - - RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer, - NULL == lpFileName ? NULL : FileNameU.Buffer, - NULL == lpExtension ? NULL : ExtensionU.Buffer, - nBufferLength, - BufferU.Buffer, - &FilePartW); - - if (0 != RetValue) - { - BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR); - /* convert ansi (or oem) string to unicode */ - if (bIsFileApiAnsi) - Status = RtlUnicodeStringToAnsiString(&Buffer, - &BufferU, - FALSE); - else - Status = RtlUnicodeStringToOemString(&Buffer, - &BufferU, - FALSE); - - if (NT_SUCCESS(Status) && Buffer.Buffer) - { - /* nul-terminate ascii string */ - Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0'; - - if (NULL != lpFilePart && BufferU.Length != 0) - { - *lpFilePart = strrchr (lpBuffer, '\') + 1; - } - } - } - -Cleanup: - RtlFreeHeap (RtlGetProcessHeap (), - 0, - PathU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - FileNameU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - ExtensionU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - BufferU.Buffer); - - if (!NT_SUCCESS(Status)) - { + /* Conversion failed for some reason, fail the call */ BaseSetLastNTError(Status); - return 0; - } - - return RetValue; -} - + PathSize = 0; + } + } + +Quickie: + /* Cleanup/complete path */ + if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString); + if (PathString.Buffer) RtlFreeUnicodeString(&PathString); + return PathSize; +}
/*********************************************************************** * ContainsPath (Wine name: contains_pathW)