Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 52943)
+++ /trunk/include/iprt/mangling.h	(revision 52944)
@@ -1035,4 +1035,6 @@
 # define RTPathFilenameEx                               RT_MANGLER(RTPathFilenameEx)
 # define RTPathGetCurrent                               RT_MANGLER(RTPathGetCurrent)
+# define RTPathGetCurrentDrive                          RT_MANGLER(RTPathGetCurrentDrive)
+# define RTPathGetCurrentOnDrive                        RT_MANGLER(RTPathGetCurrentOnDrive)
 # define RTPathGetMode                                  RT_MANGLER(RTPathGetMode)
 # define RTPathHasSuffix                                RT_MANGLER(RTPathHasSuffix)
@@ -1796,4 +1798,5 @@
 # define RTUriQuery                                     RT_MANGLER(RTUriQuery)
 # define RTUriScheme                                    RT_MANGLER(RTUriScheme)
+# define RTUtf16AllocTag                                RT_MANGLER(RTUtf16AllocTag)
 # define RTUtf16CalcLatin1Len                           RT_MANGLER(RTUtf16CalcLatin1Len)
 # define RTUtf16CalcLatin1LenEx                         RT_MANGLER(RTUtf16CalcLatin1LenEx)
Index: /trunk/include/iprt/nt/nt.h
===================================================================
--- /trunk/include/iprt/nt/nt.h	(revision 52943)
+++ /trunk/include/iprt/nt/nt.h	(revision 52944)
@@ -237,4 +237,29 @@
                             ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
 RTDECL(int) RTNtPathClose(HANDLE hHandle);
+
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              RTNtPathFree.
+ * @param   phRootDir           Where to return the root handle, if applicable.
+ * @param   pwszPath            The UTF-16 windows-style path.
+ * @param   cwcPath             The max length of the windows-style path in
+ *                              RTUTF16 units.  Use RTSTR_MAX if unknown and @a
+ *                              pwszPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszPath, size_t cwcPath);
+
+/**
+ * Frees the native path and root handle.
+ *
+ * @param   pNtName             The NT path after a successful
+ *                              RTNtPathFromWinUtf16Ex call.
+ * @param   phRootDir           The root handle variable after a successfull
+ *                              RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir);
+
 
 RT_C_DECLS_END
Index: /trunk/include/iprt/path.h
===================================================================
--- /trunk/include/iprt/path.h	(revision 52943)
+++ /trunk/include/iprt/path.h	(revision 52944)
@@ -238,4 +238,30 @@
  */
 RTDECL(int)  RTPathGetCurrent(char *pszPath, size_t cchPath);
+
+/**
+ * Gets the current working directory on the specified drive.
+ *
+ * On systems without drive letters, the root slash will be returned.
+ *
+ * @returns IPRT status code.
+ * @param   chDrive         The drive we're querying the driver letter on.
+ * @param   pszPath         Where to store the working directroy path.
+ * @param   cbPath          The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath);
+
+/**
+ * Gets the current working drive of the process.
+ *
+ * Normally drive letter and colon will be returned, never trailing a root
+ * slash.  If the current directory is on a UNC share, the root of the share
+ * will be returned.  On systems without drive letters, an empty string is
+ * returned for consistency.
+ *
+ * @returns IPRT status code.
+ * @param   pszPath         Where to store the working drive or UNC root.
+ * @param   cbPath          The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath);
 
 /**
Index: /trunk/include/iprt/string.h
===================================================================
--- /trunk/include/iprt/string.h	(revision 52943)
+++ /trunk/include/iprt/string.h	(revision 52944)
@@ -3220,4 +3220,50 @@
 
 /**
+ * Allocates memory for UTF-16 string storage (default tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string.  The first wide char is
+ *          always set to the string terminator char, the contents of the
+ *          remainder of the memory is undefined.  The string must be freed by
+ *          calling RTUtf16Free.
+ *
+ *          NULL is returned if the allocation failed.  Please translate this to
+ *          VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY.  Also consider
+ *          RTUtf16AllocEx if an IPRT status code is required.
+ *
+ * @param   cb                  How many bytes to allocate, will be rounded up
+ *                              to a multiple of two. If this is zero, we will
+ *                              allocate a terminator wide char anyway.
+ */
+#define RTUtf16Alloc(cb)                    RTUtf16AllocTag((cb), RTSTR_TAG)
+
+/**
+ * Allocates memory for UTF-16 string storage (custom tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string.  The first wide char is
+ *          always set to the string terminator char, the contents of the
+ *          remainder of the memory is undefined.  The string must be freed by
+ *          calling RTUtf16Free.
+ *
+ *          NULL is returned if the allocation failed.  Please translate this to
+ *          VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY.  Also consider
+ *          RTUtf16AllocExTag if an IPRT status code is required.
+ *
+ * @param   cb                  How many bytes to allocate, will be rounded up
+ *                              to a multiple of two. If this is zero, we will
+ *                              allocate a terminator wide char anyway.
+ * @param   pszTag              Allocation tag used for statistics and such.
+ */
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag);
+
+
+/**
  * Free a UTF-16 string allocated by RTStrToUtf16(), RTStrToUtf16Ex(),
  * RTLatin1ToUtf16(), RTLatin1ToUtf16Ex(), RTUtf16Dup() or RTUtf16DupEx().
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 52943)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 52944)
@@ -587,4 +587,5 @@
 	generic/RTLogWriteStdOut-generic.cpp \
 	generic/RTLogWriteUser-generic.cpp \
+	generic/RTPathGetCurrentDrive-generic.cpp \
 	generic/RTPathIsSame-generic.cpp \
 	generic/RTProcessQueryUsernameA-generic.cpp \
@@ -702,4 +703,5 @@
 	generic/RTMpGetCurFrequency-generic.cpp \
 	generic/RTMpGetMaxFrequency-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
 	generic/RTRandAdvCreateSystemFaster-generic.cpp \
 	generic/RTRandAdvCreateSystemTruer-generic.cpp \
@@ -768,4 +770,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
  	generic/RTSemEventMultiWait-2-ex-generic.cpp \
@@ -852,4 +856,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTRandAdvCreateSystemFaster-generic.cpp \
@@ -924,4 +930,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTThreadGetAffinity-stub-generic.cpp \
@@ -991,4 +999,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
  	generic/RTSemEventMultiWait-2-ex-generic.cpp \
  	generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
@@ -1060,4 +1070,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTProcIsRunningByName-generic.cpp \
@@ -1132,4 +1144,6 @@
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTTimeLocalNow-generic.cpp \
Index: /trunk/src/VBox/Runtime/common/string/utf-16.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 52943)
+++ /trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 52944)
@@ -100,4 +100,18 @@
 
 
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag)
+{
+    if (cb > sizeof(RTUTF16))
+        cb = RT_ALIGN_Z(cb, sizeof(RTUTF16));
+    else
+        cb = sizeof(RTUTF16);
+    PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag(cb, pszTag);
+    if (pwsz)
+        *pwsz = '\0';
+    return pwsz;
+}
+RT_EXPORT_SYMBOL(RTUtf16AllocTag);
+
+
 RTDECL(void)  RTUtf16Free(PRTUTF16 pwszString)
 {
Index: /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp	(revision 52944)
+++ /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp	(revision 52944)
@@ -0,0 +1,358 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathAbs, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+#include "internal/fs.h"
+
+
+static char *rtPathSkipRootSpec(char *pszCur)
+{
+#ifdef HAVE_DRIVE
+    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == RTPATH_SLASH)
+        pszCur += 3;
+# ifdef HAVE_UNC
+    else if (pszCur[0] == RTPATH_SLASH && pszCur[1] == RTPATH_SLASH)
+    {
+        pszCur += 2;
+        while (*pszCur == RTPATH_SLASH)
+            pszCur++;
+        if (*pszCur)
+        {
+            while (*pszCur != RTPATH_SLASH && *pszCur)
+                pszCur++;
+            if (*pszCur == RTPATH_SLASH)
+            {
+                pszCur++;
+                while (*pszCur != RTPATH_SLASH && *pszCur)
+                    pszCur++;
+                if (*pszCur == RTPATH_SLASH)
+                    pszCur++;
+            }
+        }
+    }
+# endif
+#else
+    if (pszCur[0] == RTPATH_SLASH)
+        pszCur += 1;
+#endif
+    return pszCur;
+}
+
+
+/**
+ * Cleans up a path specifier a little bit.
+ *
+ * This includes removing duplicate slashes, unnecessary single dots, and
+ * trailing slashes. Also, replaces all slash characters with RTPATH_SLASH.
+ *
+ * @returns Length of the cleaned path (in chars).
+ * @param   pszPath     The path to cleanup.
+ */
+static int fsCleanPath(char *pszPath)
+{
+    char *pszSrc = pszPath;
+    char *pszTrg = pszPath;
+
+    /*
+     * On windows, you either use on or two slashes at the head of a path,
+     * seems like it treats additional slashes as part of the UNC server name.
+     * Just change slashes to RTPATH_SLASH and skip them.
+     */
+    /** @todo check how OS/2 treats unnecessary leading slashes */
+    int cchIgnoreLeading = 0;
+#ifdef HAVE_UNC
+    if (   RTPATH_IS_SLASH(pszSrc[0])
+        && RTPATH_IS_SLASH(pszSrc[1]))
+    {
+        pszTrg[0] = RTPATH_SLASH;
+        pszTrg[1] = RTPATH_SLASH;
+        pszTrg += 2;
+        pszSrc += 2;
+        cchIgnoreLeading = 1;
+        while (RTPATH_IS_SLASH(*pszSrc))
+        {
+            cchIgnoreLeading++;
+            pszSrc++;
+            *pszTrg++ = RTPATH_SLASH;
+        }
+    }
+#endif
+
+    /*
+     * Change slashes to RTPATH_SLASH and remove duplicates.
+     */
+    for (;;)
+    {
+        char ch = *pszSrc++;
+        if (RTPATH_IS_SLASH(ch))
+        {
+            *pszTrg++ = RTPATH_SLASH;
+            for (;;)
+            {
+                do
+                    ch = *pszSrc++;
+                while (RTPATH_IS_SLASH(ch));
+
+                /* Remove '/./' and '/.'. */
+                if (   ch != '.'
+                    || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
+                    break;
+            }
+        }
+        *pszTrg = ch;
+        if (!ch)
+            break;
+        pszTrg++;
+    }
+
+    return pszTrg - pszPath;
+}
+
+
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+{
+    int rc;
+
+    /*
+     * Validation.
+     */
+    AssertPtr(pszAbsPath);
+    AssertPtr(pszPath);
+    if (RT_UNLIKELY(!*pszPath))
+        return VERR_INVALID_PARAMETER; //VERR_INVALID_NAME;
+
+    /*
+     * Make a clean working copy of the input.
+     */
+    size_t cchPath = strlen(pszPath);
+    if (cchPath >= RTPATH_MAX)
+    {
+        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
+        return VERR_FILENAME_TOO_LONG;
+    }
+
+    char szTmpPath[RTPATH_MAX];
+    memcpy(szTmpPath, pszPath, cchPath + 1);
+    size_t cchTmpPath = fsCleanPath(szTmpPath);
+
+    /*
+     * Handle "." specially (fsCleanPath does).
+     */
+    if (szTmpPath[0] == '.')
+    {
+        if (   cchTmpPath == 1
+            || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
+        {
+            rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
+            if (RT_SUCCESS(rc))
+            {
+                size_t cch = fsCleanPath(pszAbsPath);
+                char  *pszTop = rtPathSkipRootSpec(pszAbsPath);
+#if 1
+                if ((uintptr_t)&pszAbsPath[cch] > (uintptr_t)pszTop && pszAbsPath[cch - 1] == RTPATH_SLASH)
+                    pszAbsPath[cch - 1] = '\0';
+#else
+                if (   cchTmpPath == 2
+                    && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
+                {
+                    if (cch + 1 < cchAbsPath)
+                    {
+                        pszAbsPath[cch++] = RTPATH_SLASH;
+                        pszAbsPath[cch] = '\0';
+                    }
+                    else
+                        rc = VERR_BUFFER_OVERFLOW;
+                }
+#endif
+            }
+            return rc;
+        }
+    }
+
+    /*
+     * Do we have an incomplete root spec?  Supply the missing bits.
+     */
+#ifdef HAVE_DRIVE
+    if (   !(szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] == RTPATH_SLASH)
+# ifdef HAVE_UNC
+        && !(szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] == RTPATH_SLASH)
+# endif
+        )
+#else
+    if (szTmpPath[0] != RTPATH_SLASH)
+#endif
+    {
+        char    szCurDir[RTPATH_MAX];
+        size_t  cchCurDir;
+        int     offApplyAt;
+        bool    fNeedSlash;
+#ifdef HAVE_DRIVE
+        if (szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] != RTPATH_SLASH)
+        {
+            /*
+             * Relative to drive specific current directory.
+             */
+            rc = RTPathGetCurrentOnDrive(szTmpPath[0], szCurDir, sizeof(szCurDir));
+            fNeedSlash = true;
+            offApplyAt = 2;
+        }
+# ifdef HAVE_UNC
+        else if (szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] != RTPATH_SLASH)
+# else
+        else if (szTmpPath[0] == RTPATH_SLASH)
+# endif
+        {
+            /*
+             * Root of current drive.  This may return a UNC root if we're not
+             * standing on a drive but on a UNC share.
+             */
+            rc = RTPathGetCurrentDrive(szCurDir, sizeof(szCurDir));
+            fNeedSlash = false;
+            offApplyAt = 0;
+        }
+        else
+#endif
+        {
+            /*
+             * Relative to current directory.
+             */
+            rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
+            fNeedSlash = true;
+            offApplyAt = 0;
+        }
+        if (RT_SUCCESS(rc))
+        {
+            cchCurDir = fsCleanPath(szCurDir);
+            if (fNeedSlash && cchCurDir > 0 && szCurDir[cchCurDir - 1] == RTPATH_SLASH)
+                fNeedSlash = false;
+
+            if (cchCurDir + fNeedSlash + cchTmpPath - offApplyAt <= RTPATH_MAX)
+            {
+                memmove(szTmpPath + cchCurDir + fNeedSlash, szTmpPath + offApplyAt, cchTmpPath + 1 - offApplyAt);
+                memcpy(szTmpPath, szCurDir, cchCurDir);
+                if (fNeedSlash)
+                    szTmpPath[cchCurDir] = RTPATH_SLASH;
+            }
+            else
+                rc = VERR_FILENAME_TOO_LONG;
+        }
+        if (RT_FAILURE(rc))
+        {
+            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
+            return rc;
+        }
+    }
+
+    /*
+     * Skip past the root spec.
+     */
+    char *pszCur = rtPathSkipRootSpec(szTmpPath);
+    AssertMsgReturn(pszCur != &szTmpPath[0], ("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
+    char * const pszTop = pszCur;
+
+    /*
+     * Get rid of double dot path components by evaluating them.
+     */
+    for (;;)
+    {
+        if (   pszCur[0] == '.'
+            && pszCur[1] == '.'
+            && (!pszCur[2] || pszCur[2] == RTPATH_SLASH))
+        {
+            /* rewind to the previous component if any */
+            char *pszPrev = pszCur;
+            if ((uintptr_t)pszPrev > (uintptr_t)pszTop)
+            {
+                pszPrev--;
+                while (   (uintptr_t)pszPrev > (uintptr_t)pszTop
+                       && pszPrev[-1] != RTPATH_SLASH)
+                    pszPrev--;
+            }
+            if (!pszCur[2])
+            {
+                if (pszPrev != pszTop)
+                    pszPrev[-1] = '\0';
+                else
+                    *pszPrev = '\0';
+                break;
+            }
+            Assert(pszPrev[-1] == RTPATH_SLASH);
+            memmove(pszPrev, pszCur + 3, strlen(pszCur + 3) + 1);
+            pszCur = pszPrev - 1;
+        }
+        else
+        {
+            /* advance to end of component. */
+            while (*pszCur && *pszCur != RTPATH_SLASH)
+                pszCur++;
+        }
+
+        if (!*pszCur)
+            break;
+
+        /* skip the slash */
+        ++pszCur;
+    }
+
+    cchTmpPath = pszCur - szTmpPath;
+
+#if 1
+    /*
+     * Strip trailing slash if that's what's desired.
+     */
+
+    if ((uintptr_t)&szTmpPath[cchTmpPath] > (uintptr_t)pszTop && szTmpPath[cchTmpPath - 1] == RTPATH_SLASH)
+        szTmpPath[--cchTmpPath] = '\0';
+#endif
+
+    /*
+     * Copy the result to the user buffer.
+     */
+    if (cchTmpPath < cchAbsPath)
+    {
+        memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
+
+    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
+             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
+    return rc;
+}
+
Index: /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp	(revision 52944)
+++ /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp	(revision 52944)
@@ -0,0 +1,106 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathGetCurrentDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+    /*
+     * Query the current directroy and extract the wanted information from it.
+     */
+    int rc = RTPathGetCurrent(pszPath, cbPath);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Drive letter? Chop off at root slash.
+         */
+        if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
+        {
+            pszPath[2] = '\0';
+            return rc;
+        }
+
+        /*
+         * UNC? Chop off after share.
+         */
+        if (   RTPATH_IS_SLASH(pszPath[0])
+            && RTPATH_IS_SLASH(pszPath[1])
+            && !RTPATH_IS_SLASH(pszPath[2])
+            && pszPath[2])
+        {
+            /* Work thru the server name. */
+            size_t off = 3;
+            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                off++;
+            size_t offServerSlash = off;
+
+            /* Is there a share name? */
+            if (RTPATH_IS_SLASH(pszPath[off]))
+            {
+                while (RTPATH_IS_SLASH(pszPath[off]))
+                    off++;
+                if (pszPath[off])
+                {
+                    /* Work thru the share name. */
+                    while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                        off++;
+                }
+                /* No share name, chop at server name. */
+                else
+                    off = offServerSlash;
+            }
+        }
+        return VERR_INTERNAL_ERROR_4;
+    }
+    return rc;
+
+#else  /* !HAVE_DRIVE */
+    /*
+     * No drive letters on this system, return empty string.
+     */
+    if (cbPath > 0)
+    {
+        *pszPath = '\0';
+        return VINF_SUCCESS;
+    }
+    return VERR_BUFFER_OVERFLOW;
+#endif /* !HAVE_DRIVE */
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentDrive);
+
Index: /trunk/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp	(revision 52944)
+++ /trunk/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp	(revision 52944)
@@ -0,0 +1,84 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathGetCurrentOnDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+    /*
+     * Check if it's the same drive as the current directory.
+     */
+    int rc = RTPathGetCurrent(pszPath, cbPath);
+    if (RT_SUCCESS(rc))
+    {
+        if (   (   chDrive == *pszPath
+                || RT_C_TO_LOWER(chDrive) == RT_C_TO_LOWER(*pszPath))
+            && RTPATH_IS_VOLSEP(pszPath[1]))
+            return rc;
+
+        /*
+         * Different drive, indicate root.
+         */
+        if (cbPath >= 4)
+        {
+            pszPath[0] = RT_C_TO_UPPER(chDrive);
+            pszPath[1] = ':';
+            pszPath[2] = RTPATH_SLASH;
+            pszPath[3] = '\0';
+            return VINF_SUCCESS;
+        }
+    }
+    return rc;
+
+#else
+    /*
+     * No driver letters, just return root slash on whatever we're asked.
+     */
+    NOREF(chDrive);
+    if (cbPath >= 2)
+    {
+        pszPath[0] = RTPATH_SLASH;
+        pszPath[1] = '\0';
+        return VINF_SUCCESS;
+    }
+    return VERR_BUFFER_OVERFLOW;
+#endif
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentOnDrive);
+
Index: /trunk/src/VBox/Runtime/r3/nt/internal-r3-nt.h
===================================================================
--- /trunk/src/VBox/Runtime/r3/nt/internal-r3-nt.h	(revision 52943)
+++ /trunk/src/VBox/Runtime/r3/nt/internal-r3-nt.h	(revision 52944)
@@ -29,6 +29,9 @@
 #define ___internal_r3_nt_h___
 
-
-#include <iprt/nt/nt.h>
+#ifdef IN_SUP_HARDENED_R3
+# include <iprt/nt/nt-and-windows.h>
+#else
+# include <iprt/nt/nt.h>
+#endif
 #include "internal/iprt.h"
 
Index: /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp	(revision 52943)
+++ /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp	(revision 52944)
@@ -38,7 +38,13 @@
 
 
-
-/**
- * Handles the pass thru case.
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static char const g_szPrefixUnc[] = "\\??\\UNC\\";
+static char const g_szPrefix[]    = "\\??\\";
+
+
+/**
+ * Handles the pass thru case for UTF-8 input.
  *
  * @returns IPRT status code.
@@ -47,5 +53,5 @@
  * @param   pszPath             The UTF-8 path.
  */
-static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
     PRTUTF16 pwszPath = NULL;
@@ -61,5 +67,6 @@
 
             pNtName->Buffer = pwszPath;
-            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
             *phRootDir = NULL;
             return VINF_SUCCESS;
@@ -71,4 +78,54 @@
     return rc;
 }
+
+
+/**
+ * Handles the pass thru case for UTF-16 input.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.
+ * @param   phRootDir           Stores NULL here, as we don't use it.
+ * @param   pwszWinPath         The UTF-16 windows-style path.
+ * @param   cwcWinPath          The length of the windows-style input path.
+ */
+static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
+                                        PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+    /* Drop a character because: \\?\ -> \.\ */
+    pwszWinPath++;
+    cwcWinPath--;
+
+    /* Check length and allocate memory for it. */
+    int rc;
+    if (cwcWinPath < _32K - 1)
+    {
+        PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+        if (pwszNtPath)
+        {
+            /* Intialize the path. */
+            pwszNtPath[0] = '\\';
+            pwszNtPath[1] = '.';
+            pwszNtPath[2] = '\\';
+            memcpy(pwszNtPath + 3, pwszWinPath + 3, (cwcWinPath - 3) * sizeof(RTUTF16));
+            pwszNtPath[cwcWinPath] = '\0';
+
+            /* Initialize the return values. */
+            pNtName->Buffer = pwszNtPath;
+            pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+            *phRootDir = NULL;
+
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_NO_UTF16_MEMORY;
+    }
+    else
+        rc = VERR_FILENAME_TOO_LONG;
+    return rc;
+}
+
+
+
 
 
@@ -81,5 +138,5 @@
  * @param   pszPath             The UTF-8 path.
  */
-static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathUtf8ToUniStr(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
     PRTUTF16 pwszPath = NULL;
@@ -91,5 +148,6 @@
         {
             pNtName->Buffer = pwszPath;
-            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
             *phRootDir = NULL;
             return VINF_SUCCESS;
@@ -113,12 +171,9 @@
 static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
-    static char const s_szPrefixUnc[] = "\\??\\UNC\\";
-    static char const s_szPrefix[]    = "\\??\\";
-
     /*
      * Very simple conversion of a win32-like path into an NT path.
      */
-    const char *pszPrefix = s_szPrefix;
-    size_t      cchPrefix = sizeof(s_szPrefix) - 1;
+    const char *pszPrefix = g_szPrefix;
+    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
     size_t      cchSkip   = 0;
 
@@ -130,5 +185,5 @@
         if (   pszPath[2] == '?'
             && RTPATH_IS_SLASH(pszPath[3]))
-            return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
+            return rtNtPathFromWinUtf8PassThru(pNtName, phRootDir, pszPath);
 
 #ifdef IPRT_WITH_NT_PATH_PASSTHRU
@@ -136,5 +191,5 @@
         if (   pszPath[2] == '!'
             && RTPATH_IS_SLASH(pszPath[3]))
-            return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
+            return rtNtPathUtf8ToUniStr(pNtName, phRootDir, pszPath + 3);
 #endif
 
@@ -151,6 +206,6 @@
         {
             /* UNC */
-            pszPrefix = s_szPrefixUnc;
-            cchPrefix = sizeof(s_szPrefixUnc) - 1;
+            pszPrefix = g_szPrefixUnc;
+            cchPrefix = sizeof(g_szPrefixUnc) - 1;
             cchSkip   = 2;
         }
@@ -169,5 +224,116 @@
      */
     memcpy(szPath, pszPrefix, cchPrefix);
-    return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
+    return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
+}
+
+
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              RTNtPathFree.
+ * @param   phRootDir           Where to return the root handle, if applicable.
+ * @param   pwszWinPath         The UTF-16 windows-style path.
+ * @param   cwcWinPath          The max length of the windows-style path in
+ *                              RTUTF16 units.  Use RTSTR_MAX if unknown and @a
+ *                              pwszWinPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+    /*
+     * Validate the input, calculating the correct length.
+     */
+    if (cwcWinPath == 0 || *pwszWinPath == '\0')
+        return VERR_INVALID_NAME;
+
+    int rc = RTUtf16NLenEx(pwszWinPath, cwcWinPath, &cwcWinPath);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Very simple conversion of a win32-like path into an NT path.
+     */
+    const char *pszPrefix = g_szPrefix;
+    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
+    size_t      cchSkip   = 0;
+
+    if (   RTPATH_IS_SLASH(pwszWinPath[0])
+        && cwcWinPath >= 3
+        && RTPATH_IS_SLASH(pwszWinPath[1])
+        && !RTPATH_IS_SLASH(pwszWinPath[2]) )
+    {
+        if (   pwszWinPath[2] == '?'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+            return rtNtPathFromWinUtf16PassThru(pNtName, phRootDir, pwszWinPath, cwcWinPath);
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+        /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
+        if (   pwszWinPath[2] == '!'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+        {
+            pwszWinPath += 3;
+            cwcWinPath  -= 3;
+            if (cwcWinPath < _32K - 1)
+            {
+                PRTUTF16 pwszNtPath = RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+                if (pwszNtPath)
+                {
+                    memcpy(pwszNtPath, pwszWinPath, cwcWinPath * sizeof(RTUTF16));
+                    pwszNtPath[cwcWinPath] = '\0';
+                    pNtName->Buffer = pwszNtPath;
+                    pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+                    pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+                    *phRootDir = NULL;
+                    return VINF_SUCCESS;
+                }
+                rc = VERR_NO_UTF16_MEMORY;
+            }
+            else
+                rc = VERR_FILENAME_TOO_LONG;
+            return rc;
+        }
+#endif
+
+        if (   pwszWinPath[2] == '.'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+        {
+            /*
+             * Device path.
+             * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
+             */
+            cchSkip   = 4;
+        }
+        else
+        {
+            /* UNC */
+            pszPrefix = g_szPrefixUnc;
+            cchPrefix = sizeof(g_szPrefixUnc) - 1;
+            cchSkip   = 2;
+        }
+    }
+
+    /*
+     * Straighten out all .. and unnecessary . references and convert slashes.
+     */
+    char   szAbsPath[RTPATH_MAX];
+    char   szRelPath[RTPATH_MAX];
+    char  *pszRelPath = szRelPath;
+    size_t cchRelPath;
+    rc = RTUtf16ToUtf8Ex(pwszWinPath, cwcWinPath, &pszRelPath, sizeof(szRelPath), &cchRelPath);
+    if (RT_SUCCESS(rc))
+        rc = RTPathAbs(szRelPath, &szAbsPath[cchPrefix - cchSkip], sizeof(szAbsPath) - (cchPrefix - cchSkip));
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Add prefix and convert it to UTF16.
+         */
+        memcpy(szAbsPath, pszPrefix, cchPrefix);
+        return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szAbsPath);
+    }
+    return rc;
 }
 
@@ -181,8 +347,22 @@
  *                              rtNtPathToNative.
  */
-void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
+static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
 {
     RTUtf16Free(pNtName->Buffer);
     pNtName->Buffer = NULL;
+}
+
+
+/**
+ * Frees the native path and root handle.
+ *
+ * @param   pNtName             The NT path after a successful
+ *                              RTNtPathFromWinUtf16Ex call.
+ * @param   phRootDir           The root handle variable after a successfull
+ *                              RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
+{
+    rtNtPathFreeNative(pNtName, phRootDir);
 }
 
Index: /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 52943)
+++ /trunk/src/VBox/Runtime/r3/posix/path-posix.cpp	(revision 52944)
@@ -76,222 +76,4 @@
     LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
              pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>",  cchRealPath, rc));
-    return rc;
-}
-
-
-/**
- * Cleans up a path specifier a little bit.
- * This includes removing duplicate slashes, unnecessary single dots, and
- * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
- *
- * @returns Number of bytes in the clean path.
- * @param   pszPath     The path to cleanup.
- */
-static int fsCleanPath(char *pszPath)
-{
-    /*
-     * Change to '/' and remove duplicates.
-     */
-    char   *pszSrc = pszPath;
-    char   *pszTrg = pszPath;
-#ifdef HAVE_UNC
-    int     fUnc = 0;
-    if (    RTPATH_IS_SLASH(pszPath[0])
-        &&  RTPATH_IS_SLASH(pszPath[1]))
-    {   /* Skip first slash in a unc path. */
-        pszSrc++;
-        *pszTrg++ = '/';
-        fUnc = 1;
-    }
-#endif
-
-    for (;;)
-    {
-        char ch = *pszSrc++;
-        if (RTPATH_IS_SLASH(ch))
-        {
-            *pszTrg++ = '/';
-            for (;;)
-            {
-                do  ch = *pszSrc++;
-                while (RTPATH_IS_SLASH(ch));
-
-                /* Remove '/./' and '/.'. */
-                if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
-                    break;
-            }
-        }
-        *pszTrg = ch;
-        if (!ch)
-            break;
-        pszTrg++;
-    }
-
-    /*
-     * Remove trailing slash if the path may be pointing to a directory.
-     */
-    int cch = pszTrg - pszPath;
-    if (    cch > 1
-        &&  RTPATH_IS_SLASH(pszTrg[-1])
-#ifdef HAVE_DRIVE
-        &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
-#endif
-        &&  !RTPATH_IS_SLASH(pszTrg[-2]))
-        pszPath[--cch] = '\0';
-
-    return cch;
-}
-
-
-RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
-{
-    int rc;
-
-    /*
-     * Validation.
-     */
-    AssertPtr(pszAbsPath);
-    AssertPtr(pszPath);
-    if (RT_UNLIKELY(!*pszPath))
-        return VERR_INVALID_PARAMETER;
-
-    /*
-     * Make a clean working copy of the input.
-     */
-    size_t cchPath = strlen(pszPath);
-    if (cchPath > PATH_MAX)
-    {
-        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
-        return VERR_FILENAME_TOO_LONG;
-    }
-
-    char szTmpPath[PATH_MAX + 1];
-    memcpy(szTmpPath, pszPath, cchPath + 1);
-    size_t cchTmpPath = fsCleanPath(szTmpPath);
-
-    /*
-     * Handle "." specially (fsCleanPath does).
-     */
-    if (szTmpPath[0] == '.' && !szTmpPath[1])
-        return RTPathGetCurrent(pszAbsPath, cchAbsPath);
-
-    /*
-     * Do we have a root slash?
-     */
-    char *pszCur = szTmpPath;
-#ifdef HAVE_DRIVE
-    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
-        pszCur += 3;
-# ifdef HAVE_UNC
-    else if (pszCur[0] == '/' && pszCur[1] == '/')
-        pszCur += 2;
-# endif
-#else  /* !HAVE_DRIVE */
-    if (pszCur[0] == '/')
-        pszCur += 1;
-#endif /* !HAVE_DRIVE */
-    else
-    {
-        /*
-         * No, prepend the current directory to the relative path.
-         */
-        char szCurDir[RTPATH_MAX];
-        rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
-        AssertRCReturn(rc, rc);
-
-        size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
-        if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
-        {
-            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
-            return VERR_FILENAME_TOO_LONG;
-        }
-
-        memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
-        memcpy(szTmpPath, szCurDir, cchCurDir);
-        szTmpPath[cchCurDir] = '/';
-
-
-#ifdef HAVE_DRIVE
-        if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
-            pszCur += 3;
-# ifdef HAVE_UNC
-        else if (pszCur[0] == '/' && pszCur[1] == '/')
-            pszCur += 2;
-# endif
-#else
-        if (pszCur[0] == '/')
-            pszCur += 1;
-#endif
-        else
-            AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
-    }
-
-    char *pszTop = pszCur;
-
-    /*
-     * Get rid of double dot path components by evaluating them.
-     */
-    for (;;)
-    {
-        if (   pszCur[0] == '.'
-            && pszCur[1] == '.'
-            && (!pszCur[2] || pszCur[2] == '/'))
-        {
-            /* rewind to the previous component if any */
-            char *pszPrev = pszCur - 1;
-            if (pszPrev > pszTop)
-                while (*--pszPrev != '/')
-                    ;
-
-            AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
-            memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
-
-            pszCur = pszPrev;
-        }
-        else
-        {
-            /* advance to end of component. */
-            while (*pszCur && *pszCur != '/')
-                pszCur++;
-        }
-
-        if (!*pszCur)
-            break;
-
-        /* skip the slash */
-        ++pszCur;
-    }
-
-    if (pszCur < pszTop)
-    {
-        /*
-         * We overwrote the root slash with '\0', restore it.
-         */
-        *pszCur++ = '/';
-        *pszCur = '\0';
-    }
-    else if (pszCur > pszTop && pszCur[-1] == '/')
-    {
-        /*
-         * Extra trailing slash in a non-root path, remove it.
-         * (A bit questionable...)
-         */
-        *--pszCur = '\0';
-    }
-
-    /*
-     * Copy the result to the user buffer.
-     */
-    cchTmpPath = pszCur - szTmpPath;
-    if (cchTmpPath < cchAbsPath)
-    {
-        memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_BUFFER_OVERFLOW;
-
-    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
-             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
     return rc;
 }
Index: /trunk/src/VBox/Runtime/r3/win/path-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 52943)
+++ /trunk/src/VBox/Runtime/r3/win/path-win.cpp	(revision 52944)
@@ -89,5 +89,5 @@
 }
 
-
+#if 0
 /**
  * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
@@ -125,4 +125,5 @@
         if (RT_SUCCESS(rc))
         {
+# if 1 /** @todo This code is completely bonkers. */
             /*
              * Remove trailing slash if the path may be pointing to a directory.
@@ -134,4 +135,5 @@
                 &&  !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
                 pszAbsPath[cch - 1] = '\0';
+# endif
         }
     }
@@ -144,4 +146,5 @@
     return rc;
 }
+#endif
 
 
@@ -684,2 +687,19 @@
 }
 
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+    WCHAR wszInput[4];
+    wszInput[0] = chDrive;
+    wszInput[1] = ':';
+    wszInput[2] = '\0';
+
+    int rc;
+    RTUTF16 wszFullPath[RTPATH_MAX];
+    if (GetFullPathNameW(wszInput, RTPATH_MAX, wszFullPath, NULL))
+        rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
+    else
+        rc = RTErrConvertFromWin32(GetLastError());
+    return rc;
+}
+
Index: /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 52943)
+++ /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 52944)
@@ -315,5 +315,5 @@
     { "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" },
     { NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ },
-    { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server" },
+    { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" },
     { NULL, "\\\\", VINF_SUCCESS, "\\\\" },
     { NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ },
