Author: hbelusca Date: Sat Apr 5 14:56:41 2014 New Revision: 62623
URL: http://svn.reactos.org/svn/reactos?rev=62623&view=rev Log: [RTL] 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)
Modified: trunk/reactos/lib/rtl/path.c
Modified: trunk/reactos/lib/rtl/path.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/path.c?rev=62623&am... ============================================================================== --- trunk/reactos/lib/rtl/path.c [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/path.c [iso-8859-1] Sat Apr 5 14:56:41 2014 @@ -10,7 +10,7 @@ * Pierre Schweitzer (pierre@reactos.org) */
-/* INCLUDES *****************************************************************/ +/* INCLUDES *******************************************************************/
#include <rtl.h>
@@ -289,102 +289,137 @@ /****************************************************************** * 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; - - p = path + mark; + EndPath = next; + + 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; - - /* Null-terminate the string */ - *p = UNICODE_NULL; + while (p > Path && (p[-1] == L' ' || p[-1] == L'.')) p--; + + /* + * 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 @@ 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 @@
/********************************************** - ** CODE REWRITTEN IS HAPPENING THERE ** + ** CODE REWRITING IS HAPPENING THERE ** **********************************************/ Source = FileNameBuffer; SourceLength = FileNameLength; @@ -619,7 +654,7 @@ * 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 @@ /* * 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 @@ }
/* - * 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 @@ Quit: /* Release PEB lock */ RtlReleasePebLock(); - return (ULONG)reqsize; + + return reqsize; }
NTSTATUS