Some fixes for RtlGetFullPathName_U(str):
- Start to polish RtlpCollapsePath (Work in progress)
- Correctly zero-out the path destination buffer

They fix the following tests:
* ntdll:RtlGetFullPathName_U (2 failures to full success)
* ntdll:RtlGetFullPathName_UstrEx (2 failures to full success)

svn path=/trunk/; revision=62623
This commit is contained in:
Hermès Bélusca-Maïto 2014-04-05 14:56:41 +00:00
parent 9ad09cfd87
commit e9cd63fb67

View file

@ -10,7 +10,7 @@
* Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES *******************************************************************/
#include <rtl.h>
@ -289,102 +289,137 @@ RtlpCheckDeviceName(IN PUNICODE_STRING FileName,
/******************************************************************
* RtlpCollapsePath (from WINE)
*
* Helper for RtlGetFullPathName_U.
* 1) Convert slashes into backslashes
* 2) Get rid of duplicate backslashes
* 3) Get rid of . and .. components in the path.
* Helper for RtlGetFullPathName_U
*
* 1) Converts slashes into backslashes and gets rid of duplicated ones;
* 2) Gets rid of . and .. components in the path.
*
* Returns the full path length without its terminating NULL character.
*/
static VOID
RtlpCollapsePath(PWSTR path, ULONG mark, BOOLEAN SkipTrailingPathSeparators)
static ULONG
RtlpCollapsePath(PWSTR Path, /* ULONG PathBufferSize, ULONG PathLength, */ ULONG mark, BOOLEAN SkipTrailingPathSeparators)
{
PWSTR p, next;
/* convert every / into a \ */
for (p = path; *p; p++)
// FIXME: Do not suppose NULL-terminated strings!!
ULONG PathLength = wcslen(Path);
PWSTR EndBuffer = Path + PathLength; // Path + PathBufferSize / sizeof(WCHAR);
PWSTR EndPath;
/* Convert slashes into backslashes */
for (p = Path; *p; p++)
{
if (*p == L'/') *p = L'\\';
}
/* collapse duplicate backslashes */
next = path + max( 1, mark );
/* Collapse duplicate backslashes */
next = Path + max( 1, mark );
for (p = next; *p; p++)
{
if (*p != L'\\' || next[-1] != L'\\') *next++ = *p;
}
*next = UNICODE_NULL;
EndPath = next;
p = path + mark;
p = Path + mark;
while (*p)
{
if (*p == L'.')
{
switch(p[1])
switch (p[1])
{
case UNICODE_NULL: /* final . */
if (p > path + mark) p--;
if (p > Path + mark) p--;
*p = UNICODE_NULL;
EndPath = p;
continue;
case L'\\': /* .\ component */
next = p + 2;
RtlMoveMemory( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
// ASSERT(EndPath - next == wcslen(next));
RtlMoveMemory(p, next, (EndPath - next + 1) * sizeof(WCHAR));
EndPath -= (next - p);
continue;
case L'.':
if (p[2] == L'\\') /* ..\ component */
{
next = p + 3;
if (p > path + mark)
if (p > Path + mark)
{
p--;
while (p > path + mark && p[-1] != L'\\') p--;
while (p > Path + mark && p[-1] != L'\\') p--;
}
RtlMoveMemory( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
// ASSERT(EndPath - next == wcslen(next));
RtlMoveMemory(p, next, (EndPath - next + 1) * sizeof(WCHAR));
EndPath -= (next - p);
continue;
}
else if (!p[2]) /* final .. */
else if (p[2] == UNICODE_NULL) /* final .. */
{
if (p > path + mark)
if (p > Path + mark)
{
p--;
while (p > path + mark && p[-1] != L'\\') p--;
if (p > path + mark) p--;
while (p > Path + mark && p[-1] != L'\\') p--;
if (p > Path + mark) p--;
}
*p = UNICODE_NULL;
EndPath = p;
continue;
}
break;
}
}
/* skip to the next component */
/* Skip to the next component */
while (*p && *p != L'\\') p++;
if (*p == L'\\')
{
/* remove last dot in previous dir name */
if (p > path + mark && p[-1] == L'.')
RtlMoveMemory( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) );
/* Remove last dot in previous dir name */
if (p > Path + mark && p[-1] == L'.')
{
// ASSERT(EndPath - p == wcslen(p));
RtlMoveMemory(p - 1, p, (EndPath - p + 1) * sizeof(WCHAR));
EndPath--;
}
else
{
p++;
}
}
}
/* Remove trailing backslashes if needed (after the UNC part if it exists) */
if (SkipTrailingPathSeparators)
{
while (p > path + mark && IS_PATH_SEPARATOR(p[-1])) *p-- = UNICODE_NULL;
while (p > Path + mark && IS_PATH_SEPARATOR(p[-1])) p--;
}
/* Remove trailing spaces and dots (for all the path) */
while (p > path && (p[-1] == L' ' || p[-1] == L'.')) *p-- = UNICODE_NULL;
while (p > Path && (p[-1] == L' ' || p[-1] == L'.')) p--;
/* Null-terminate the string */
*p = UNICODE_NULL;
/*
* Zero-out the discarded buffer zone, starting just after
* the path string and going up to the end of the buffer.
* It also NULL-terminate the path string.
*/
ASSERT(EndBuffer >= p);
RtlZeroMemory(p, (EndBuffer - p + 1) * sizeof(WCHAR));
/* Return the real path length */
PathLength = (p - Path);
// ASSERT(PathLength == wcslen(Path));
return (PathLength * sizeof(WCHAR));
}
/******************************************************************
* RtlpSkipUNCPrefix (from WINE)
*
* Helper for RtlGetFullPathName_U
* Skip the \\share\dir part of a file name and return the new position
* (which can point on the last backslash of "dir\")
*
* Skips the \\share\dir part of a file name and returns the new position
* (which can point on the last backslash of "dir\").
*/
static SIZE_T
RtlpSkipUNCPrefix(PCWSTR FileNameBuffer)
@ -542,7 +577,7 @@ RtlGetFullPathName_Ustr(
return FullLength + sizeof(UNICODE_NULL);
}
/* Zero out the destination buffer. FileName must be different from Buffer */
/* Zero-out the destination buffer. FileName must be different from Buffer */
RtlZeroMemory(Buffer, Size);
/* Get the path type */
@ -551,7 +586,7 @@ RtlGetFullPathName_Ustr(
/**********************************************
** CODE REWRITTEN IS HAPPENING THERE **
** CODE REWRITING IS HAPPENING THERE **
**********************************************/
Source = FileNameBuffer;
SourceLength = FileNameLength;
@ -619,7 +654,7 @@ RtlGetFullPathName_Ustr(
* FIXME: Win2k seems to check that the environment
* variable actually points to an existing directory.
* If not, root of the drive is used (this seems also
* to be the only spot in RtlGetFullPathName that the
* to be the only place in RtlGetFullPathName that the
* existence of a part of a path is checked).
*/
EnvVarValue.Buffer[EnvVarValue.Length / sizeof(WCHAR)] = L'\\';
@ -709,13 +744,10 @@ RtlGetFullPathName_Ustr(
/*
* Build the full path
*/
// if (ShortName) DPRINT1("buffer(1) = %S\n", Buffer);
/* Copy the path's prefix */
if (PrefixLength) RtlMoveMemory(Buffer, Prefix, PrefixLength);
// if (ShortName) DPRINT1("buffer(2) = %S\n", Buffer);
/* Copy the remaining part of the path */
RtlMoveMemory(Buffer + PrefixLength / sizeof(WCHAR), Source, SourceLength + sizeof(WCHAR));
// if (ShortName) DPRINT1("buffer(3) = %S\n", Buffer);
/* Some cleanup */
Prefix = NULL;
@ -726,15 +758,11 @@ RtlGetFullPathName_Ustr(
}
/*
* Finally, put the path in canonical form,
* i.e. simplify redundant . and .., etc...
* Finally, put the path in canonical form (remove redundant . and ..,
* (back)slashes...) and retrieve the length of the full path name
* (without its terminating null character) (in chars).
*/
// if (*PathType == RtlPathTypeUncAbsolute) DPRINT1("RtlpCollapsePath('%S', %lu)\n", Buffer, PrefixCut);
RtlpCollapsePath(Buffer, PrefixCut, SkipTrailingPathSeparators);
// if (ShortName) DPRINT1("buffer(4) = %S\n", Buffer);
/* Get the length of the full path name, without its terminating null character */
reqsize = wcslen(Buffer) * sizeof(WCHAR);
reqsize = RtlpCollapsePath(Buffer, /* Size, reqsize, */ PrefixCut, SkipTrailingPathSeparators);
/* Find the file part, which is present after the last path separator */
if (ShortName)
@ -761,7 +789,8 @@ RtlGetFullPathName_Ustr(
Quit:
/* Release PEB lock */
RtlReleasePebLock();
return (ULONG)reqsize;
return reqsize;
}
NTSTATUS