From 97d2212a197d3d4739db441f2c19044583a97979 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Wed, 2 Mar 2011 11:42:30 +0000 Subject: [PATCH] [RTL/PATH] - Update path.c code to Wine 1.3.14. Fixes a buffer overwrite happening in RtlDosSearchPath_U() when invoked by "shell32_winetest.exe shlexec". - RtlDosPathNameToNtPathName_U remains unsynced. - Author names added to the header of the file. See issue #5964 for more details. svn path=/trunk/; revision=50954 --- reactos/lib/rtl/path.c | 185 ++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 94 deletions(-) diff --git a/reactos/lib/rtl/path.c b/reactos/lib/rtl/path.c index 238d5c89b34..d0b4e21a7a1 100644 --- a/reactos/lib/rtl/path.c +++ b/reactos/lib/rtl/path.c @@ -3,7 +3,9 @@ * PROJECT: ReactOS system libraries * FILE: lib/rtl/path.c * PURPOSE: Path and current directory functions - * PROGRAMMERS: + * PROGRAMMERS: Wine team + * Thomas Weidenmueller + * Gunnar Dalsnes */ /* INCLUDES *****************************************************************/ @@ -112,30 +114,24 @@ RtlIsDosDeviceName_U(PWSTR dos_name) if (!_wcsicmp( dos_name, consoleW )) return MAKELONG( sizeof(conW), 4 * sizeof(WCHAR) ); /* 4 is length of \\.\ prefix */ return 0; + case RtlPathTypeDriveAbsolute: + case RtlPathTypeDriveRelative: + start = dos_name + 2; /* skip drive letter */ + break; default: + start = dos_name; break; } - end = dos_name + wcslen(dos_name) - 1; - while (end >= dos_name && *end == ':') end--; /* remove all trailing ':' */ - /* find start of file name */ - for (start = end; start >= dos_name; start--) - { - if (IS_PATH_SEPARATOR(start[0])) break; - /* check for ':' but ignore if before extension (for things like NUL:.txt) */ - if (start[0] == ':' && start[1] != '.') break; - } - start++; + for (p = start; *p; p++) if (IS_PATH_SEPARATOR(*p)) start = p + 1; + + /* truncate at extension and ':' */ + for (end = start; *end; end++) if (*end == '.' || *end == ':') break; + end--; - /* remove extension */ - if ((p = wcschr( start, '.' ))) - { - end = p - 1; - if (end >= dos_name && *end == ':') end--; /* remove trailing ':' before extension */ - } /* remove trailing spaces */ - while (end >= dos_name && *end == ' ') end--; + while (end >= start && *end == ' ') end--; /* now we have a potential device name between start and end, check it */ switch(end - start + 1) @@ -218,6 +214,8 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING dir) DPRINT("RtlSetCurrentDirectory %wZ\n", dir); + full.Buffer = NULL; + RtlAcquirePebLock (); cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath; @@ -287,16 +285,13 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING dir) } - /****************************************************************** - * collapse_path + * collapse_path * * Helper for RtlGetFullPathName_U. - * 1) Convert slashes into backslashes - * 2) Get rid of duplicate backslashes - * 3) Get rid of . and .. components in the path. + * Get rid of . and .. components in the path. */ -static __inline void collapse_path( WCHAR *path, UINT mark ) +void FORCEINLINE collapse_path( WCHAR *path, UINT mark ) { WCHAR *p, *next; @@ -469,9 +464,11 @@ static ULONG get_full_path_helper( tmp[1] = ':'; tmp[2] = '\\'; ins_str = tmp; + RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer); break; default: DPRINT1("Unsupported status code\n"); + RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer); break; } mark = 3; @@ -554,7 +551,7 @@ static ULONG get_full_path_helper( if (reqsize) memcpy(buffer, ins_str, reqsize); reqsize += deplen; - if (ins_str && ins_str != tmp && ins_str != cd->Buffer) + if (ins_str != tmp && ins_str != cd->Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str); collapse_path( buffer, mark ); @@ -614,10 +611,9 @@ ULONG NTAPI RtlGetFullPathName_U( if (reqsize > size) { LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize); - if (tmp == NULL) - return 0; + if (tmp == NULL) return 0; reqsize = get_full_path_helper(name, tmp, reqsize); - if (reqsize > size) /* it may have worked the second time */ + if (reqsize + sizeof(WCHAR) > size) /* it may have worked the second time */ { RtlFreeHeap(RtlGetProcessHeap(), 0, tmp); return reqsize + sizeof(WCHAR); @@ -799,77 +795,79 @@ RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName, /* * @implemented */ +/****************************************************************** + * RtlDosSearchPath_U + * + * Searches a file of name 'name' into a ';' separated list of paths + * (stored in paths) + * Doesn't seem to search elsewhere than the paths list + * Stores the result in buffer (file_part will point to the position + * of the file name in the buffer) + * FIXME: + * - how long shall the paths be ??? (MAX_PATH or larger with \\?\ constructs ???) + */ ULONG NTAPI -RtlDosSearchPath_U ( - PCWSTR sp, - PCWSTR name, - PCWSTR ext, - ULONG buf_sz, - WCHAR *buffer, - PWSTR *FilePart - ) +RtlDosSearchPath_U(PCWSTR paths, + PCWSTR search, + PCWSTR ext, + ULONG buffer_size, + PWSTR buffer, + PWSTR* file_part) { - ULONG Type; - ULONG Length = 0; - PWSTR full_name; - PWSTR wcs; - PCWSTR path; + RTL_PATH_TYPE type = RtlDetermineDosPathNameType_U(search); + ULONG len = 0; - Type = RtlDetermineDosPathNameType_U (name); + if (type == RtlPathTypeRelative) + { + ULONG allocated = 0, needed, filelen; + WCHAR *name = NULL; - if (Type == 5) - { - Length = wcslen (sp); - Length += wcslen (name); - if (wcschr (name, L'.')) - ext = NULL; - if (ext != NULL) - Length += wcslen (ext); + filelen = 1 /* for \ */ + wcslen(search) + 1 /* \0 */; - full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (), - 0, - (Length + 1) * sizeof(WCHAR)); - Length = 0; - if (full_name != NULL) - { - path = sp; - while (*path) - { - wcs = full_name; - while (*path && *path != L';') - *wcs++ = *path++; - if (*path) - path++; - if (wcs != full_name && *(wcs - 1) != L'\\') - *wcs++ = L'\\'; - wcscpy (wcs, name); - if (ext) - wcscat (wcs, ext); - if (RtlDoesFileExists_U (full_name)) - { - Length = RtlGetFullPathName_U (full_name, - buf_sz, - buffer, - FilePart); - break; - } - } + /* Windows only checks for '.' without worrying about path components */ + if (wcschr( search, '.' )) ext = NULL; + if (ext != NULL) filelen += wcslen(ext); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - full_name); - } - } - else if (RtlDoesFileExists_U (name)) - { - Length = RtlGetFullPathName_U (name, - buf_sz, - buffer, - FilePart); - } + while (*paths) + { + LPCWSTR ptr; - return Length; + for (needed = 0, ptr = paths; *ptr != 0 && *ptr++ != ';'; needed++); + if (needed + filelen > allocated) + { + if (!name) name = RtlAllocateHeap(RtlGetProcessHeap(), 0, + (needed + filelen) * sizeof(WCHAR)); + else + { + WCHAR *newname = RtlReAllocateHeap(RtlGetProcessHeap(), 0, name, + (needed + filelen) * sizeof(WCHAR)); + if (!newname) RtlFreeHeap(RtlGetProcessHeap(), 0, name); + name = newname; + } + if (!name) return 0; + allocated = needed + filelen; + } + memmove(name, paths, needed * sizeof(WCHAR)); + /* append '\\' if none is present */ + if (needed > 0 && name[needed - 1] != '\\') name[needed++] = '\\'; + wcscpy(&name[needed], search); + if (ext) wcscat(&name[needed], ext); + if (RtlDoesFileExists_U(name)) + { + len = RtlGetFullPathName_U(name, buffer_size, buffer, file_part); + break; + } + paths = ptr; + } + RtlFreeHeap(RtlGetProcessHeap(), 0, name); + } + else if (RtlDoesFileExists_U(search)) + { + len = RtlGetFullPathName_U(search, buffer_size, buffer, file_part); + } + + return len; } @@ -881,11 +879,10 @@ RtlDoesFileExists_U(IN PCWSTR FileName) { UNICODE_STRING NtFileName; OBJECT_ATTRIBUTES Attr; - FILE_BASIC_INFORMATION Info; + FILE_BASIC_INFORMATION Info; NTSTATUS Status; CURDIR CurDir; - if (!RtlDosPathNameToNtPathName_U (FileName, &NtFileName, NULL, @@ -905,7 +902,7 @@ RtlDoesFileExists_U(IN PCWSTR FileName) Status = ZwQueryAttributesFile (&Attr, &Info); - RtlFreeUnicodeString(&NtFileName); + RtlFreeUnicodeString(&NtFileName); if (NT_SUCCESS(Status) ||