Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 60480)
+++ /trunk/include/iprt/mangling.h	(revision 60481)
@@ -2194,4 +2194,5 @@
 # define RTUriIsSchemeMatch                             RT_MANGLER(RTUriIsSchemeMatch)
 # define RTUtf16AllocTag                                RT_MANGLER(RTUtf16AllocTag)
+# define RTUtf16ReallocTag                              RT_MANGLER(RTUtf16ReallocTag)
 # define RTUtf16CalcLatin1Len                           RT_MANGLER(RTUtf16CalcLatin1Len)
 # define RTUtf16CalcLatin1LenEx                         RT_MANGLER(RTUtf16CalcLatin1LenEx)
@@ -2200,4 +2201,5 @@
 # define RTUtf16Cmp                                     RT_MANGLER(RTUtf16Cmp)
 # define RTUtf16CmpAscii                                RT_MANGLER(RTUtf16CmpAscii)
+# define RTUtf16CmpUtf8                                 RT_MANGLER(RTUtf16CmpUtf8)
 # define RTUtf16DupExTag                                RT_MANGLER(RTUtf16DupExTag)
 # define RTUtf16DupTag                                  RT_MANGLER(RTUtf16DupTag)
@@ -2206,4 +2208,5 @@
 # define RTUtf16GetCpInternal                           RT_MANGLER(RTUtf16GetCpInternal)
 # define RTUtf16ICmp                                    RT_MANGLER(RTUtf16ICmp)
+# define RTUtf16ICmpUtf8                                RT_MANGLER(RTUtf16ICmpUtf8)
 # define RTUtf16IsValidEncoding                         RT_MANGLER(RTUtf16IsValidEncoding)
 # define RTUtf16Len                                     RT_MANGLER(RTUtf16Len)
Index: /trunk/include/iprt/utf16.h
===================================================================
--- /trunk/include/iprt/utf16.h	(revision 60480)
+++ /trunk/include/iprt/utf16.h	(revision 60481)
@@ -82,4 +82,76 @@
 RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag);
 
+/**
+ * Reallocates the specified UTF-16 string (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 VINF_SUCCESS.
+ * @retval  VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a
+ *          *ppwsz remains unchanged.
+ *
+ * @param   ppwsz               Pointer to the string variable containing the
+ *                              input and output string.
+ *
+ *                              When not freeing the string, the result will
+ *                              always have the last RTUTF16 set to the
+ *                              terminator character so that when used for
+ *                              string truncation the result will be a valid
+ *                              C-style string (your job to keep it a valid
+ *                              UTF-16 string).
+ *
+ *                              When the input string is NULL and we're supposed
+ *                              to reallocate, the returned string will also
+ *                              have the first RTUTF16 set to the terminator
+ *                              char so it will be a valid C-style string.
+ *
+ * @param   cbNew               When @a cbNew is zero, we'll behave like
+ *                              RTUtf16Free and @a *ppwsz will be set to NULL.
+ *
+ *                              When not zero, this will be rounded up to a
+ *                              multiple of two, and used as the new size of the
+ *                              memory backing the string, i.e. it includes the
+ *                              terminator (RTUTF16) char.
+ */
+#define RTUtf16Realloc(ppwsz, cb)       RTUtf16ReallocTag((ppwsz), (cb), RTSTR_TAG)
+
+/**
+ * Reallocates the specified UTF-16 string (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 VINF_SUCCESS.
+ * @retval  VERR_NO_UTF16_MEMORY if we failed to reallocate the string, @a
+ *          *ppwsz remains unchanged.
+ *
+ * @param   ppwsz               Pointer to the string variable containing the
+ *                              input and output string.
+ *
+ *                              When not freeing the string, the result will
+ *                              always have the last RTUTF16 set to the
+ *                              terminator character so that when used for
+ *                              string truncation the result will be a valid
+ *                              C-style string (your job to keep it a valid
+ *                              UTF-16 string).
+ *
+ *                              When the input string is NULL and we're supposed
+ *                              to reallocate, the returned string will also
+ *                              have the first RTUTF16 set to the terminator
+ *                              char so it will be a valid C-style string.
+ *
+ * @param   cbNew               When @a cbNew is zero, we'll behave like
+ *                              RTUtf16Free and @a *ppwsz will be set to NULL.
+ *
+ *                              When not zero, this will be rounded up to a
+ *                              multiple of two, and used as the new size of the
+ *                              memory backing the string, i.e. it includes the
+ *                              terminator (RTUTF16) char.
+ * @param   pszTag              Allocation tag used for statistics and such.
+ */
+RTDECL(int) RTUtf16ReallocTag(PRTUTF16 *ppwsz, size_t cbNew, const char *pszTag);
 
 /**
@@ -333,4 +405,17 @@
 
 /**
+ * Performs a case sensitive string compare between an UTF-16 string and a UTF-8
+ * string.
+ *
+ * @returns < 0 if the first string less than the second string.s
+ * @returns 0 if the first string identical to the second string.
+ * @returns > 0 if the first string greater than the second string.
+ * @param   pwsz1       First UTF-16 string. Null is allowed.
+ * @param   psz2        Second string, UTF-8. Null is allowed.
+ * @remarks NULL and empty strings are treated equally.
+ */
+RTDECL(int) RTUtf16CmpUtf8(PCRTUTF16 pwsz1, const char *psz2);
+
+/**
  * Performs a case insensitive string compare between two UTF-16 strings.
  *
@@ -346,4 +431,17 @@
  */
 RTDECL(int) RTUtf16ICmp(PCRTUTF16 pwsz1, PCRTUTF16 pwsz2);
+
+/**
+ * Performs a case insensitive string compare between an UTF-16 string and a
+ * UTF-8 string.
+ *
+ * @returns < 0 if the first string less than the second string.s
+ * @returns 0 if the first string identical to the second string.
+ * @returns > 0 if the first string greater than the second string.
+ * @param   pwsz1       First UTF-16 string. Null is allowed.
+ * @param   psz2        Second string, UTF-8. Null is allowed.
+ * @remarks NULL and empty strings are treated equally.
+ */
+RTDECL(int) RTUtf16ICmpUtf8(PCRTUTF16 pwsz1, const char *psz2);
 
 /**
Index: /trunk/src/VBox/Runtime/common/string/utf-16-case.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/utf-16-case.cpp	(revision 60480)
+++ /trunk/src/VBox/Runtime/common/string/utf-16-case.cpp	(revision 60481)
@@ -106,4 +106,43 @@
 
 
+RTDECL(int) RTUtf16ICmpUtf8(PCRTUTF16 pwsz1, const char *psz2)
+{
+    /*
+     * NULL and empty strings are all the same.
+     */
+    if (!pwsz1)
+        return !psz2 || !*psz2 ? 0 : -1;
+    if (!psz2)
+        return !*pwsz1         ? 0 :  1;
+
+    /*
+     * Compare with a UTF-8 string by enumerating them char by char.
+     */
+    for (;;)
+    {
+        RTUNICP uc1;
+        int rc = RTUtf16GetCpEx(&pwsz1, &uc1);
+        AssertRCReturn(rc, 1);
+
+        RTUNICP uc2;
+        rc = RTStrGetCpEx(&psz2, &uc2);
+        AssertRCReturn(rc, -1);
+        if (uc1 == uc2)
+        {
+            if (uc1)
+                continue;
+            return 0;
+        }
+
+        if (RTUniCpToUpper(uc1) == RTUniCpToUpper(uc2))
+            continue;
+        if (RTUniCpToLower(uc1) == RTUniCpToLower(uc2))
+            continue;
+        return uc1 < uc2 ? -1 : 1;
+    }
+}
+RT_EXPORT_SYMBOL(RTUtf16CmpIUtf8);
+
+
 RTDECL(PRTUTF16) RTUtf16ToLower(PRTUTF16 pwsz)
 {
Index: /trunk/src/VBox/Runtime/common/string/utf-16.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 60480)
+++ /trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 60481)
@@ -114,4 +114,35 @@
 
 
+RTDECL(int) RTUtf16ReallocTag(PRTUTF16 *ppwsz, size_t cbNew, const char *pszTag)
+{
+    PRTUTF16 pwszOld = *ppwsz;
+    cbNew = RT_ALIGN_Z(cbNew, sizeof(RTUTF16));
+    if (!cbNew)
+    {
+        RTMemFree(pwszOld);
+        *ppwsz = NULL;
+    }
+    else if (pwszOld)
+    {
+        PRTUTF16 pwszNew = (PRTUTF16)RTMemReallocTag(pwszOld, cbNew, pszTag);
+        if (!pwszNew)
+            return VERR_NO_STR_MEMORY;
+        pwszNew[cbNew / sizeof(RTUTF16) - 1] = '\0';
+        *ppwsz = pwszNew;
+    }
+    else
+    {
+        PRTUTF16 pwszNew = (PRTUTF16)RTMemAllocTag(cbNew, pszTag);
+        if (!pwszNew)
+            return VERR_NO_UTF16_MEMORY;
+        pwszNew[0] = '\0';
+        pwszNew[cbNew / sizeof(RTUTF16) - 1] = '\0';
+        *ppwsz = pwszNew;
+    }
+    return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTUtf16ReallocTag);
+
+
 RTDECL(void)  RTUtf16Free(PRTUTF16 pwszString)
 {
@@ -183,4 +214,38 @@
 }
 RT_EXPORT_SYMBOL(RTUtf16Cmp);
+
+
+RTDECL(int) RTUtf16CmpUtf8(PCRTUTF16 pwsz1, const char *psz2)
+{
+    /*
+     * NULL and empty strings are all the same.
+     */
+    if (!pwsz1)
+        return !psz2 || !*psz2 ? 0 : -1;
+    if (!psz2)
+        return !*pwsz1         ? 0 :  1;
+
+    /*
+     * Compare with a UTF-8 string by enumerating them char by char.
+     */
+    for (;;)
+    {
+        RTUNICP uc1;
+        int rc = RTUtf16GetCpEx(&pwsz1, &uc1);
+        AssertRCReturn(rc, 1);
+
+        RTUNICP uc2;
+        rc = RTStrGetCpEx(&psz2, &uc2);
+        AssertRCReturn(rc, -1);
+        if (uc1 == uc2)
+        {
+            if (uc1)
+                continue;
+            return 0;
+        }
+        return uc1 < uc2 ? -1 : 1;
+    }
+}
+RT_EXPORT_SYMBOL(RTUtf16CmpUtf8);
 
 
Index: /trunk/src/VBox/Runtime/nt/RTNtPathExpand8dot3Path.cpp
===================================================================
--- /trunk/src/VBox/Runtime/nt/RTNtPathExpand8dot3Path.cpp	(revision 60480)
+++ /trunk/src/VBox/Runtime/nt/RTNtPathExpand8dot3Path.cpp	(revision 60481)
@@ -158,5 +158,5 @@
                     pUniStr->Length += (USHORT)(cwcNameNew * sizeof(WCHAR));
                     pwszFixEnd      -= cwcNameOld;
-                    pwszFixEnd      -= cwcNameNew;
+                    pwszFixEnd      += cwcNameNew;
                     memcpy(pwszFix, &puBuf->Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
                 }
Index: /trunk/src/VBox/Runtime/nt/RTNtPathFindPossible8dot3Name.cpp
===================================================================
--- /trunk/src/VBox/Runtime/nt/RTNtPathFindPossible8dot3Name.cpp	(revision 60481)
+++ /trunk/src/VBox/Runtime/nt/RTNtPathFindPossible8dot3Name.cpp	(revision 60481)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * IPRT - Native NT, RTNtPathFindPossible8dot3Name.
+ */
+
+/*
+ * Copyright (C) 2006-2016 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_FS
+#ifdef IN_SUP_HARDENED_R3
+# include <iprt/nt/nt-and-windows.h>
+#else
+# include <iprt/nt/nt.h>
+#endif
+
+
+
+/**
+ * Checks whether the path could be containing alternative 8.3 names generated
+ * by NTFS, FAT, or other similar file systems.
+ *
+ * @returns Pointer to the first component that might be an 8.3 name, NULL if
+ *          not 8.3 path.
+ * @param   pwszPath        The path to check.
+ *
+ * @remarks This is making bad ASSUMPTION wrt to the naming scheme of 8.3 names,
+ *          however, non-tilde 8.3 aliases are probably rare enough to not be
+ *          worth all the extra code necessary to open each path component and
+ *          check if we've got the short name or not.
+ */
+RTDECL(PRTUTF16) RTNtPathFindPossible8dot3Name(PCRTUTF16 pwszPath)
+{
+    PCRTUTF16 pwszName = pwszPath;
+    for (;;)
+    {
+        RTUTF16 wc = *pwszPath++;
+        if (wc == '~')
+        {
+            /* Could check more here before jumping to conclusions... */
+            if (pwszPath - pwszName <= 8+1+3)
+                return (PRTUTF16)pwszName;
+        }
+        else if (wc == '\\' || wc == '/' || wc == ':')
+            pwszName = pwszPath;
+        else if (wc == 0)
+            break;
+    }
+    return NULL;
+}
+
Index: /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp	(revision 60480)
+++ /trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp	(revision 60481)
@@ -162,8 +162,9 @@
 
 /**
- * Converts a path to NT format and encoding.
- *
- * @returns IPRT status code.
- * @param   pNtName             Where to return the NT name.
+ * Converts a windows-style path to NT format and encoding.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              rtTNtPathToNative.
  * @param   phRootDir           Where to return the root handle, if applicable.
  * @param   pszPath             The UTF-8 path.
@@ -225,4 +226,19 @@
     memcpy(szPath, pszPrefix, cchPrefix);
     return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
+}
+
+
+/**
+ * Converts a windows-style path to NT format and encoding.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              RTNtPathToNative.
+ * @param   phRootDir           Where to return the root handle, if applicable.
+ * @param   pszPath             The UTF-8 path.
+ */
+RTDECL(int) RTNtPathFromWinUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+{
+    return rtNtPathToNative(pNtName, phRootDir, pszPath);
 }
 
@@ -341,10 +357,36 @@
 
 /**
+ * Ensures that the NT string has sufficient storage to hold @a cwcMin RTUTF16
+ * chars plus a terminator.
+ *
+ * The NT string must have been returned by RTNtPathFromWinUtf8 or
+ * RTNtPathFromWinUtf16Ex.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             The NT path string.
+ * @param   cwcMin              The minimum number of RTUTF16 chars. Max 32767.
+ * @sa      RTNtPathFree
+ */
+RTDECL(int) RTNtPathEnsureSpace(struct _UNICODE_STRING *pNtName, size_t cwcMin)
+{
+    if (pNtName->MaximumLength / sizeof(RTUTF16) > cwcMin)
+        return VINF_SUCCESS;
+
+    AssertReturn(cwcMin < _64K / sizeof(RTUTF16), VERR_OUT_OF_RANGE);
+
+    size_t const cbMin = (cwcMin + 1) * sizeof(RTUTF16);
+    int rc = RTUtf16Realloc(&pNtName->Buffer, cbMin);
+    if (RT_SUCCESS(rc))
+        pNtName->MaximumLength = (uint16_t)cbMin;
+    return rc;
+}
+
+
+/**
  * Frees the native path and root handle.
  *
  * @param   pNtName             The NT path after a successful rtNtPathToNative
  *                              call.
- * @param   phRootDir           The root handle variable after a
- *                              rtNtPathToNative.
+ * @param   phRootDir           The root handle variable from the same call.
  */
 static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
@@ -358,8 +400,7 @@
  * 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.
+ * @param   pNtName             The NT path from a successful RTNtPathToNative
+ *                              or RTNtPathFromWinUtf16Ex call.
+ * @param   phRootDir           The root handle variable from the same call.
  */
 RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 60480)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 60481)
@@ -152,4 +152,5 @@
 	tstRTProcWait \
 	tstFileAppendWin-1 \
+	tstRTNtPath-1 \
 	ntGetTimerResolution
 PROGRAMS.linux += \
@@ -526,4 +527,7 @@
 	../common/string/strlen.asm
 
+tstRTNtPath-1_TEMPLATE = VBOXR3TSTEXE
+tstRTNtPath-1_SOURCES = tstRTNtPath-1.cpp
+
 tstOnce_TEMPLATE = VBOXR3TSTEXE
 tstOnce_SOURCES = tstOnce.cpp
Index: /trunk/src/VBox/Runtime/testcase/tstRTNtPath-1.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTNtPath-1.cpp	(revision 60481)
+++ /trunk/src/VBox/Runtime/testcase/tstRTNtPath-1.cpp	(revision 60481)
@@ -0,0 +1,212 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - RTNtPath*.
+ */
+
+/*
+ * Copyright (C) 2010-2016 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 <iprt/nt/nt-and-windows.h>
+
+#include <iprt/err.h>
+#include <iprt/dir.h>
+#include <iprt/env.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef struct TSTRAVERSE
+{
+    uint32_t        cHits;
+    uint32_t        cFirstClassHits;
+    uint32_t        cEntries;
+    uint32_t        cDirs;
+    UNICODE_STRING  UniStr;
+    char            szLongPath[RTPATH_MAX];
+    char            szLongPathNt[RTPATH_MAX];
+    char            szShortPath[RTPATH_MAX];
+    union
+    {
+        RTDIRENTRYEX    EntryEx;
+        uint8_t         abBuf[RTPATH_MAX + sizeof(RTDIRENTRYEX)];
+    } u;
+    size_t          cbDirEntry;
+} TSTRAVERSE;
+
+
+void tstTraverse8dot3(TSTRAVERSE *pThis, size_t cchLong, size_t cchShort, uint32_t cShortNames)
+{
+    pThis->cDirs++;
+
+    uint32_t cLeftToTest = 2;
+    PRTDIR  hDir;
+    int rc = RTDirOpen(&hDir, pThis->szLongPath);
+    if (RT_FAILURE(rc))
+        return;
+    while (pThis->cFirstClassHits < 256)
+    {
+        pThis->cbDirEntry = sizeof(pThis->u);
+        rc = RTDirReadEx(hDir, &pThis->u.EntryEx, &pThis->cbDirEntry,  RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+        if (RT_FAILURE(rc))
+            break;
+        pThis->cEntries++;
+
+        if (RTDirEntryExIsStdDotLink(&pThis->u.EntryEx))
+            continue;
+
+        if (   cchLong + pThis->u.EntryEx.cbName + 1 >= sizeof(pThis->szLongPath)
+            || cchShort + RT_MAX(pThis->u.EntryEx.cbName, pThis->u.EntryEx.cwcShortName * 3) + 1 >= sizeof(pThis->szShortPath) )
+            continue; /* ignore obvious overflows */
+
+        bool fHave8Dot3 = pThis->u.EntryEx.cwcShortName
+                       && RTUtf16ICmpUtf8(pThis->u.EntryEx.wszShortName, pThis->u.EntryEx.szName) != 0;
+        if (   fHave8Dot3
+            || RTFS_IS_DIRECTORY(pThis->u.EntryEx.Info.Attr.fMode)
+            || cLeftToTest > 0)
+        {
+            if (!fHave8Dot3)
+                memcpy(&pThis->szShortPath[cchShort], pThis->u.EntryEx.szName, pThis->u.EntryEx.cbName + 1);
+            else
+            {
+                char *pszDst = &pThis->szShortPath[cchShort];
+                rc = RTUtf16ToUtf8Ex(pThis->u.EntryEx.wszShortName, pThis->u.EntryEx.cwcShortName, &pszDst,
+                                     sizeof(pThis->szShortPath) - cchShort, NULL);
+                if (RT_FAILURE(rc))
+                    continue;
+            }
+            memcpy(&pThis->szLongPath[cchLong], pThis->u.EntryEx.szName, pThis->u.EntryEx.cbName + 1);
+
+            /*
+             * Check it out.
+             */
+            HANDLE hRoot;
+            RTTESTI_CHECK_RC(rc = RTNtPathFromWinUtf8(&pThis->UniStr, &hRoot, pThis->szShortPath), VINF_SUCCESS);
+            if (RT_SUCCESS(rc))
+            {
+                RTTESTI_CHECK(pThis->UniStr.MaximumLength > pThis->UniStr.Length);
+                RTTESTI_CHECK(pThis->UniStr.Length == RTUtf16Len(pThis->UniStr.Buffer) * sizeof(RTUTF16));
+
+                RTTESTI_CHECK_RC(rc = RTNtPathEnsureSpace(&pThis->UniStr, RTPATH_MAX + 256), VINF_SUCCESS);
+                if (RT_SUCCESS(rc))
+                {
+                    RTTESTI_CHECK_RC(rc = RTNtPathExpand8dot3Path(&pThis->UniStr, false /*fPathOnly*/), VINF_SUCCESS);
+                    if (RT_SUCCESS(rc))
+                    {
+                        RTTESTI_CHECK(pThis->UniStr.Length == RTUtf16Len(pThis->UniStr.Buffer) * sizeof(RTUTF16));
+
+                        /* Skip the win32 path prefix (it is usually \??\) so we can compare. Crude but works */
+                        size_t offPrefix = 0;
+                        while (   pThis->UniStr.Buffer[offPrefix] != pThis->szLongPath[0]
+                               && pThis->UniStr.Buffer[offPrefix] != '\0')
+                            offPrefix++;
+                        if (!pThis->UniStr.Buffer[offPrefix])
+                            offPrefix = 0;
+
+                        if (RTUtf16CmpUtf8(&pThis->UniStr.Buffer[offPrefix], pThis->szLongPath) == 0)
+                        { /* ok */ }
+                        else if (RTUtf16ICmpUtf8(&pThis->UniStr.Buffer[offPrefix], pThis->szLongPath) == 0)
+                            RTTestIFailed("case mismatch: '%ls' vs '%s'", pThis->UniStr.Buffer, pThis->szLongPath);
+                        else
+                            RTTestIFailed("mismatch: '%ls' vs '%s'", pThis->UniStr.Buffer, pThis->szLongPath);
+
+                        /*
+                         * Update test efficiency hits.
+                         */
+                        if (   cLeftToTest > 0
+                            && !pThis->u.EntryEx.cwcShortName
+                            && !RTFS_IS_DIRECTORY(pThis->u.EntryEx.Info.Attr.fMode))
+                        {
+                            cLeftToTest--;
+                            if (cShortNames >= 3)
+                                pThis->cFirstClassHits++;
+                        }
+                        pThis->cHits++;
+                    }
+                }
+                RTNtPathFree(&pThis->UniStr, &hRoot);
+            }
+            //RTTestIPrintf(RTTESTLVL_ALWAYS, "debug: %u %u/%u %u/%u %s\n",
+            //              cShortNames, pThis->cFirstClassHits, pThis->cHits, pThis->cDirs, pThis->cEntries, pThis->szShortPath);
+
+            /*
+             * Decend into sub-directories.  Must add slash first.
+             */
+            if (RTFS_IS_DIRECTORY(pThis->u.EntryEx.Info.Attr.fMode))
+            {
+                pThis->szLongPath[cchLong + pThis->u.EntryEx.cbName]     = '\\';
+                pThis->szLongPath[cchLong + pThis->u.EntryEx.cbName + 1] = '\0';
+                strcat(&pThis->szShortPath[cchShort], "\\");
+
+                tstTraverse8dot3(pThis,
+                                 cchLong + pThis->u.EntryEx.cbName + 1,
+                                 cchShort + strlen(&pThis->szShortPath[cchShort]),
+                                 cShortNames + (pThis->u.EntryEx.cwcShortName != 0));
+            }
+        }
+    }
+    RTDirClose(hDir);
+}
+
+
+int main()
+{
+    RTTEST hTest;
+    int rc = RTTestInitAndCreate("tstRTNtPath-1", &hTest);
+    if (rc)
+        return rc;
+    RTTestBanner(hTest);
+
+    /*
+     * Traverse the boot file system looking for short named and try locate an instance
+     * where we have at least 3 in a row.
+     */
+    RTTestSub(hTest, "8dot3");
+
+    TSTRAVERSE This;
+    RT_ZERO(This);
+    rc = RTEnvGetEx(RTENV_DEFAULT, "SystemDrive", This.szLongPath, 64, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        RTStrCat(This.szLongPath, sizeof(This.szLongPath), "\\");
+        size_t cch = strlen(This.szLongPath);
+        memcpy(This.szShortPath, This.szLongPath, cch + 1);
+
+        tstTraverse8dot3(&This, cch, cch, 0);
+
+
+    }
+    else
+        RTTestSkipped(hTest, "failed to resolve %SystemDrive%: %Rrc",  rc);
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
