[RTL/PATH]
authorAleksey Bragin <aleksey@reactos.org>
Wed, 2 Mar 2011 11:42:30 +0000 (11:42 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Wed, 2 Mar 2011 11:42:30 +0000 (11:42 +0000)
- 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

index 238d5c8..d0b4e21 100644 (file)
@@ -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);
-
-               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;
-                               }
-                       }
+        filelen = 1 /* for \ */ + wcslen(search) + 1 /* \0 */;
 
-                       RtlFreeHeap (RtlGetProcessHeap (),
-                                    0,
-                                    full_name);
-               }
-       }
-       else if (RtlDoesFileExists_U (name))
-       {
-               Length = RtlGetFullPathName_U (name,
-                                              buf_sz,
-                                              buffer,
-                                              FilePart);
-       }
+        /* Windows only checks for '.' without worrying about path components */
+        if (wcschr( search, '.' )) ext = NULL;
+        if (ext != NULL) filelen += wcslen(ext);
+
+        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) ||