[KERNEL32]: Fix infinite loop in FindLFNorSFN_U.

[KERNEL32]: Reimplement GetFullPathNameA to implement similar functionality and checks as the other reimplemented A functions, especially w.r.t ANSI/OEM and DBCS strings.

svn path=/trunk/; revision=54321
This commit is contained in:
Alex Ionescu 2011-11-06 21:00:10 +00:00
parent 3bdf1b6e8a
commit 504de2415f

View file

@ -187,11 +187,10 @@ FindLFNorSFN_U(IN PWCHAR Path,
* Check if it is valid * Check if it is valid
* Note that !IsShortName != IsLongName, these two functions simply help * Note that !IsShortName != IsLongName, these two functions simply help
* us determine if a conversion is necessary or not. * us determine if a conversion is necessary or not.
* "Found" really means: "Is a conversion necessary?", hence the "!"
*/ */
Found = UseShort ? IsShortName_U(Path, Length) : IsLongName_U(Path, Length); Found = UseShort ? !IsShortName_U(Path, Length) : !IsLongName_U(Path, Length);
if (Found)
/* "Found" really means: "Is a conversion necessary?", hence the ! */
if (!Found)
{ {
/* It is! did the caller request to know the markers? */ /* It is! did the caller request to know the markers? */
if ((First) && (Last)) if ((First) && (Last))
@ -211,7 +210,7 @@ FindLFNorSFN_U(IN PWCHAR Path,
} }
/* Return if anything was found and valid */ /* Return if anything was found and valid */
return !Found; return Found;
} }
PWCHAR PWCHAR
@ -454,53 +453,114 @@ NeedCurrentDirectoryForExePathA(IN LPCSTR ExeName)
*/ */
DWORD DWORD
WINAPI WINAPI
GetFullPathNameA ( GetFullPathNameA(IN LPCSTR lpFileName,
LPCSTR lpFileName, IN DWORD nBufferLength,
DWORD nBufferLength, IN LPSTR lpBuffer,
LPSTR lpBuffer, IN LPSTR *lpFilePart)
LPSTR *lpFilePart
)
{ {
WCHAR BufferW[MAX_PATH]; NTSTATUS Status;
PWCHAR FileNameW; PWCHAR Buffer;
DWORD ret; ULONG PathSize, FilePartSize;
LPWSTR FilePartW = NULL; ANSI_STRING AnsiString;
UNICODE_STRING FileNameString, UniString;
PWCHAR LocalFilePart;
PWCHAR* FilePart;
DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, " /* If the caller wants filepart, use a local wide buffer since this is A */
"lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart); FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) /* Initialize for Quickie */
return 0; FilePartSize = PathSize = 0;
FileNameString.Buffer = NULL;
ret = GetFullPathNameW(FileNameW, MAX_PATH, BufferW, &FilePartW); /* First get our string in Unicode */
Status = Basep8BitStringToDynamicUnicodeString(&FileNameString, lpFileName);
if (!NT_SUCCESS(Status)) goto Quickie;
if (!ret) /* Allocate a buffer to hold teh path name */
return 0; Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL));
if (!Buffer)
{
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
goto Quickie;
}
if (ret > MAX_PATH) /* Call into RTL to get the full Unicode path name */
{ PathSize = RtlGetFullPathName_U(FileNameString.Buffer,
SetLastError(ERROR_FILENAME_EXCED_RANGE); MAX_PATH * sizeof(WCHAR),
return 0; Buffer,
} FilePart);
if (PathSize <= (MAX_PATH * sizeof(WCHAR)))
{
/* The buffer will fit, get the real ANSI string size now */
Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize);
if (NT_SUCCESS(Status))
{
/* Now check if the user wanted file part size as well */
if ((PathSize) && (lpFilePart) && (LocalFilePart))
{
/* 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;
}
}
}
}
else
{
/* Reset the path size since the buffer is not large enough */
PathSize = 0;
}
ret = FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1); /* Either no path, or local buffer was too small, enter failure code */
if (!PathSize) goto Quickie;
if (ret < nBufferLength && lpFilePart) /* If the *caller's* buffer was too small, fail, but add in space for NULL */
{ if (PathSize < nBufferLength)
/* if the path closed with '\', FilePart is NULL */ {
if (!FilePartW) PathSize++;
*lpFilePart=NULL; goto Quickie;
else }
*lpFilePart = (FilePartW - BufferW) + lpBuffer;
}
DPRINT("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n", /* So far so good, initialize a unicode string to convert back to ANSI/OEM */
lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart); RtlInitUnicodeString(&UniString, Buffer);
Status = BasepUnicodeStringTo8BitString(&AnsiString, &UniString, TRUE);
if (!NT_SUCCESS(Status))
{
/* Final conversion failed, fail the call */
BaseSetLastNTError(Status);
PathSize = 0;
}
else
{
/* 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)
{
/* Use the size we computed earlier and add it to the buffer */
*lpFilePart = LocalFilePart ? &lpBuffer[FilePartSize] : 0;
}
}
return ret; Quickie:
/* Cleanup and return the path size */
if (FileNameString.Buffer) RtlFreeUnicodeString(&FileNameString);
if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return PathSize;
} }
/* /*
* @implemented * @implemented
*/ */
@ -511,6 +571,7 @@ GetFullPathNameW(IN LPCWSTR lpFileName,
IN LPWSTR lpBuffer, IN LPWSTR lpBuffer,
OUT LPWSTR *lpFilePart) OUT LPWSTR *lpFilePart)
{ {
/* Call Rtl to do the work */
return RtlGetFullPathName_U((LPWSTR)lpFileName, return RtlGetFullPathName_U((LPWSTR)lpFileName,
nBufferLength * sizeof(WCHAR), nBufferLength * sizeof(WCHAR),
lpBuffer, lpBuffer,