{
PUNICODE_STRING FileNameString;
UNICODE_STRING PathString, ExtensionString;
NTSTATUSStatus;
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))
{
/* 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
{
/* Conversion failed for some reason, fail the call */BaseSetLastNTError(Status);
PathSize = 0;
}
}
Quickie:
/* Cleanup/complete path */if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString);
if (PathString.Buffer) RtlFreeUnicodeString(&PathString);
return PathSize;
}
Generated on Sun May 27 2012 04:45:58 for ReactOS by
1.7.6.1
ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.