Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 78047)
+++ /trunk/include/iprt/mangling.h	(revision 78048)
@@ -1597,4 +1597,5 @@
 # define RTPathAbsDup                                   RT_MANGLER(RTPathAbsDup)
 # define RTPathAbsEx                                    RT_MANGLER(RTPathAbsEx)
+# define RTPathAbsExEx                                  RT_MANGLER(RTPathAbsExEx)
 # define RTPathAbsExDup                                 RT_MANGLER(RTPathAbsExDup)
 # define RTPathAppDocs                                  RT_MANGLER(RTPathAppDocs)
Index: /trunk/include/iprt/path.h
===================================================================
--- /trunk/include/iprt/path.h	(revision 78047)
+++ /trunk/include/iprt/path.h	(revision 78048)
@@ -50,6 +50,12 @@
  */
 #if !defined(IPRT_INCLUDED_param_h) || defined(DOXYGEN_RUNNING)
-# define RTPATH_MAX         (4096 + 4)    /* (PATH_MAX + 1) on linux w/ some alignment */
+# define RTPATH_MAX                 (4096 + 4)    /* (PATH_MAX + 1) on linux w/ some alignment */
 #endif
+
+/**
+ * The absolute max host path length we are willing to support.
+ * @note Not really suitable for stack buffers.
+ */
+#define RTPATH_BIG_MAX              (_64K)
 
 /** @def RTPATH_TAG
@@ -61,5 +67,5 @@
  */
 #ifndef RTPATH_TAG
-# define RTPATH_TAG     (__FILE__)
+# define RTPATH_TAG                 (__FILE__)
 #endif
 
@@ -305,10 +311,10 @@
  * @param   pszPath         The path to resolve.
  * @param   pszAbsPath      Where to store the absolute path.
- * @param   cchAbsPath      Size of the buffer.
+ * @param   cbAbsPath       Size of the buffer.
  *
  * @note    Current implementation is buggy and will remove trailing slashes
  *          that would normally specify a directory.  Don't depend on this.
  */
-RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath);
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath);
 
 /**
@@ -335,10 +341,42 @@
  * @param   pszPath         The path to resolve.
  * @param   pszAbsPath      Where to store the absolute path.
- * @param   cchAbsPath      Size of the buffer.
+ * @param   cbAbsPath       Size of the buffer.
  *
  * @note    Current implementation is buggy and will remove trailing slashes
  *          that would normally specify a directory.  Don't depend on this.
  */
-RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath);
+RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cbAbsPath);
+
+/**
+ * Get the absolute path (no symlinks, no . or .. components), assuming the
+ * given base path as the current directory.
+ *
+ * The resulting path doesn't have to exist.
+ *
+ * @returns iprt status code.
+ * @param   pszBase         The base path to act like a current directory.
+ *                          When NULL, the actual cwd is used (i.e. the call
+ *                          is equivalent to RTPathAbs(pszPath, ...).
+ * @param   pszPath         The path to resolve.
+ * @param   fFlags          One of the RTPATH_STR_F_STYLE_XXX flags combined
+ *                          with any of the RTPATHABS_F_XXX ones.  Most
+ *                          users will pass RTPATH_STR_F_STYLE_HOST (0).
+ * @param   pszAbsPath      Where to store the absolute path.
+ * @param   pcbAbsPath      Hold the size of the buffer when called.  The return
+ *                          value is the string length on success, and the
+ *                          required (or slightly more in some case) buffer
+ *                          size, including terminator, on VERR_BUFFER_OVERFLOW
+ *                          failures.
+ */
+RTDECL(int) RTPathAbsExEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath);
+
+/** @name RTPATHABS_F_XXX - Flags for RTPathAbsEx.
+ * @note The RTPATH_F_STR_XXX style flags also applies.
+ * @{ */
+/** Treat specified base directory as a root that cannot be ascended beyond.  */
+#define RTPATHABS_F_STOP_AT_BASE    RT_BIT_32(16)
+/** Treat CWD as a root that cannot be ascended beyond.  */
+#define RTPATHABS_F_STOP_AT_CWD     RT_BIT_32(17)
+/** @} */
 
 /**
@@ -619,4 +657,7 @@
  * RTPATH_PROP_RELATIVE will always be set together with this.  */
 #define RTPATH_PROP_DOTDOT_REFS     UINT16_C(0x1000)
+/** Special UNC root.
+ * The share name is not sacred when this is set. */
+#define RTPATH_PROP_SPECIAL_UNC     UINT16_C(0x2000)
 
 
@@ -714,9 +755,11 @@
  *
  * @returns IPRT status code.
- * @retval  VERR_BUFFER_OVERFLOW if @a cbDstPath is less than or equal to
- *          RTPATHPARSED::cchPath.
+ * @retval  VERR_BUFFER_OVERFLOW if the destination buffer is too small.
+ *          The necessary length is @a pParsed->cchPath + 1 (updated).
  *
  * @param   pszSrcPath          The source path.
- * @param   pParsed             The parser output for @a pszSrcPath.
+ * @param   pParsed             The parser output for @a pszSrcPath.  Caller may
+ *                              eliminate elements by setting their length to
+ *                              zero.  The cchPath member is updated.
  * @param   fFlags              Combination of RTPATH_STR_F_STYLE_XXX.
  *                              Most users will pass 0.
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 78047)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 78048)
@@ -512,4 +512,5 @@
 	common/path/RTPathAbsEx.cpp \
 	common/path/RTPathAbsExDup.cpp \
+	common/path/RTPathAbsExEx.cpp \
 	common/path/RTPathAppend.cpp \
 	common/path/RTPathAppendEx.cpp \
@@ -1706,4 +1707,5 @@
 	common/path/RTPathAbsEx.cpp \
 	common/path/RTPathAbsExDup.cpp \
+	common/path/RTPathAbsExEx.cpp \
 	common/path/RTPathAppend.cpp \
 	common/path/RTPathAppendEx.cpp \
@@ -2720,4 +2722,5 @@
 	common/path/RTPathAbsEx.cpp \
 	common/path/RTPathAbsExDup.cpp \
+	common/path/RTPathAbsExEx.cpp \
 	common/path/RTPathAppend.cpp \
 	common/path/RTPathAppendEx.cpp \
Index: /trunk/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathAbsDup.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/common/path/RTPathAbsDup.cpp	(revision 78048)
@@ -31,5 +31,6 @@
 #include "internal/iprt.h"
 #include <iprt/path.h>
-#include <iprt/errcore.h>
+
+#include <iprt/err.h>
 #include <iprt/param.h>
 #include <iprt/string.h>
@@ -45,8 +46,27 @@
 RTDECL(char *) RTPathAbsDup(const char *pszPath)
 {
+    /* Try with a static buffer first. */
     char szPath[RTPATH_MAX];
     int rc = RTPathAbs(pszPath, szPath, sizeof(szPath));
     if (RT_SUCCESS(rc))
         return RTStrDup(szPath);
+
+    /* If it looks like we ran out of buffer space, double the size until
+       we reach 64 KB. */
+    if (rc == VERR_FILENAME_TOO_LONG || rc == VERR_BUFFER_OVERFLOW)
+    {
+        size_t cbBuf = RTPATH_MAX;
+        do
+        {
+            cbBuf *= 2;
+            char *pszBuf = RTStrAlloc(cbBuf);
+            if (!pszBuf)
+                break;
+            rc = RTPathAbs(pszPath, pszBuf, cbBuf);
+            if (RT_SUCCESS(rc))
+                return pszBuf;
+            RTStrFree(pszBuf);
+        } while (cbBuf <= _32K);
+    }
     return NULL;
 }
Index: /trunk/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathAbsEx.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/common/path/RTPathAbsEx.cpp	(revision 78048)
@@ -49,8 +49,9 @@
  * @param   pszPath         The path to resolve.
  * @param   pszAbsPath      Where to store the absolute path.
- * @param   cchAbsPath      Size of the buffer.
+ * @param   cbAbsPath       Size of the buffer.
  */
-RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
 {
+#if 1
     if (    pszBase
         &&  pszPath
@@ -58,5 +59,5 @@
        )
     {
-#if defined(RT_OS_WINDOWS)
+# if defined(RT_OS_WINDOWS)
         /* The format for very long paths is not supported. */
         if (    RTPATH_IS_SLASH(pszBase[0])
@@ -66,5 +67,5 @@
            )
             return VERR_INVALID_NAME;
-#endif
+# endif
 
         /** @todo there are a couple of things which isn't 100% correct, although the
@@ -96,9 +97,12 @@
             memcpy(&szTmpPath[cchBase + 1], pszPath, cchPath + 1);
         }
-        return RTPathAbs(szTmpPath, pszAbsPath, cchAbsPath);
+        return RTPathAbs(szTmpPath, pszAbsPath, cbAbsPath);
     }
 
     /* Fallback to the non *Ex version */
-    return RTPathAbs(pszPath, pszAbsPath, cchAbsPath);
+    return RTPathAbs(pszPath, pszAbsPath, cbAbsPath);
+#else
+    return RTPathAbsExEx(pszBase, pszPath, RTPATH_STR_F_STYLE_HOST, pszAbsPath, &cbAbsPath);
+#endif
 }
 
Index: /trunk/src/VBox/Runtime/common/path/RTPathAbsExEx.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathAbsExEx.cpp	(revision 78048)
+++ /trunk/src/VBox/Runtime/common/path/RTPathAbsExEx.cpp	(revision 78048)
@@ -0,0 +1,656 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathAbsExEx
+ */
+
+/*
+ * Copyright (C) 2019 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                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/err.h>
+#include <iprt/ctype.h>
+#include <iprt/mem.h>
+#include <iprt/param.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+
+/**
+ * Ensures that the drive letter is capitalized (prereq: RTPATH_PROP_VOLUME).
+ */
+DECLINLINE(void) rtPathAbsExExUpperCaseDriveLetter(char *pszAbsPath)
+{
+    AssertReturnVoid(pszAbsPath[1] == ':');
+    char ch = *pszAbsPath;
+    AssertReturnVoid(RT_C_IS_ALPHA(ch));
+    *pszAbsPath = RT_C_TO_UPPER(ch);
+}
+
+
+/**
+ * Common worker for relative paths.
+ *
+ * Uses RTPATHABS_F_STOP_AT_BASE for RTPATHABS_F_STOP_AT_CWD.
+ */
+static int rtPathAbsExExWithCwdOrBaseCommon(const char *pszBase, size_t cchBaseInPlace, PRTPATHPARSED pBaseParsed,
+                                            const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags,
+                                            char *pszAbsPath, size_t *pcbAbsPath)
+{
+    AssertReturn(pBaseParsed->cComps > 0, VERR_INVALID_PARAMETER);
+
+    /*
+     * Clean up the base path first if necessary.
+     *
+     * Note! UNC tries to preserve the first two elements in the base path,
+     *       unless it's a \\.\ or \\?\ prefix.
+     */
+    uint32_t const iBaseStop = (pBaseParsed->fProps & (RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC)) != RTPATH_PROP_UNC
+                            || pBaseParsed->cComps < 2 ? 0 : 1;
+    uint32_t       iBaseLast = iBaseStop;
+    if (pBaseParsed->fProps & (RTPATH_PROP_DOT_REFS | RTPATH_PROP_DOTDOT_REFS))
+    {
+        uint32_t const cComps = pBaseParsed->cComps;
+        uint32_t       i      = iBaseStop + 1;
+        while (i < cComps)
+        {
+            uint32_t const cchComp = pBaseParsed->aComps[i].cch;
+            if (   cchComp > 2
+                || pszPath[pBaseParsed->aComps[i].off] != '.'
+                || (cchComp == 2 && pszPath[pBaseParsed->aComps[i].off + 1] != '.') )
+                iBaseLast = i;
+            else
+            {
+                Assert(cchComp == 1 || cchComp == 2);
+                pBaseParsed->aComps[i].cch = 0;
+                if (cchComp == 2)
+                {
+                    while (iBaseLast > 0 && pBaseParsed->aComps[iBaseLast].cch == 0)
+                        iBaseLast--;
+                    if (iBaseLast > iBaseStop)
+                    {
+                        Assert(pBaseParsed->aComps[iBaseLast].cch != 0);
+                        pBaseParsed->aComps[iBaseLast].cch = 0;
+                        iBaseLast--;
+                    }
+                }
+            }
+            i++;
+        }
+        Assert(iBaseLast < cComps);
+    }
+    else
+        iBaseLast = pBaseParsed->cComps - 1;
+
+    /*
+     * Clean up the path next if needed.
+     */
+    int32_t iLast = -1; /* Is signed here! */
+    if (pParsed->fProps & (RTPATH_PROP_DOT_REFS | RTPATH_PROP_DOTDOT_REFS))
+    {
+        uint32_t const cComps = pParsed->cComps;
+        uint32_t       i      = 0;
+
+        /* If we have a volume specifier, take it from the base path. */
+        if (pParsed->fProps & RTPATH_PROP_VOLUME)
+            pParsed->aComps[i++].cch = 0;
+
+        while (i < cComps)
+        {
+            uint32_t const cchComp = pParsed->aComps[i].cch;
+            if (   cchComp > 2
+                || pszPath[pParsed->aComps[i].off] != '.'
+                || (cchComp == 2 && pszPath[pParsed->aComps[i].off + 1] != '.') )
+                iLast = i;
+            else
+            {
+                Assert(cchComp == 1 || cchComp == 2);
+                pParsed->aComps[i].cch = 0;
+                if (cchComp == 2)
+                {
+                    while (iLast >= 0 && pParsed->aComps[iLast].cch == 0)
+                        iLast--;
+                    if (iLast >= 0)
+                    {
+                        Assert(pParsed->aComps[iLast].cch != 0);
+                        pParsed->aComps[iLast].cch = 0;
+                        iLast--;
+                    }
+                    else if (   iBaseLast > iBaseStop
+                             && !(fFlags & RTPATHABS_F_STOP_AT_BASE))
+                    {
+                        while (iBaseLast > iBaseStop && pBaseParsed->aComps[iBaseLast].cch == 0)
+                            iBaseLast--;
+                        if (iBaseLast > iBaseStop)
+                        {
+                            Assert(pBaseParsed->aComps[iBaseLast].cch != 0);
+                            pBaseParsed->aComps[iBaseLast].cch = 0;
+                            iBaseLast--;
+                        }
+                    }
+                }
+            }
+            i++;
+        }
+        Assert(iLast < (int32_t)cComps);
+    }
+    else
+    {
+        /* If we have a volume specifier, take it from the base path. */
+        iLast = pParsed->cComps - 1;
+        if (pParsed->fProps & RTPATH_PROP_VOLUME)
+        {
+            pParsed->aComps[0].cch = 0;
+            if (iLast == 0)
+                iLast = -1;
+        }
+    }
+
+    /*
+     * Do we need a trailing slash in the base?
+     * If nothing is taken from pszPath, preserve its trailing slash,
+     * otherwise make sure there is a slash for joining the two.
+     */
+    Assert(!(pParsed->fProps & RTPATH_PROP_ROOT_SLASH));
+    if (pBaseParsed->cComps == 1)
+    {
+        AssertReturn(pBaseParsed->fProps & RTPATH_PROP_ROOT_SLASH, VERR_PATH_DOES_NOT_START_WITH_ROOT);
+        Assert(!(pBaseParsed->fProps & RTPATH_PROP_DIR_SLASH));
+    }
+    else
+    {
+        Assert(pBaseParsed->cComps > 1);
+        if (iLast >= 0 || (pParsed->fProps & RTPATH_PROP_DIR_SLASH))
+            pBaseParsed->fProps |= RTPATH_PROP_DIR_SLASH;
+        else
+            pBaseParsed->fProps &= ~RTPATH_PROP_DIR_SLASH;
+    }
+
+    /*
+     * Combine the two.  RTPathParsedReassemble can handle in place stuff, as
+     * long as the path doesn't grow.
+     */
+    int rc = RTPathParsedReassemble(pszBase, pBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
+    if (RT_SUCCESS(rc))
+    {
+        if (pBaseParsed->fProps & RTPATH_PROP_VOLUME)
+            rtPathAbsExExUpperCaseDriveLetter(pszAbsPath);
+
+        cchBaseInPlace = pBaseParsed->cchPath;
+        Assert(cchBaseInPlace == strlen(pszAbsPath));
+        if (iLast >= 0)
+        {
+            rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
+                                        &pszAbsPath[cchBaseInPlace], *pcbAbsPath - cchBaseInPlace);
+            *pcbAbsPath = cchBaseInPlace + pParsed->cchPath;
+            if (RT_SUCCESS(rc))
+                Assert(*pcbAbsPath == strlen(pszAbsPath));
+        }
+        else
+            *pcbAbsPath = cchBaseInPlace;
+    }
+    else if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        if (iLast >= 0)
+        {
+            RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
+            *pcbAbsPath = pBaseParsed->cchPath + pParsed->cchPath;
+        }
+        else
+            *pcbAbsPath = pBaseParsed->cchPath;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Handles the no-root-path scenario where we do CWD prefixing.
+ */
+static int rtPathAbsExExWithCwd(const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
+{
+    /*
+     * Get the current directory and place it in the output buffer.
+     */
+    size_t cchInPlace;
+    size_t cbCwd      = *pcbAbsPath;
+    char  *pszCwdFree = NULL;
+    char  *pszCwd     = pszAbsPath;
+    int    rc;
+    if (   !(fFlags & RTPATH_STR_F_STYLE_DOS)
+        || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
+        rc = RTPathGetCurrent(pszCwd, cbCwd);
+    else
+        rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
+    if (RT_SUCCESS(rc))
+        cchInPlace = strlen(pszCwd);
+    else if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        /* Allocate a big temporary buffer so we can return the correct length
+           (the destination buffer might even be big enough if pszPath includes
+           sufficient '..' entries). */
+        cchInPlace = 0;
+        cbCwd      = RT_MAX(cbCwd * 4, RTPATH_BIG_MAX);
+        pszCwdFree = pszCwd = (char *)RTMemTmpAlloc(cbCwd);
+        if (pszCwdFree)
+        {
+            if (   !(fFlags & RTPATH_STR_F_STYLE_DOS)
+                || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
+                rc = RTPathGetCurrent(pszCwd, cbCwd);
+            else
+                rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
+            if (RT_FAILURE(rc))
+            {
+                if (rc == VERR_BUFFER_OVERFLOW)
+                    rc = VERR_FILENAME_TOO_LONG;
+                RTMemTmpFree(pszCwdFree);
+                return rc;
+            }
+        }
+        else
+        {
+            *pcbAbsPath = cbCwd + 1 + pParsed->cchPath + 1;
+            return rc;
+        }
+    }
+    else
+        return rc;
+
+    /*
+     * Parse the path.
+     */
+    union
+    {
+        RTPATHPARSED Parsed;
+        uint8_t      abPadding[1024];
+    } uCwd;
+    PRTPATHPARSED pCwdParsedFree = NULL;
+    PRTPATHPARSED pCwdParsed     = &uCwd.Parsed;
+    size_t        cbCwdParsed    = sizeof(uCwd);
+    rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+    if (RT_SUCCESS(rc))
+    { /* likely */ }
+    else if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        cbCwdParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pCwdParsed->cComps + 2]);
+        pCwdParsedFree = pCwdParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbCwdParsed);
+        AssertReturnStmt(pCwdParsed, RTMemTmpFree(pszCwdFree), VERR_NO_TMP_MEMORY);
+        rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+        AssertRCReturnStmt(rc, RTMemTmpFree(pCwdParsedFree); RTMemTmpFree(pszCwdFree), rc);
+    }
+    else
+        AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
+
+    /*
+     * Join paths with the base-path code.
+     */
+    if (fFlags & RTPATHABS_F_STOP_AT_CWD)
+        fFlags |= RTPATHABS_F_STOP_AT_BASE;
+    else
+        fFlags &= ~RTPATHABS_F_STOP_AT_BASE;
+    rc = rtPathAbsExExWithCwdOrBaseCommon(pszCwd, cchInPlace, pCwdParsed, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+    if (pCwdParsedFree)
+        RTMemTmpFree(pCwdParsedFree);
+    if (pszCwdFree)
+        RTMemTmpFree(pszCwdFree);
+    return rc;
+}
+
+
+/**
+ * Handles the no-root-path scenario where we've got a base path.
+ */
+static int rtPathAbsExExWithBase(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags,
+                                 char *pszAbsPath, size_t *pcbAbsPath)
+{
+    /*
+     * Parse the base path.
+     */
+    union
+    {
+        RTPATHPARSED Parsed;
+        uint8_t      abPadding[1024];
+    } uBase;
+    PRTPATHPARSED pBaseParsedFree = NULL;
+    PRTPATHPARSED pBaseParsed     = &uBase.Parsed;
+    size_t        cbBaseParsed    = sizeof(uBase);
+    int rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+    if (RT_SUCCESS(rc))
+    { /* likely */ }
+    else if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
+        pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
+        AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
+        rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+        AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
+    }
+    else
+        AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
+
+    /*
+     * If the base path isn't absolute, we need to deal with that.
+     */
+    size_t cchInPlace = 0;
+    if ((pBaseParsed->fProps & (RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_DOT_REFS)) == RTPATH_PROP_ABSOLUTE)
+    { /* likely */ }
+    else
+    {
+        cchInPlace = *pcbAbsPath;
+        rc = RTPathAbsExEx(NULL, pszBase, fFlags, pszAbsPath, &cchInPlace);
+        if (RT_SUCCESS(rc))
+        {
+            Assert(strlen(pszAbsPath) == cchInPlace);
+            Assert(cchInPlace > 0);
+        }
+        else
+        {
+/** @todo Allocate temp buffer like we do for CWD? */
+            /* This is over generious, but don't want to put too much effort into it yet. */
+            if (rc == VERR_BUFFER_OVERFLOW)
+                *pcbAbsPath = cchInPlace + 1 + pParsed->cchPath + 1;
+            return rc;
+        }
+
+        /*
+         * Reparse it.
+         */
+        rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+        if (RT_SUCCESS(rc))
+        { /* likely */ }
+        else if (rc == VERR_BUFFER_OVERFLOW)
+        {
+            if (pBaseParsedFree)
+                RTMemTmpFree(pBaseParsedFree);
+            cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
+            pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
+            AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
+            rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+            AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
+        }
+        else
+            AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
+    }
+
+    /*
+     * Join paths with the CWD code.
+     */
+    rc = rtPathAbsExExWithCwdOrBaseCommon(cchInPlace ? pszAbsPath : pszBase, cchInPlace, pBaseParsed,
+                                          pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+    if (pBaseParsedFree)
+        RTMemTmpFree(pBaseParsedFree);
+    return rc;
+}
+
+
+/**
+ * Handles the RTPATH_PROP_ROOT_SLASH case.
+ */
+static int rtPathAbsExExRootSlash(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed,
+                                  uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
+{
+    /*
+     * Eliminate dot and dot-dot components.
+     * Note! aComp[0] is the root stuff and must never be dropped.
+     */
+    uint32_t const cComps = pParsed->cComps;
+    uint32_t const iStop  = (pParsed->fProps & (RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC)) != RTPATH_PROP_UNC
+                         || pParsed->cComps < 2 ? 0 : 1;
+    uint32_t       iLast  = iStop;
+    uint32_t       i      = iStop + 1;
+    while (i < cComps)
+    {
+        uint32_t const cchComp = pParsed->aComps[i].cch;
+        if (   cchComp > 2
+            || pszPath[pParsed->aComps[i].off] != '.'
+            || (cchComp == 2 && pszPath[pParsed->aComps[i].off + 1] != '.') )
+            iLast = i;
+        else
+        {
+            Assert(cchComp == 1 || cchComp == 2);
+            pParsed->aComps[i].cch = 0;
+            if (cchComp == 2)
+            {
+                while (iLast > iStop && pParsed->aComps[iLast].cch == 0)
+                    iLast--;
+                if (iLast > iStop)
+                {
+                    Assert(pParsed->aComps[iLast].cch > 0);
+                    pParsed->aComps[iLast].cch = 0;
+                    iLast--;
+                }
+            }
+        }
+        i++;
+    }
+
+    /*
+     * DOS-style: Do we need to supply a drive letter or UNC root?
+     */
+    size_t cchRootPrefix = 0;
+    if (   (fFlags & RTPATH_STR_F_STYLE_DOS)
+        && !(pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_UNC)) )
+    {
+        /* Use the drive/UNC from the base path if we have one and it has such a component: */
+        if (pszBase)
+        {
+            union
+            {
+                RTPATHPARSED    Parsed;
+                uint8_t         abPadding[sizeof(RTPATHPARSED) + sizeof(pParsed->aComps[0]) * 2];
+            } uBase;
+            int rc = RTPathParse(pszBase, &uBase.Parsed, sizeof(uBase), fFlags & RTPATH_STR_F_STYLE_MASK);
+            AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW, ("%Rrc - '%s'\n", rc, pszBase), rc);
+
+            if (uBase.Parsed.fProps & RTPATH_PROP_VOLUME)
+            {
+                /* get the drive letter. */
+                Assert(uBase.Parsed.aComps[0].cch == 2 || uBase.Parsed.aComps[0].cch == 3);
+                cchRootPrefix = RT_MIN(uBase.Parsed.aComps[0].cch, 2);
+                if (cchRootPrefix < *pcbAbsPath)
+                    memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
+                else
+                {
+                    int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
+                    Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
+
+                    *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
+                    return VERR_BUFFER_OVERFLOW;
+                }
+                rtPathAbsExExUpperCaseDriveLetter(pszAbsPath);
+            }
+            else if (uBase.Parsed.fProps & RTPATH_PROP_UNC)
+            {
+                /* Include the share if we've got one. */
+                cchRootPrefix = uBase.Parsed.aComps[0].cch;
+                if (uBase.Parsed.cComps >= 2 && !(uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
+                    cchRootPrefix += uBase.Parsed.aComps[1].cch;
+                else if (uBase.Parsed.fProps & RTPATH_PROP_ROOT_SLASH)
+                    cchRootPrefix--;
+                if (cchRootPrefix < *pcbAbsPath)
+                {
+                    if (uBase.Parsed.cComps < 2 || (uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
+                        memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
+                    else
+                    {
+                        size_t cchFirst = uBase.Parsed.aComps[0].cch;
+                        memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchFirst);
+                        memcpy(&pszAbsPath[cchFirst], &pszBase[uBase.Parsed.aComps[1].off], uBase.Parsed.aComps[1].cch);
+                    }
+                }
+                else
+                {
+                    int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
+                    Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
+
+                    *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
+                    return VERR_BUFFER_OVERFLOW;
+                }
+            }
+            else
+                pszBase = NULL;
+        }
+
+        /* Otherwise, query the current drive: */
+        if (!pszBase)
+        {
+            int rc = RTPathGetCurrentDrive(pszAbsPath, *pcbAbsPath);
+            if (RT_SUCCESS(rc))
+                cchRootPrefix = strlen(pszAbsPath);
+            else
+            {
+                if (rc == VERR_BUFFER_OVERFLOW)
+                {
+                    int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
+                    Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
+
+                    char *pszTmp = (char *)RTMemTmpAlloc(RTPATH_BIG_MAX);
+                    if (pszTmp)
+                    {
+                        rc = RTPathGetCurrentDrive(pszTmp, RTPATH_BIG_MAX);
+                        if (RT_SUCCESS(rc))
+                            *pcbAbsPath = strlen(pszTmp) + pParsed->cchPath + 1;
+                        else
+                            *pcbAbsPath = RT_MAX(*pcbAbsPath * 2, (size_t)RTPATH_BIG_MAX * 3 + pParsed->cchPath + 1);
+                        RTMemTmpFree(pszTmp);
+                    }
+                    else
+                        rc = VERR_NO_TMP_MEMORY;
+                }
+                return rc;
+            }
+        }
+    }
+
+    /*
+     * Reassemble the path and return.
+     */
+    int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
+                                    pszAbsPath + cchRootPrefix, *pcbAbsPath - cchRootPrefix);
+    *pcbAbsPath = cchRootPrefix + pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
+    return rc;
+}
+
+
+/**
+ * Handles the RTPATH_PROP_ABSOLUTE case.
+ */
+static int rtPathAbsExExAbsolute(const char *pszPath, PRTPATHPARSED pParsed,
+                                 uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
+{
+    if (pParsed->fProps & RTPATH_PROP_DOT_REFS)
+    {
+        uint32_t i = pParsed->cComps;
+        while (i-- > 0)
+            if (   pParsed->aComps[i].cch == 1
+                && pszPath[pParsed->aComps[i].off] == '.')
+                pParsed->aComps[i].cch = 0;
+    }
+    int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
+    *pcbAbsPath = pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
+    if (RT_SUCCESS(rc) && (pParsed->fProps & RTPATH_PROP_VOLUME))
+        rtPathAbsExExUpperCaseDriveLetter(pszAbsPath);
+    return rc;
+}
+
+
+RTDECL(int) RTPathAbsExEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
+{
+    /*
+     * Some input validation.
+     */
+    AssertPtr(pszPath);
+    AssertPtr(pszAbsPath);
+    AssertPtr(pcbAbsPath);
+    AssertReturn(*pszPath != '\0', VERR_PATH_ZERO_LENGTH);
+
+    AssertCompile(RTPATH_STR_F_STYLE_HOST == 0);
+    AssertReturn(   RTPATH_STR_F_IS_VALID(fFlags, RTPATHABS_F_STOP_AT_BASE | RTPATHABS_F_STOP_AT_CWD)
+                 && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
+    if ((fFlags & RTPATH_STR_F_STYLE_MASK) == RTPATH_STR_F_STYLE_HOST)
+        fFlags |= RTPATH_STYLE;
+
+    /*
+     * Parse the path we're to straigthen out.
+     */
+    union
+    {
+        RTPATHPARSED Parsed;
+        uint8_t      abPadding[1024];
+    } uBuf;
+    PRTPATHPARSED pParsedFree = NULL;
+    PRTPATHPARSED pParsed     = &uBuf.Parsed;
+    size_t        cbParsed    = sizeof(uBuf);
+    int rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+    if (RT_SUCCESS(rc))
+    { /* likely */ }
+    else if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        cbParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pParsed->cComps + 2]);
+        pParsedFree = pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
+        AssertReturn(pParsed, VERR_NO_TMP_MEMORY);
+        rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
+        AssertRCReturnStmt(rc, RTMemTmpFree(pParsedFree), rc);
+    }
+    else
+        AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
+
+    /*
+     * Check if the input is more or less perfect as it is.
+     */
+    if (pParsed->fProps & RTPATH_PROP_ABSOLUTE)
+        rc = rtPathAbsExExAbsolute(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+    /*
+     * What about relative but with a root slash.
+     */
+    else if (pParsed->fProps & RTPATH_PROP_ROOT_SLASH)
+        rc = rtPathAbsExExRootSlash(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+    /*
+     * Not exactly perfect.  No root slash.
+     *
+     * If we have a base path, we use it unless we're into drive letters and
+     * pszPath refers to a different drive letter.
+     */
+    else if (   pszBase
+             && (   !(fFlags & RTPATH_STR_F_STYLE_DOS)
+                 /** @todo add flag for skipping this and always using the base path? */
+                 || !(pParsed->fProps & RTPATH_PROP_VOLUME)
+                 || (   RT_C_IS_ALPHA(pszBase[0])
+                     && pszBase[1] == ':'
+                     && RT_C_TO_UPPER(pszBase[0]) == RT_C_TO_UPPER(pszPath[0])
+                    )
+                )
+            )
+        rc = rtPathAbsExExWithBase(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+    else
+        rc = rtPathAbsExExWithCwd(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
+
+    if (pParsedFree)
+        RTMemTmpFree(pParsedFree);
+    return rc;
+}
+
Index: /trunk/src/VBox/Runtime/common/path/RTPathParse.cpp.h
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathParse.cpp.h	(revision 78047)
+++ /trunk/src/VBox/Runtime/common/path/RTPathParse.cpp.h	(revision 78048)
@@ -59,27 +59,24 @@
         }
 #if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
-        else if (   RTPATH_IS_SLASH(pszPath[1])
-                 && !RTPATH_IS_SLASH(pszPath[2])
-                 && pszPath[2])
-        {
-            /* UNC - skip to the end of the potential namespace or computer name. */
+        else if (RTPATH_IS_SLASH(pszPath[1]))
+        {
+            /* UNC - there are exactly two prefix slashes followed by a namespace
+               or computer name, which can be empty on windows.  */
             offCur = 2;
             while (!RTPATH_IS_SLASH(pszPath[offCur]) && pszPath[offCur])
                 offCur++;
 
-            /* If there is another slash, we considered it a valid UNC path, if
-               not it's just a root path with an extra slash thrown in. */
+            /* Special fun for windows. */
+            fProps = RTPATH_PROP_UNC | RTPATH_PROP_ABSOLUTE;
+            if (   offCur == 3
+                && (pszPath[2] == '.' || pszPath[2] == '?'))
+                fProps |= RTPATH_PROP_SPECIAL_UNC;
+
             if (RTPATH_IS_SLASH(pszPath[offCur]))
             {
-                fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_UNC | RTPATH_PROP_ABSOLUTE;
-                offCur++;
-                cchPath = offCur;
-            }
-            else
-            {
-                fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE;
-                offCur = 1;
-                cchPath = 1;
-            }
+                fProps |= RTPATH_PROP_ROOT_SLASH;
+                offCur++;
+            }
+            cchPath = offCur;
         }
 #endif
Index: /trunk/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp	(revision 78048)
@@ -48,5 +48,38 @@
     AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
     AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER);
-    AssertReturn(cbDstPath > pParsed->cchPath, VERR_BUFFER_OVERFLOW);
+
+    /*
+     * Recalculate the length.
+     */
+    uint32_t const  cComps  = pParsed->cComps;
+    uint32_t        idxComp = 0;
+    uint32_t        cchPath = 0;
+    if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
+    {
+        cchPath = pParsed->aComps[0].cch;
+        idxComp++;
+    }
+    bool fNeedSlash = false;
+    while (idxComp < cComps)
+    {
+        uint32_t const cchComp = pParsed->aComps[idxComp].cch;
+        idxComp++;
+        if (cchComp > 0)
+        {
+            cchPath += cchComp + fNeedSlash;
+            fNeedSlash = true;
+        }
+    }
+    if ((pParsed->fProps & RTPATH_PROP_DIR_SLASH) && fNeedSlash)
+        cchPath += 1;
+    pParsed->cchPath = cchPath;
+    if (cbDstPath > cchPath)
+    { /* likely */ }
+    else
+    {
+        if (cbDstPath)
+            *pszDstPath = '\0';
+        return VERR_BUFFER_OVERFLOW;
+    }
 
     /*
@@ -74,20 +107,16 @@
     /*
      * Do the joining.
+     * Note! Using memmove here as we want to support pszSrcPath == pszDstPath.
      */
-    uint32_t const  cchOrgPath = pParsed->cchPath;
-    uint32_t        cchDstPath = 0;
-    uint32_t const  cComps     = pParsed->cComps;
-    uint32_t        idxComp    = 0;
-    char           *pszDst     = pszDstPath;
-    uint32_t        cchComp;
+    char *pszDst = pszDstPath;
+    idxComp      = 0;
+    fNeedSlash   = false;
 
     if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
     {
-        cchComp = pParsed->aComps[0].cch;
-        cchDstPath += cchComp;
-        AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
-        memcpy(pszDst, &pszSrcPath[pParsed->aComps[0].off], cchComp);
+        uint32_t cchComp = pParsed->aComps[0].cch;
+        memmove(pszDst, &pszSrcPath[pParsed->aComps[0].off], cchComp);
 
-        /* fix the slashes */
+        /* fix the slashes (harmless for unix style) */
         char chOtherSlash = chSlash == '\\' ? '/' : '\\';
         while (cchComp-- > 0)
@@ -102,18 +131,18 @@
     while (idxComp < cComps)
     {
-        cchComp = pParsed->aComps[idxComp].cch;
-        cchDstPath += cchComp;
-        AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
-        memcpy(pszDst, &pszSrcPath[pParsed->aComps[idxComp].off], cchComp);
-        pszDst += cchComp;
+        uint32_t const cchComp = pParsed->aComps[idxComp].cch;
+        if (cchComp > 0)
+        {
+            if (fNeedSlash)
+                *pszDst++ = chSlash;
+            fNeedSlash = true;
+            memmove(pszDst, &pszSrcPath[pParsed->aComps[idxComp].off], cchComp);
+            pszDst += cchComp;
+        }
         idxComp++;
-        if (idxComp != cComps || (pParsed->fProps & RTPATH_PROP_DIR_SLASH))
-        {
-            cchDstPath++;
-            AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
-            *pszDst++ = chSlash;
-        }
     }
 
+    if ((pParsed->fProps & RTPATH_PROP_DIR_SLASH) && fNeedSlash)
+        *pszDst++ = chSlash;
     *pszDst = '\0';
 
Index: /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp	(revision 78048)
@@ -40,4 +40,5 @@
 #include "internal/fs.h"
 
+#if 1
 
 static char *rtPathSkipRootSpec(char *pszCur)
@@ -145,5 +146,5 @@
 
 
-RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
 {
     int rc;
@@ -163,5 +164,5 @@
     if (cchPath >= RTPATH_MAX)
     {
-        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
+        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cbAbsPath, VERR_FILENAME_TOO_LONG));
         return VERR_FILENAME_TOO_LONG;
     }
@@ -179,5 +180,5 @@
             || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
         {
-            rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
+            rc = RTPathGetCurrent(pszAbsPath, cbAbsPath);
             if (RT_SUCCESS(rc))
             {
@@ -191,5 +192,5 @@
                     && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
                 {
-                    if (cch + 1 < cchAbsPath)
+                    if (cch + 1 < cbAbsPath)
                     {
                         pszAbsPath[cch++] = RTPATH_SLASH;
@@ -274,5 +275,5 @@
         if (RT_FAILURE(rc))
         {
-            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
+            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cbAbsPath, rc));
             return rc;
         }
@@ -360,5 +361,5 @@
      * Copy the result to the user buffer.
      */
-    if (cchTmpPath < cchAbsPath)
+    if (cchTmpPath < cbAbsPath)
     {
         memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
@@ -369,6 +370,15 @@
 
     LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
-             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
+             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cbAbsPath, rc));
     return rc;
 }
 
+#else
+
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
+{
+    return RTPathAbsExEx(NULL, pszPath, RTPATH_STR_F_STYLE_HOST, pszAbsPath, &cbAbsPath);
+}
+
+#endif
+
Index: /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp	(revision 78048)
@@ -35,4 +35,5 @@
 #include <iprt/ctype.h>
 #include <iprt/err.h>
+#include <iprt/mem.h>
 #include <iprt/string.h>
 #include "internal/path.h"
@@ -45,5 +46,17 @@
      * Query the current directroy and extract the wanted information from it.
      */
-    int rc = RTPathGetCurrent(pszPath, cbPath);
+    char *pszPathFree = NULL;
+    char *pszCwd = pszPath;
+    int rc = RTPathGetCurrent(pszCwd, cbPath);
+    if (RT_SUCCESS(rc))
+    { /* likely */ }
+    else if (rc != VERR_BUFFER_OVERFLOW)
+        return rc;
+    else
+    {
+        pszPathFree = pszCwd = (char *)RTMemTmpAlloc(RTPATH_BIG_MAX);
+        AssertReturn(pszPathFree, VERR_NO_TMP_MEMORY);
+        rc = RTPathGetCurrent(pszCwd, RTPATH_BIG_MAX);
+    }
     if (RT_SUCCESS(rc))
     {
@@ -51,33 +64,29 @@
          * Drive letter? Chop off at root slash.
          */
-        if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
-        {
-            pszPath[2] = '\0';
-            return rc;
-        }
-
+        if (pszCwd[0] && RTPATH_IS_VOLSEP(pszCwd[1]))
+            pszCwd[2] = '\0';
         /*
          * UNC? Chop off after share.
          */
-        if (   RTPATH_IS_SLASH(pszPath[0])
-            && RTPATH_IS_SLASH(pszPath[1])
-            && !RTPATH_IS_SLASH(pszPath[2])
-            && pszPath[2])
+        else if (   RTPATH_IS_SLASH(pszCwd[0])
+                 && RTPATH_IS_SLASH(pszCwd[1])
+                 && !RTPATH_IS_SLASH(pszCwd[2])
+                 && pszCwd[2])
         {
             /* Work thru the server name. */
             size_t off = 3;
-            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+            while (!RTPATH_IS_SLASH(pszCwd[off]) && pszCwd[off])
                 off++;
             size_t offServerSlash = off;
 
             /* Is there a share name? */
-            if (RTPATH_IS_SLASH(pszPath[off]))
+            if (RTPATH_IS_SLASH(pszCwd[off]))
             {
-                while (RTPATH_IS_SLASH(pszPath[off]))
+                while (RTPATH_IS_SLASH(pszCwd[off]))
                     off++;
-                if (pszPath[off])
+                if (pszCwd[off])
                 {
                     /* Work thru the share name. */
-                    while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                    while (!RTPATH_IS_SLASH(pszCwd[off]) && pszCwd[off])
                         off++;
                 }
@@ -86,6 +95,14 @@
                     off = offServerSlash;
             }
+            pszCwd[off] = '\0';
         }
-        return VERR_INTERNAL_ERROR_4;
+        else
+            rc = VERR_INTERNAL_ERROR_4;
+    }
+    if (pszPathFree)
+    {
+        if (RT_SUCCESS(rc))
+            rc = RTStrCopy(pszPath, cbPath, pszCwd);
+        RTMemTmpFree(pszPathFree);
     }
     return rc;
Index: /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 78047)
+++ /trunk/src/VBox/Runtime/testcase/tstRTPath.cpp	(revision 78048)
@@ -57,8 +57,8 @@
         { 2, 12,  8,  "C:Config.sys",     RTPATH_PROP_VOLUME | RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX,                                RTPATH_STR_F_STYLE_DOS },
         { 1, 10,  6,  "Config.sys",       RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_SUFFIX,                                                     RTPATH_STR_F_STYLE_DOS },
-        { 1,  4,  4,  "//./",             RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE,                                                      RTPATH_STR_F_STYLE_DOS },
-        { 2,  5,  5,  "//./f",            RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME,                               RTPATH_STR_F_STYLE_DOS },
-        { 2,  5,  6,  "//.//f",           RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_EXTRA_SLASHES,   RTPATH_STR_F_STYLE_DOS },
-        { 3,  7,  7,  "//././f",          RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOT_REFS,        RTPATH_STR_F_STYLE_DOS },
+        { 1,  4,  4,  "//./",             RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE,                                                      RTPATH_STR_F_STYLE_DOS },
+        { 2,  5,  5,  "//./f",            RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME,                               RTPATH_STR_F_STYLE_DOS },
+        { 2,  5,  6,  "//.//f",           RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_EXTRA_SLASHES,   RTPATH_STR_F_STYLE_DOS },
+        { 3,  7,  7,  "//././f",          RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOT_REFS,        RTPATH_STR_F_STYLE_DOS },
         { 3,  8,  8,  "//.././f",         RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOT_REFS,        RTPATH_STR_F_STYLE_DOS },
         { 3,  9,  9,  "//../../f",        RTPATH_PROP_UNC | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE | RTPATH_PROP_FILENAME | RTPATH_PROP_DOTDOT_REFS,     RTPATH_STR_F_STYLE_DOS },
@@ -398,4 +398,160 @@
         }
     }
+
+    /*
+     * RTPathAbsExEx - will replace RTPathAbsEx shortly.
+     */
+    RTTestSub(hTest, "RTPathAbsExEx");
+    static const struct
+    {
+        uint32_t    fFlags;
+        const char *pcszInputBase;
+        const char *pcszInputPath;
+        int rc;
+        const char *pcszOutput;
+    }
+    s_aRTPathAbsExExTests[] =
+    {
+        { RTPATH_STR_F_STYLE_HOST,  NULL, "", VERR_PATH_ZERO_LENGTH, NULL },
+        { RTPATH_STR_F_STYLE_HOST,  NULL, ".", VINF_SUCCESS, "%p" },
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\", VINF_SUCCESS, "%d\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\..", VINF_SUCCESS, "%d\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "/absolute/..", VINF_SUCCESS, "%d\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "/absolute\\\\../..", VINF_SUCCESS, "%d\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "/absolute//../path\\", VINF_SUCCESS, "%d\\path\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "/absolute/../../path", VINF_SUCCESS, "%d\\path" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p\\dir\\file.txt" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\data\\", VINF_SUCCESS, "%d\\data\\" },
+        { RTPATH_STR_F_STYLE_DOS,   "relative_base/dir\\", "\\from_root", VINF_SUCCESS, "%d\\from_root" },
+        { RTPATH_STR_F_STYLE_DOS,   "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p\\relative_base\\dir\\relative_also" },
+#else
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, ".", VINF_SUCCESS, "%p" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "relative/../dir/./././file.txt", VINF_SUCCESS, "%p/dir/file.txt" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p/dir\\.\\.\\.\\file.txt" },  /* linux-specific */
+        { RTPATH_STR_F_STYLE_UNIX,  "relative_base/dir/", "/from_root", VINF_SUCCESS, "/from_root" },
+        { RTPATH_STR_F_STYLE_UNIX,  "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p/relative_base/dir/relative_also" },
+#endif
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/", VINF_SUCCESS, "/" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/..", VINF_SUCCESS, "/" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/absolute/..", VINF_SUCCESS, "/" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/absolute\\\\../..", VINF_SUCCESS, "/" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/absolute//../path/", VINF_SUCCESS, "/path/" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/absolute/../../path", VINF_SUCCESS, "/path" },
+        { RTPATH_STR_F_STYLE_UNIX,  NULL, "/data/", VINF_SUCCESS, "/data/" },
+#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "C:\\", VINF_SUCCESS, "C:\\" },
+        { RTPATH_STR_F_STYLE_DOS,   "C:\\", "..", VINF_SUCCESS, "C:\\" },
+        { RTPATH_STR_F_STYLE_DOS,   "C:\\temp", "..", VINF_SUCCESS, "C:\\" },
+        { RTPATH_STR_F_STYLE_DOS,   "C:\\VirtualBox/Machines", "..\\VirtualBox.xml", VINF_SUCCESS, "C:\\VirtualBox\\VirtualBox.xml" },
+        { RTPATH_STR_F_STYLE_DOS,   "C:\\MustDie", "\\from_root/dir/..", VINF_SUCCESS, "C:\\from_root" },
+        { RTPATH_STR_F_STYLE_DOS,   "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\", VINF_SUCCESS, "\\\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ },
+        { RTPATH_STR_F_STYLE_DOS,   "\\\\server\\share_as_base", "/from_root", VINF_SUCCESS, "\\\\server\\share_as_base\\from_root" },
+        { RTPATH_STR_F_STYLE_DOS,   "\\\\just_server", "/from_root", VINF_SUCCESS, "\\\\just_server\\from_root" },
+        { RTPATH_STR_F_STYLE_DOS,   "\\\\server\\share_as_base", "relative\\data", VINF_SUCCESS, "\\\\server\\share_as_base\\relative\\data" },
+        { RTPATH_STR_F_STYLE_DOS,   "base", "\\\\?\\UNC\\relative/edwef/..", VINF_SUCCESS, "\\\\?\\UNC\\relative" },
+        { RTPATH_STR_F_STYLE_DOS,   "\\\\?\\UNC\\base", "/from_root", VINF_SUCCESS, "\\\\?\\from_root" },
+        { RTPATH_STR_F_STYLE_DOS,   "\\\\?\\UNC\\base", "./..", VINF_SUCCESS, "\\\\?\\UNC" },
+        { RTPATH_STR_F_STYLE_DOS | RTPATHABS_F_STOP_AT_BASE, "\\\\?\\UNC\\base", "./..", VINF_SUCCESS, "\\\\?\\UNC\\base" },
+        { RTPATH_STR_F_STYLE_DOS | RTPATHABS_F_STOP_AT_BASE, "\\\\?\\UNC\\base", "/..", VINF_SUCCESS, "\\\\?\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\.\\asdf\\..", VINF_SUCCESS, "\\\\.\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\?\\asdf\\..", VINF_SUCCESS, "\\\\?\\" },
+        { RTPATH_STR_F_STYLE_DOS,   NULL, "\\\\x\\asdf\\..", VINF_SUCCESS, "\\\\x\\asdf" },
+#else
+        { RTPATH_STR_F_STYLE_UNIX,  "\\temp", "\\data", VINF_SUCCESS, "%p/\\temp/\\data" },
+#endif
+        { RTPATH_STR_F_STYLE_UNIX,  "/VirtualBox/Machines", "../VirtualBox.xml", VINF_SUCCESS, "/VirtualBox/VirtualBox.xml" },
+        { RTPATH_STR_F_STYLE_UNIX,  "/MustDie", "/from_root/dir/..", VINF_SUCCESS, "/from_root" },
+        { RTPATH_STR_F_STYLE_UNIX,  "/temp", "..", VINF_SUCCESS, "/" },
+    };
+    for (unsigned i = 0; i < RT_ELEMENTS(s_aRTPathAbsExExTests); ++ i)
+    {
+        if (RT_FAILURE(s_aRTPathAbsExExTests[i].rc))
+            RTTestDisableAssertions(hTest);
+
+        size_t cbAbsPath = sizeof(szPath);
+        rc = RTPathAbsExEx(s_aRTPathAbsExExTests[i].pcszInputBase,
+                           s_aRTPathAbsExExTests[i].pcszInputPath,
+                           s_aRTPathAbsExExTests[i].fFlags,
+                           szPath, &cbAbsPath);
+
+        if (RT_FAILURE(s_aRTPathAbsExExTests[i].rc))
+            RTTestRestoreAssertions(hTest);
+
+        if (rc != s_aRTPathAbsExExTests[i].rc)
+        {
+            RTTestIFailed("#%u: unexpected result code!\n"
+                          "        flags: %#x\n"
+                          "   input base: '%s'\n"
+                          "   input path: '%s'\n"
+                          "       output: '%s'\n"
+                          "           rc: %Rrc\n"
+                          "  expected rc: %Rrc",
+                          i,
+                          s_aRTPathAbsExExTests[i].fFlags,
+                          s_aRTPathAbsExExTests[i].pcszInputBase,
+                          s_aRTPathAbsExExTests[i].pcszInputPath,
+                          szPath, rc,
+                          s_aRTPathAbsExExTests[i].rc);
+            continue;
+        }
+
+        char szTmp[RTPATH_MAX];
+        char *pszExpected = NULL;
+        if (s_aRTPathAbsExExTests[i].pcszOutput != NULL)
+        {
+            if (s_aRTPathAbsExExTests[i].pcszOutput[0] == '%')
+            {
+                RTTESTI_CHECK_RC(rc = RTPathGetCurrent(szTmp, sizeof(szTmp)), VINF_SUCCESS);
+                if (RT_FAILURE(rc))
+                    break;
+
+                pszExpected = szTmp;
+
+                if (s_aRTPathAbsExExTests[i].pcszOutput[1] == 'p')
+                {
+                    cch = strlen(szTmp);
+                    if (cch + strlen(s_aRTPathAbsExExTests[i].pcszOutput) - 2 <= sizeof(szTmp))
+                        strcpy(szTmp + cch, s_aRTPathAbsExExTests[i].pcszOutput + 2);
+                }
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+                else if (s_aRTPathAbsExExTests[i].pcszOutput[1] == 'd')
+                {
+                    if (2 + strlen(s_aRTPathAbsExExTests[i].pcszOutput) - 2 <= sizeof(szTmp))
+                        strcpy(szTmp + 2, s_aRTPathAbsExExTests[i].pcszOutput + 2);
+                }
+#endif
+            }
+            else
+            {
+                strcpy(szTmp, s_aRTPathAbsExExTests[i].pcszOutput);
+                pszExpected = szTmp;
+            }
+
+            if (   strcmp(szPath, pszExpected)
+                || strlen(szPath) != cbAbsPath)
+            {
+                RTTestIFailed("#%u: Unexpected result\n"
+                              "        flags: %#x\n"
+                              "   input base: '%s'\n"
+                              "   input path: '%s'\n"
+                              "       output: '%s'\n"
+                              "     expected: '%s' ('%s')\n"
+                              "    cchResult: %#x, actual %#x",
+                              i,
+                              s_aRTPathAbsExExTests[i].fFlags,
+                              s_aRTPathAbsExExTests[i].pcszInputBase,
+                              s_aRTPathAbsExExTests[i].pcszInputPath,
+                              szPath,
+                              pszExpected, s_aRTPathAbsExExTests[i].pcszOutput,
+                              cbAbsPath, strlen(szPath));
+            }
+        }
+    }
+
 
     /*
