- Make the drive letter to uppercase in RtlDosPathNameToNtPathName_U.
[reactos.git] / reactos / lib / ntdll / rtl / path.c
index 8363da0..3e60798 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: path.c,v 1.22 2003/10/18 20:32:58 navaraf Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
 
 #include <ddk/ntddk.h>
 #include <ntdll/rtl.h>
+#include <ntos/minmax.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <base.h>
 #include <ddk/obfuncs.h>
-#include <ntos/rtl.h>
 
 #define NDEBUG
 #include <ntdll/ntdll.h>
 
 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
 
+
 /* GLOBALS ********************************************************************/
 
-static const UNICODE_STRING _condev = 
-{
-    .Length        = sizeof(L"\\\\.\\CON") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"\\\\.\\CON"),
-    .Buffer        = L"\\\\.\\CON"
-};
+static const WCHAR DeviceRootW[] = L"\\\\.\\";
 
-static const UNICODE_STRING _lpt =
-{
-    .Length        = sizeof(L"LPT") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"LPT"),
-    .Buffer        = L"LPT"
-};
+static const UNICODE_STRING _condev = RTL_CONSTANT_STRING(L"\\\\.\\CON");
 
-static const UNICODE_STRING _com =
-{
-    .Length        = sizeof(L"COM") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"COM"),
-    .Buffer        = L"COM"
-};
+static const UNICODE_STRING _lpt = RTL_CONSTANT_STRING(L"LPT");
 
-static const UNICODE_STRING _prn =
-{
-    .Length        = sizeof(L"PRN") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"PRN"),
-    .Buffer        = L"PRN"
-};
+static const UNICODE_STRING _com = RTL_CONSTANT_STRING(L"COM");
 
-static const UNICODE_STRING _aux =
-{
-    .Length        = sizeof(L"AUX") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"AUX"),
-    .Buffer        = L"AUX"
-};
+static const UNICODE_STRING _prn = RTL_CONSTANT_STRING(L"PRN");
 
-static const UNICODE_STRING _con =
-{
-    .Length        = sizeof(L"CON") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"CON"),
-    .Buffer        = L"CON"
-};
+static const UNICODE_STRING _aux = RTL_CONSTANT_STRING(L"AUX");
 
-static const UNICODE_STRING _nul =
-{
-    .Length        = sizeof(L"NUL") - sizeof(WCHAR),
-    .MaximumLength  = sizeof(L"NUL"),
-    .Buffer        = L"NUL"
-};
+static const UNICODE_STRING _con = RTL_CONSTANT_STRING(L"CON");
+
+static const UNICODE_STRING _nul = RTL_CONSTANT_STRING(L"NUL");
 
 /* FUNCTIONS *****************************************************************/
 
+
 /*
  * @implemented
  */
@@ -91,44 +61,38 @@ ULONG STDCALL RtlGetLongestNtPathLength (VOID)
 
 /*
  * @implemented
+ *
  */
 ULONG STDCALL
-RtlDetermineDosPathNameType_U(PWSTR Path)
+RtlDetermineDosPathNameType_U(PCWSTR Path)
 {
    DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
 
    if (Path == NULL)
-     {
-       return 0;
-     }
+   {
+      return INVALID_PATH;
+   }
 
    if (IS_PATH_SEPARATOR(Path[0]))
-     {
-       if (!IS_PATH_SEPARATOR(Path[1]))
-         {
-            return 4;                  /* \xxx   */
-         }
-
-       if (Path[2] != L'.')
-         return 1;                     /* \\xxx   */
-
-       if (IS_PATH_SEPARATOR(Path[3]))
-         return 6;                     /* \\.\xxx */
-
-       if (Path[3])
-         return 1;                     /* \\.xxxx */
+   {
+      if (!IS_PATH_SEPARATOR(Path[1])) return ABSOLUTE_PATH;         /* \xxx   */
+      if (Path[2] != L'.') return UNC_PATH;                          /* \\xxx   */
+      if (IS_PATH_SEPARATOR(Path[3])) return DEVICE_PATH;            /* \\.\xxx */
+      if (Path[3]) return UNC_PATH;                                  /* \\.xxxx */
 
-       return 7;                               /* \\.     */
-     }
+      return UNC_DOT_PATH;                                           /* \\.     */
+   }
    else
-     {
-       if (Path[1] != L':')
-               return 5;                       /* xxx     */
-
-       if (IS_PATH_SEPARATOR(Path[2]))
-               return 2;                       /* x:\xxx  */
-
-       return 3;                               /* x:xxx   */
+   {
+      /* FIXME: the Wine version of this line reads:
+       * if (!Path[1] || Path[1] != L':')    return RELATIVE_PATH
+       * Should we do this too?
+       * -Gunnar
+       */ 
+      if (Path[1] != L':') return RELATIVE_PATH;                     /* xxx     */
+      if (IS_PATH_SEPARATOR(Path[2])) return ABSOLUTE_DRIVE_PATH;    /* x:\xxx  */
+
+      return RELATIVE_DRIVE_PATH;                                    /* x:xxx   */
    }
 }
 
@@ -291,7 +255,7 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
    PWSTR buf = 0;
    PFILE_NAME_INFORMATION filenameinfo;
    ULONG backslashcount = 0;
-   PWSTR cntr;
+   ULONG Index;
    WCHAR var[4];
    
    DPRINT ("RtlSetCurrentDirectory %wZ\n", name);
@@ -354,7 +318,7 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
        RtlReleasePebLock ();
        return Status;
      }
-   
+
    filenameinfo = RtlAllocateHeap(RtlGetProcessHeap(),
                                  0,
                                  MAX_PATH*sizeof(WCHAR)+sizeof(ULONG));
@@ -379,7 +343,8 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
        return(Status);
      }
    
-   if (filenameinfo->FileName[1]) // If it's just "\", we need special handling
+   /* If it's just "\", we need special handling */
+   if (filenameinfo->FileNameLength > sizeof(WCHAR))
      {
        wcs = buf + size / sizeof(WCHAR) - 1;
        if (*wcs == L'\\')
@@ -389,9 +354,11 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
            size -= sizeof(WCHAR);
          }
 
-       for (cntr=filenameinfo->FileName;*cntr!=0;cntr++)
+       for (Index = 0;
+            Index < filenameinfo->FileNameLength / sizeof(WCHAR);
+            Index++)
          {
-            if (*cntr=='\\') backslashcount++;
+            if (filenameinfo->FileName[Index] == '\\') backslashcount++;
          }
 
        DPRINT("%d \n",backslashcount);
@@ -401,9 +368,10 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
          }
        wcs++;
 
-       wcscpy(wcs,filenameinfo->FileName);
+       RtlCopyMemory(wcs, filenameinfo->FileName, filenameinfo->FileNameLength);
+       wcs[filenameinfo->FileNameLength / sizeof(WCHAR)] = 0;
 
-       size=((wcs-buf)+wcslen(filenameinfo->FileName))*sizeof(WCHAR);
+       size = (wcs - buf) * sizeof(WCHAR) + filenameinfo->FileNameLength;
      }
    
    RtlFreeHeap (RtlGetProcessHeap (),
@@ -423,7 +391,7 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
           buf,
           size + sizeof(WCHAR));
    cd->DosPath.Length = size;
-   
+
    if (cd->Handle)
      NtClose(cd->Handle);
    cd->Handle = handle;
@@ -452,59 +420,158 @@ RtlSetCurrentDirectory_U(PUNICODE_STRING name)
    return STATUS_SUCCESS;
 }
 
+
+
+/******************************************************************
+ *    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.
+ */
+static inline void collapse_path( WCHAR *path, UINT mark )
+{
+    WCHAR *p, *next;
+
+    /* convert every / into a \ */
+    for (p = path; *p; p++) if (*p == '/') *p = '\\';
+
+    /* collapse duplicate backslashes */
+    next = path + max( 1, mark );
+    for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p;
+    *next = 0;
+
+    p = path + mark;
+    while (*p)
+    {
+        if (*p == '.')
+        {
+            switch(p[1])
+            {
+            case '\\': /* .\ component */
+                next = p + 2;
+                memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
+                continue;
+            case 0:  /* final . */
+                if (p > path + mark) p--;
+                *p = 0;
+                continue;
+            case '.':
+                if (p[2] == '\\')  /* ..\ component */
+                {
+                    next = p + 3;
+                    if (p > path + mark)
+                    {
+                        p--;
+                        while (p > path + mark && p[-1] != '\\') p--;
+                    }
+                    memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
+                    continue;
+                }
+                else if (!p[2])  /* final .. */
+                {
+                    if (p > path + mark)
+                    {
+                        p--;
+                        while (p > path + mark && p[-1] != '\\') p--;
+                        if (p > path + mark) p--;
+                    }
+                    *p = 0;
+                    continue;
+                }
+                break;
+            }
+        }
+        /* skip to the next component */
+        while (*p && *p != '\\') p++;
+        if (*p == '\\') p++;
+    }
+
+    /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */
+    while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--;
+    *p = 0;
+}
+
+
+
 /******************************************************************
- *             get_full_path_helper
+ *    skip_unc_prefix
+ *
+ * Skip the \\share\dir\ part of a file name. Helper for RtlGetFullPathName_U.
+ */
+static const WCHAR *skip_unc_prefix( const WCHAR *ptr )
+{
+    ptr += 2;
+    while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++;  /* share name */
+    while (IS_PATH_SEPARATOR(*ptr)) ptr++;
+    while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++;  /* dir name */
+    while (IS_PATH_SEPARATOR(*ptr)) ptr++;
+    return ptr;
+}
+
+
+/******************************************************************
+ *    get_full_path_helper
  *
  * Helper for RtlGetFullPathName_U
+ * Note: name and buffer are allowed to point to the same memory spot
  */
-static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
+static ULONG get_full_path_helper(
+   LPCWSTR name, 
+   LPWSTR buffer, 
+   ULONG size)
 {
-    ULONG               reqsize, mark = 0;
-    /*DOS_PATHNAME_TYPE*/INT   type;
-    LPWSTR              ptr;
-    UNICODE_STRING*     cd;
+    ULONG                       reqsize = 0, mark = 0, dep = 0, deplen;
+    DOS_PATHNAME_TYPE           type;
+    LPWSTR                      ins_str = NULL;
+    LPCWSTR                     ptr;
+    const UNICODE_STRING*       cd;
+    WCHAR                       tmp[4];
 
-    reqsize = sizeof(WCHAR); /* '\0' at the end */
+    /* return error if name only consists of spaces */
+    for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
+    if (!*ptr) return 0;
 
     RtlAcquirePebLock();
-    cd = &NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName;
 
-    switch (type = RtlDetermineDosPathNameType_U((LPWSTR)name))
+    cd = &((PCURDIR)&NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectoryName)->DosPath;
+
+    switch (type = RtlDetermineDosPathNameType_U(name))
     {
-    case 1 /*UNC_PATH*/:              /* \\foo   */
-    case 6 /*DEVICE_PATH*/:           /* \\.\foo */
-        if (reqsize <= size) buffer[0] = '\0';
+    case UNC_PATH:              /* \\foo   */
+        ptr = skip_unc_prefix( name );
+        mark = (ptr - name);
         break;
 
-    case 2 /*ABSOLUTE_DRIVE_PATH*/:   /* c:\foo  */
-        reqsize += sizeof(WCHAR);
-        if (reqsize <= size)
-        {
-            buffer[0] = RtlUpcaseUnicodeChar(name[0]);
-            buffer[1] = '\0';
-        }
-        name++;
+    case DEVICE_PATH:           /* \\.\foo */
+        mark = 4;
+        break;
+
+    case ABSOLUTE_DRIVE_PATH:   /* c:\foo  */
+        reqsize = sizeof(WCHAR);
+        tmp[0] = towupper(name[0]);
+        ins_str = tmp;
+        dep = 1;
+        mark = 3;
         break;
 
-    case 3 /*RELATIVE_DRIVE_PATH*/:   /* c:foo   */
-        if (RtlUpcaseUnicodeChar(name[0]) != RtlUpcaseUnicodeChar(cd->Buffer[0]) ||
-            cd->Buffer[1] != ':')
+    case RELATIVE_DRIVE_PATH:   /* c:foo   */
+        dep = 2;
+        if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':')
         {
-            WCHAR               drive[4];
             UNICODE_STRING      var, val;
 
-            drive[0] = '=';
-            drive[1] = name[0];
-            drive[2] = ':';
-            drive[3] = '\0';
-            var.Length = 6;
-            var.MaximumLength = 8;
-            var.Buffer = drive;
+            tmp[0] = '=';
+            tmp[1] = name[0];
+            tmp[2] = ':';
+            tmp[3] = '\0';
+            var.Length = 3 * sizeof(WCHAR);
+            var.MaximumLength = 4 * sizeof(WCHAR);
+            var.Buffer = tmp;
             val.Length = 0;
             val.MaximumLength = size;
-            val.Buffer = buffer;
-
-            name += 2;
+            val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size);
 
             switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
             {
@@ -516,182 +583,150 @@ static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size)
                  */
                 /* fall thru */
             case STATUS_BUFFER_TOO_SMALL:
-                reqsize += val.Length;
-                /* append trailing \\ */
-                reqsize += sizeof(WCHAR);
-                if (reqsize <= size)
-                {
-                    buffer[reqsize / sizeof(WCHAR) - 2] = '\\';
-                    buffer[reqsize / sizeof(WCHAR) - 1] = '\0';
-                }
+                reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
+                val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
+                ins_str = val.Buffer;
                 break;
             case STATUS_VARIABLE_NOT_FOUND:
-                reqsize += 3 * sizeof(WCHAR);
-                if (reqsize <= size)
-                {
-                    buffer[0] = drive[1];
-                    buffer[1] = ':';
-                    buffer[2] = '\\';
-                    buffer[3] = '\0';
-                }
+                reqsize = 3 * sizeof(WCHAR);
+                tmp[0] = name[0];
+                tmp[1] = ':';
+                tmp[2] = '\\';
+                ins_str = tmp;
                 break;
             default:
-                DPRINT("Unsupported status code\n");
+                DPRINT1("Unsupported status code\n");
                 break;
             }
+            mark = 3;
             break;
         }
-        name += 2;
         /* fall through */
 
-    case 5 /*RELATIVE_PATH*/:         /* foo     */
-        reqsize += cd->Length;
-        if (reqsize <= size)
-        {
-            memcpy(buffer, cd->Buffer, cd->Length);
-            buffer[cd->Length / sizeof(WCHAR)] = 0;
-        }
+    case RELATIVE_PATH:         /* foo     */
+        reqsize = cd->Length;
+        ins_str = cd->Buffer;
         if (cd->Buffer[1] != ':')
         {
-            ptr = wcsrchr(cd->Buffer + 2, '\\');
-            if (ptr) ptr = wcsrchr(ptr + 1, '\\');
-            if (!ptr) ptr = cd->Buffer + wcslen(cd->Buffer);
+            ptr = skip_unc_prefix( cd->Buffer );
             mark = ptr - cd->Buffer;
         }
+        else mark = 3;
         break;
 
-    case 4 /*ABSOLUTE_PATH*/:         /* \xxx    */
-        if (cd->Buffer[1] == ':')
+    case ABSOLUTE_PATH:         /* \xxx    */
+#ifdef __WINE__
+        if (name[0] == '/')  /* may be a Unix path */
         {
-            reqsize += 2 * sizeof(WCHAR);
-            if (reqsize <= size)
+            const WCHAR *ptr = name;
+            int drive = find_drive_root( &ptr );
+            if (drive != -1)
             {
-                buffer[0] = cd->Buffer[0];
-                buffer[1] = ':';
-                buffer[2] = '\0';
+                reqsize = 3 * sizeof(WCHAR);
+                tmp[0] = 'A' + drive;
+                tmp[1] = ':';
+                tmp[2] = '\\';
+                ins_str = tmp;
+                mark = 3;
+                dep = ptr - name;
+                break;
             }
         }
+#endif
+        if (cd->Buffer[1] == ':')
+        {
+            reqsize = 2 * sizeof(WCHAR);
+            tmp[0] = cd->Buffer[0];
+            tmp[1] = ':';
+            ins_str = tmp;
+            mark = 3;
+        }
         else
         {
-            unsigned    len;
-
-            ptr = wcsrchr(cd->Buffer + 2, '\\');
-            if (ptr) ptr = wcsrchr(ptr + 1, '\\');
-            if (!ptr) ptr = cd->Buffer + wcslen(cd->Buffer);
-            len = (ptr - cd->Buffer) * sizeof(WCHAR);
-            reqsize += len;
-            mark = len / sizeof(WCHAR);
-            if (reqsize <= size)
-            {
-                memcpy(buffer, cd->Buffer, len);
-                buffer[len / sizeof(WCHAR)] = '\0';
-            }
-            else
-                buffer[0] = '\0';
+            ptr = skip_unc_prefix( cd->Buffer );
+            reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
+            mark = reqsize / sizeof(WCHAR);
+            ins_str = cd->Buffer;
         }
         break;
 
-    case 7 /*UNC_DOT_PATH*/:         /* \\.     */
-        reqsize += 4 * sizeof(WCHAR);
-        name += 3;
-        if (reqsize <= size)
-        {
-            buffer[0] = '\\';
-            buffer[1] = '\\';
-            buffer[2] = '.';
-            buffer[3] = '\\';
-            buffer[4] = '\0';
-        }
+    case UNC_DOT_PATH:         /* \\.     */
+        reqsize = 4 * sizeof(WCHAR);
+        dep = 3;
+        tmp[0] = '\\';
+        tmp[1] = '\\';
+        tmp[2] = '.';
+        tmp[3] = '\\';
+        ins_str = tmp;
+        mark = 4;
         break;
 
-    case 0 /*INVALID_PATH*/:
-        reqsize = 0;
+    case INVALID_PATH:
         goto done;
     }
 
-    reqsize += wcslen(name) * sizeof(WCHAR);
-    if (reqsize > size) goto done;
-
-    wcscat(buffer, name);
+    /* enough space ? */
+    deplen = wcslen(name + dep) * sizeof(WCHAR);
+    if (reqsize + deplen + sizeof(WCHAR) > size)
+    {
+        /* not enough space, return need size (including terminating '\0') */
+        reqsize += deplen + sizeof(WCHAR);
+        goto done;
+    }
 
-    /* convert every / into a \ */
-    for (ptr = buffer; ptr < buffer + size / sizeof(WCHAR); ptr++) 
-        if (*ptr == '/') *ptr = '\\';
+    memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
+    if (reqsize) memcpy(buffer, ins_str, reqsize);
+    reqsize += deplen;
 
-    reqsize -= sizeof(WCHAR); /* don't count trailing \0 */
+    if (ins_str && ins_str != tmp && ins_str != cd->Buffer)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str);
 
-    /* mark is non NULL for UNC names, so start path collapsing after server & share name
-     * otherwise, it's a fully qualified DOS name, so start after the drive designation
-     */
-    for (ptr = buffer + (mark ? mark : 2); ptr < buffer + reqsize / sizeof(WCHAR); )
-    {
-        WCHAR* p = wcsrchr(ptr, '\\');
-        if (!p) break;
-
-        p++;
-        if (p[0] == '.')
-        {
-            switch (p[1])
-            {
-            case '.':
-                switch (p[2])
-                {
-                case '\\':
-                    {
-                        WCHAR*      prev = p - 2;
-                        while (prev >= buffer + mark && *prev != '\\') prev--;
-                        /* either collapse \foo\.. into \ or \.. into \ */
-                        if (prev < buffer + mark) prev = p - 1;
-                        reqsize -= (p + 2 - prev) * sizeof(WCHAR);
-                        memmove(prev, p + 2, buffer + reqsize - prev + sizeof(WCHAR));
-                        p = prev;
-                    }
-                    break;
-                case '\0':
-                    reqsize -= 2 * sizeof(WCHAR);
-                    *p = 0;
-                    break;
-                }
-                break;
-            case '\\':
-                reqsize -= 2 * sizeof(WCHAR);
-                memmove(ptr, ptr + 2, buffer + reqsize - ptr + sizeof(WCHAR));
-                break;
-            }
-        }
-        ptr = p;
-    }
+    collapse_path( buffer, mark );
+    reqsize = wcslen(buffer) * sizeof(WCHAR);
 
 done:
     RtlReleasePebLock();
     return reqsize;
 }
 
-/*
+
+/******************************************************************
+ *    RtlGetFullPathName_U  (NTDLL.@)
+ *
+ * Returns the number of bytes written to buffer (not including the
+ * terminating NULL) if the function succeeds, or the required number of bytes
+ * (including the terminating NULL) if the buffer is too small.
+ *
+ * file_part will point to the filename part inside buffer (except if we use
+ * DOS device name, in which case file_in_buf is NULL)
+ *
  * @implemented
  */
-DWORD STDCALL RtlGetFullPathName_U(WCHAR* name, ULONG size, WCHAR* buffer,
-                                  WCHAR** file_part)
+DWORD STDCALL RtlGetFullPathName_U(
+   const WCHAR* name, 
+   ULONG size, 
+   WCHAR* buffer,
+   WCHAR** file_part)
 {
     WCHAR*      ptr;
     DWORD       dosdev;
     DWORD       reqsize;
 
-    DPRINT("(%s %lu %p %p)\n", name, size, buffer, file_part);
+    DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
 
     if (!name || !*name) return 0;
 
     if (file_part) *file_part = NULL;
 
     /* check for DOS device name */
-    dosdev = RtlIsDosDeviceName_U((WCHAR *)name);
+    dosdev = RtlIsDosDeviceName_U((WCHAR*)name);
     if (dosdev)
     {
-        DWORD   offset = ((dosdev & 0xffff0000) >> 16) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
-        DWORD   sz = dosdev & 0xffff; /* in bytes */
+        DWORD   offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
+        DWORD   sz = LOWORD(dosdev); /* in bytes */
 
         if (8 + sz + 2 > size) return sz + 10;
-        wcscpy(buffer, L"\\\\.\\");
+        wcscpy(buffer, DeviceRootW);
         memmove(buffer + 4, name + offset, sz);
         buffer[4 + sz / sizeof(WCHAR)] = '\0';
         /* file_part isn't set in this case */
@@ -699,6 +734,7 @@ DWORD STDCALL RtlGetFullPathName_U(WCHAR* name, ULONG size, WCHAR* buffer,
     }
 
     reqsize = get_full_path_helper(name, buffer, size);
+    if (!reqsize) return 0;
     if (reqsize > size)
     {
         LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize);
@@ -718,8 +754,9 @@ DWORD STDCALL RtlGetFullPathName_U(WCHAR* name, ULONG size, WCHAR* buffer,
     return reqsize;
 }
 
+
 /*
- * @unimplemented
+ * @implemented
  */
 BOOLEAN STDCALL
 RtlDosPathNameToNtPathName_U(PWSTR dosname,
@@ -737,6 +774,7 @@ RtlDosPathNameToNtPathName_U(PWSTR dosname,
        WCHAR fullname[MAX_PATH + 1];
        PWSTR Buffer = NULL;
 
+
        RtlAcquirePebLock ();
 
        RtlInitUnicodeString (&us, dosname);
@@ -801,6 +839,12 @@ RtlDosPathNameToNtPathName_U(PWSTR dosname,
        Length = wcslen(fullname + Offset);
        memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
        Length += tmpLength;
+       if (Type == ABSOLUTE_DRIVE_PATH ||
+           Type == RELATIVE_DRIVE_PATH)
+       {
+           /* make the drive letter to uppercase */
+           Buffer[tmpLength] = towupper(Buffer[tmpLength]);
+       }
 
        /* set NT filename */
        ntname->Length        = Length * sizeof(WCHAR);
@@ -831,7 +875,6 @@ RtlDosPathNameToNtPathName_U(PWSTR dosname,
        }
 
        RtlReleasePebLock();
-
        return TRUE;
 }
 
@@ -914,7 +957,7 @@ RtlDosSearchPath_U (
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOLEAN STDCALL
 RtlDoesFileExists_U(IN PWSTR FileName)
@@ -975,4 +1018,18 @@ RtlDoesFileExists_U(IN PWSTR FileName)
        return FALSE;
 }
 
+NTSTATUS STDCALL
+RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
+{
+    DPRINT1("RtlpEnsureBufferSize: stub\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS STDCALL
+RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
+{
+    DPRINT1("RtlNtPathNameToDosPathName: stub\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 /* EOF */