Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 69825)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 69826)
@@ -551,6 +551,5 @@
      * @param   pvThis      The implementation specific directory data.
      * @param   pszEntry    The name of the immediate file to open or create.
-     * @param   fOpenFile   RTFILE_O_XXX combination.  Currently RTFILE_O_OPEN is
-     *                      required, but this may change.
+     * @param   fOpenFile   RTFILE_O_XXX combination.
      * @param   fObjFlags   More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX.
      *                      The meaning of RTPATH_F_FOLLOW_LINK differs here, if
@@ -562,4 +561,22 @@
     DECLCALLBACKMEMBER(int, pfnOpen)(void *pvThis, const char *pszEntry, uint64_t fOpenFile,
                                      uint32_t fObjFlags, PRTVFSOBJ phVfsObj);
+
+    /**
+     * Optional method for symbolic link handling in the vfsstddir.cpp.
+     *
+     * This is really just a hack to make symbolic link handling work when working
+     * with directory objects that doesn't have an associated VFS.  It also helps
+     * deal with drive letters in symbolic links on Windows and OS/2.
+     *
+     * @returns IPRT status code.
+     * @retval  VERR_PATH_IS_RELATIVE if @a pszPath isn't absolute and should be
+     *          handled using pfnOpen().
+     *
+     * @param   pvThis      The implementation specific directory data.
+     * @param   pszRoot     Path to the alleged root.
+     * @param   phVfsDir    Where to return the handle to the specified root
+     *                      directory (or may current dir on a drive letter).
+     */
+    DECLCALLBACKMEMBER(int, pfnFollowAbsoluteSymlink)(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir);
 
     /**
Index: /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp	(revision 69825)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp	(revision 69826)
@@ -995,4 +995,5 @@
     },
     rtDvmVfsDir_Open,
+    NULL /* pfnFollowAbsoluteSymlink */,
     rtDvmVfsDir_OpenFile,
     rtDvmVfsDir_OpenDir,
Index: /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp	(revision 69825)
+++ /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp	(revision 69826)
@@ -4723,4 +4723,5 @@
     },
     rtFsFatDir_Open,
+    NULL /* pfnFollowAbsoluteSymlink */,
     rtFsFatDir_OpenFile,
     rtFsFatDir_OpenDir,
Index: /trunk/src/VBox/Runtime/common/fs/isovfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fs/isovfs.cpp	(revision 69825)
+++ /trunk/src/VBox/Runtime/common/fs/isovfs.cpp	(revision 69826)
@@ -3691,4 +3691,5 @@
     },
     rtFsIsoDir_Open,
+    NULL /* pfnFollowAbsoluteSymlink */,
     rtFsIsoDir_OpenFile,
     rtFsIsoDir_OpenDir,
Index: /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 69825)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 69826)
@@ -47,4 +47,5 @@
 #include "internal/fs.h"
 #include "internal/magics.h"
+#include "internal/path.h"
 //#include "internal/vfs.h"
 
@@ -353,4 +354,6 @@
 DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis);
 static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir);
+static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
+                                            PRTVFSPARSEDPATH pPath, uint32_t fFlags);
 
 
@@ -1207,61 +1210,53 @@
     if (RT_SUCCESS(rc))
     {
-        if (pPath->cComponents > 0)
-        {
-            /*
-             * Tranverse the path, resolving the parent node, not
-             * checking for symbolic links in the final element.
+        /*
+         * Tranverse the path, resolving the parent node.
+         * We'll do the symbolic link checking here with help of pfnOpen.
+         */
+        RTVFSDIRINTERNAL *pVfsParentDir;
+        rc = rtVfsTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
+        if (RT_SUCCESS(rc))
+        {
+
+           /*
+             * Do the opening.  Loop if we need to follow symbolic links.
              */
-            RTVFSDIRINTERNAL *pVfsParentDir;
-            rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
-            if (RT_SUCCESS(rc))
+            for (uint32_t cLoops = 1; ; cLoops++)
             {
-                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
-
-                /*
-                 * If we've got a trailing directory slash, use pfnOpenDir
-                 * instead of pfnOpen.
-                 */
+                /* If we end with a directory slash, adjust open flags. */
                 if (pPath->fDirSlash)
                 {
-                    RTVFSDIR hVfsDir;
-                    RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
-                    rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, 0 /** @todo fFlags*/, &hVfsDir);
-                    RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
-                    if (RT_SUCCESS(rc))
-                    {
-                        *phVfsObj = RTVfsObjFromDir(hVfsDir);
-                        RTVfsDirRelease(hVfsDir);
-                        AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
-                    }
+                    fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
+                    if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
+                        fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
                 }
+
+                /* Open it. */
+                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
+                RTVFSOBJ    hVfsObj;
+                RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
+                rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
+                RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
+                if (RT_FAILURE(rc))
+                    break;
+
+                /* We're done if we don't follow links or this wasn't a link. */
+                if (   !(fObjFlags & RTPATH_F_FOLLOW_LINK)
+                    || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
+                {
+                    *phVfsObj = hVfsObj;
+                    break;
+                }
+
+                /* Follow symbolic link. */
+                if (cLoops < RTVFS_MAX_LINKS)
+                    rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
                 else
-                {
-                    RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
-                    rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, phVfsObj);
-                    RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
-                }
-                RTVfsDirRelease(pVfsParentDir);
+                    rc = VERR_TOO_MANY_SYMLINKS;
+                RTVfsObjRelease(hVfsObj);
+                if (RT_FAILURE(rc))
+                    break;
             }
         }
-        /*
-         * The path boils down to '.', call pfnOpenDir on pThis with '.' as input.
-         * The caller may wish for a new directory instance to enumerate the entries
-         * in parallel or some such thing.
-         */
-        else
-        {
-            RTVFSDIR hVfsDir;
-            RTVfsLockAcquireRead(pThis->Base.hLock);
-            rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &hVfsDir); /** @todo flags */
-            RTVfsLockReleaseRead(pThis->Base.hLock);
-            if (RT_SUCCESS(rc))
-            {
-                *phVfsObj = RTVfsObjFromDir(hVfsDir);
-                RTVfsDirRelease(hVfsDir);
-                AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
-            }
-        }
-
         RTVfsParsePathFree(pPath);
     }
@@ -1380,4 +1375,7 @@
     if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
         *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
+
+/** @todo The '..' handling doesn't really work wrt to symbolic links in the
+ *        path.  */
 
     /*
@@ -1490,5 +1488,5 @@
 RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
 {
-    if (*pszPath != '/')
+    if (*pszPath != '/' && *pszPath != '\\')
     {
         if (pszCwd)
@@ -1531,5 +1529,5 @@
         pPath->szPath[1]         = '\0';
         pPath->szPath[2]         = '\0';
-        while (pszPath[0] == '/')
+        while (pszPath[0] == '/' || pszPath[0] == '\\')
             pszPath++;
         if (!pszPath[0])
@@ -1581,12 +1579,15 @@
  *
  * @returns IPRT status code.
+ * @param   ppCurDir            The current directory variable. We change it if
+ *                              the symbolic links is absolute.
  * @param   pPath               The parsed path to update.
- * @param   piComponent         The component iterator to update.
+ * @param   iPathComponent      The current path component.
  * @param   hSymlink            The symbolic link to process.
  */
-static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
-{
-    /*
-     * Read the link.
+static int rtVfsTraverseHandleSymlink(RTVFSDIRINTERNAL **ppCurDir, PRTVFSPARSEDPATH pPath,
+                                      uint16_t iPathComponent, RTVFSSYMLINK hSymlink)
+{
+    /*
+     * Read the link and append the trailing path to it.
      */
     char szPath[RTPATH_MAX];
@@ -1595,42 +1596,66 @@
     {
         szPath[sizeof(szPath) - 1] = '\0';
-        if (szPath[0] == '/')
-        {
-            /*
-             * Absolute symlink.
-             */
-            rc = RTVfsParsePath(pPath, szPath, NULL);
-            if (RT_SUCCESS(rc))
+        if (iPathComponent + 1 < pPath->cComponents)
+            rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iPathComponent + 1]]);
+    }
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Special hack help vfsstddir.cpp deal with symbolic links.
+         */
+        RTVFSDIRINTERNAL *pCurDir = *ppCurDir;
+        char             *pszPath = szPath;
+        if (pCurDir->pOps->pfnFollowAbsoluteSymlink)
+        {
+            size_t cchRoot = rtPathRootSpecLen(szPath);
+            if (cchRoot > 0)
             {
-                *piComponent = 0;
-                return VINF_SUCCESS;
-            }
-        }
-        else
-        {
-            /*
-             * Relative symlink, must replace the current component with the
-             * link value.  We do that by using the remainder of the symlink
-             * buffer as temporary storage.
-             */
-            uint16_t iComponent = *piComponent;
-            if (iComponent + 1 < pPath->cComponents)
-                rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iComponent + 1]]);
-            if (RT_SUCCESS(rc))
-            {
-                pPath->cch = pPath->aoffComponents[iComponent] - (iComponent > 0);
-                pPath->aoffComponents[iComponent + 1] = pPath->cch + 1;
-                pPath->szPath[pPath->cch]     = '\0';
-                pPath->szPath[pPath->cch + 1] = '\0';
-
-                rc = RTVfsParsePathAppend(pPath, szPath, &iComponent);
+                pszPath = &szPath[cchRoot];
+                char const chSaved = *pszPath;
+                *pszPath = '\0';
+                RTVFSDIRINTERNAL *pVfsRootDir;
+                RTVfsLockAcquireWrite(pCurDir->Base.hLock);
+                rc = pCurDir->pOps->pfnFollowAbsoluteSymlink(pCurDir, szPath, &pVfsRootDir);
+                RTVfsLockAcquireWrite(pCurDir->Base.hLock);
+                *pszPath = chSaved;
                 if (RT_SUCCESS(rc))
                 {
-                    *piComponent = iComponent;
-                    return VINF_SUCCESS;
+                    RTVfsDirRelease(pCurDir);
+                    *ppCurDir = pCurDir = pVfsRootDir;
                 }
+                else if (rc == VERR_PATH_IS_RELATIVE)
+                    pszPath = szPath;
+                else
+                    return rc;
             }
         }
-    }
+
+        rc = RTVfsParsePath(pPath, pszPath, NULL);
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Deal with absolute references in a VFS setup.
+             * Note! The current approach only correctly handles this on root volumes.
+             */
+            if (   pPath->fAbsolute
+                && pCurDir->Base.hVfs != NIL_RTVFS) /** @todo This needs fixing once we implement mount points. */
+            {
+                RTVFSINTERNAL    *pVfs = pCurDir->Base.hVfs;
+                RTVFSDIRINTERNAL *pVfsRootDir;
+                RTVfsLockAcquireRead(pVfs->Base.hLock);
+                rc = pVfs->pOps->pfnOpenRoot(pVfs->Base.pvThis, &pVfsRootDir);
+                RTVfsLockReleaseRead(pVfs->Base.hLock);
+                if (RT_SUCCESS(rc))
+                {
+                    RTVfsDirRelease(pCurDir);
+                    *ppCurDir = pCurDir = pVfsRootDir;
+                }
+                else
+                    return rc;
+            }
+        }
+    }
+    else if (rc == VERR_BUFFER_OVERFLOW)
+        rc = VERR_FILENAME_TOO_LONG;
     return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
 }
@@ -1639,9 +1664,12 @@
 /**
  * Internal worker for various open functions as well as RTVfsTraverseToParent.
+ *
  *
  * @returns IPRT status code.
  * @param   pThis           The VFS.
  * @param   pPath           The parsed path.  This may be changed as symbolic
- *                          links are processed during the path traversal.
+ *                          links are processed during the path traversal.  If
+ *                          it contains zero components, a dummy component is
+ *                          added to assist the caller.
  * @param   fFlags          RTPATH_F_XXX.
  * @param   ppVfsParentDir  Where to return the parent directory handle
@@ -1660,5 +1688,4 @@
     AssertPtr(ppVfsParentDir);
     *ppVfsParentDir = NULL;
-    AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
     Assert(RTPATH_F_IS_VALID(fFlags, 0));
 
@@ -1669,4 +1696,25 @@
         return VERR_INVALID_HANDLE;
     RTVFSDIRINTERNAL *pCurDir = pThis;
+
+    /*
+     * Special case for traversing zero components.
+     * We fake up a "./" in the pPath to help the caller along.
+     */
+    if (pPath->cComponents == 0)
+    {
+        pPath->fDirSlash         = true;
+        pPath->szPath[0]         = '.';
+        pPath->szPath[1]         = '\0';
+        pPath->szPath[2]         = '\0';
+        pPath->cch               = 1;
+        pPath->cComponents       = 1;
+        pPath->aoffComponents[0] = 0;
+        pPath->aoffComponents[1] = 1;
+        pPath->aoffComponents[2] = 1;
+
+        *ppVfsParentDir = pCurDir;
+        return VINF_SUCCESS;
+    }
+
 
     /*
@@ -1782,21 +1830,8 @@
                 break;
             }
-            uint16_t iRestartComp = iComponent;
-            rc = rtVfsTraverseHandleSymlink(pPath, &iRestartComp, hSymlink);
+            rc = rtVfsTraverseHandleSymlink(&pCurDir, pPath, iComponent, hSymlink);
             if (RT_FAILURE(rc))
                 break;
-            if (iRestartComp != iComponent)
-            {
-                /* Must restart from the root. */
-                RTVfsDirRelease(pCurDir);
-                if (RTVfsDirRetain(pThis) == UINT32_MAX)
-                {
-                    rc = VERR_INVALID_HANDLE;
-                    pCurDir = NULL;
-                    break;
-                }
-                pCurDir = pThis;
-                iComponent = 0;
-            }
+            iComponent = 0;
         }
         else
@@ -1866,4 +1901,36 @@
     return rc;
 }
+
+
+
+/**
+ * Follows a symbolic link object to the next parent directory.
+ *
+ * @returns IPRT status code
+ * @param   ppVfsParentDir  Pointer to the parent directory of @a hVfsObj on
+ *                          input, the parent directory of the link target on
+ *                          return.
+ * @param   hVfsObj         Symbolic link object handle.
+ * @param   pPath           Path buffer to use parse the symbolic link target.
+ * @param   fFlags          See rtVfsDirTraverseToParent.
+ */
+static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
+                                            PRTVFSPARSEDPATH pPath, uint32_t fFlags)
+{
+    RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
+    AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, VERR_INTERNAL_ERROR_3);
+
+    int rc = rtVfsTraverseHandleSymlink(ppVfsParentDir, pPath, pPath->cComponents, hVfsSymlink);
+    if (RT_SUCCESS(rc))
+    {
+        RTVFSDIRINTERNAL *pVfsStartDir = *ppVfsParentDir;
+        rc = rtVfsDirTraverseToParent(pVfsStartDir, pPath, fFlags, ppVfsParentDir);
+        RTVfsDirRelease(pVfsStartDir);
+    }
+
+    RTVfsSymlinkRelease(hVfsSymlink);
+    return rc;
+}
+
 
 
@@ -2731,46 +2798,50 @@
     if (RT_SUCCESS(rc))
     {
-        if (   pPath->fDirSlash
-            || pPath->cComponents == 0)
-        {
-            fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
-            if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
-                fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
-        }
-
         /*
-         * Tranverse the path, resolving the parent node, not checking for
-         * symbolic links in the final element.
+         * Tranverse the path, resolving the parent node.
+         * We'll do the symbolic link checking here with help of pfnOpen.
          */
-        const char       *pszEntryName;
         RTVFSDIRINTERNAL *pVfsParentDir;
-        if (pPath->cComponents > 0)
-        {
-            rc = rtVfsDirTraverseToParent(pThis, pPath, fObjFlags & RTPATH_F_MASK, &pVfsParentDir);
-            pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
-        }
-        else
-        {
-            RTVfsDirRetain(pThis);
-            pVfsParentDir = pThis;
-            pszEntryName  = ".";
-        }
+        rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
         if (RT_SUCCESS(rc))
         {
             /*
-             * Do the opening.
+             * Do the opening.  Loop if we need to follow symbolic links.
              */
-            RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
-            rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, phVfsObj);
-            RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
-
-            if (   (fObjFlags & RTPATH_F_FOLLOW_LINK)
-                && RTVfsObjGetType(*phVfsObj) == RTVFSOBJTYPE_SYMLINK)
+            for (uint32_t cLoops = 1; ; cLoops++)
             {
-                /** @todo implement following symbolic links. */
-                AssertFailed();
-                RTVfsObjRelease(*phVfsObj);
-                *phVfsObj = NIL_RTVFSOBJ;
-                rc = VERR_NOT_IMPLEMENTED;
+                /* If we end with a directory slash, adjust open flags. */
+                if (pPath->fDirSlash)
+                {
+                    fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
+                    if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
+                        fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
+                }
+
+                /* Open it. */
+                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
+                RTVFSOBJ    hVfsObj;
+                RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
+                rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
+                RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
+                if (RT_FAILURE(rc))
+                    break;
+
+                /* We're done if we don't follow links or this wasn't a link. */
+                if (   !(fObjFlags & RTPATH_F_FOLLOW_LINK)
+                    || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
+                {
+                    *phVfsObj = hVfsObj;
+                    break;
+                }
+
+                /* Follow symbolic link. */
+                if (cLoops < RTVFS_MAX_LINKS)
+                    rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
+                else
+                    rc = VERR_TOO_MANY_SYMLINKS;
+                RTVfsObjRelease(hVfsObj);
+                if (RT_FAILURE(rc))
+                    break;
             }
 
Index: /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp	(revision 69825)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp	(revision 69826)
@@ -255,5 +255,5 @@
  */
 static DECLCALLBACK(int) rtVfsStdDir_Open(void *pvThis, const char *pszEntry, uint64_t fFileOpen,
-                                          uint32_t fVfsFlags, PRTVFSOBJ phVfsObj)
+                                          uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
 {
     PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
@@ -270,5 +270,5 @@
         {
             case RTFS_TYPE_DIRECTORY:
-                if (!(fVfsFlags & RTVFSOBJ_F_OPEN_DIRECTORY))
+                if (fObjFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
                 {
                     if (   (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
@@ -277,5 +277,5 @@
                     {
                         RTDIR hSubDir;
-                        rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, fVfsFlags, &hSubDir);
+                        rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, 0 /*fFlags*/, &hSubDir);
                         if (RT_SUCCESS(rc))
                         {
@@ -307,19 +307,19 @@
                 {
                     case RTFS_TYPE_FILE:
-                        rc = fVfsFlags & RTVFSOBJ_F_OPEN_FILE      ? VINF_SUCCESS : VERR_IS_A_FILE;
+                        rc = fObjFlags & RTVFSOBJ_F_OPEN_FILE      ? VINF_SUCCESS : VERR_IS_A_FILE;
                         break;
                     case RTFS_TYPE_DEV_BLOCK:
-                        rc = fVfsFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
+                        rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
                         break;
                     case RTFS_TYPE_DEV_CHAR:
-                        rc = fVfsFlags & RTVFSOBJ_F_OPEN_DEV_CHAR  ? VINF_SUCCESS : VERR_IS_A_CHAR_DEVICE;
+                        rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_CHAR  ? VINF_SUCCESS : VERR_IS_A_CHAR_DEVICE;
                         break;
                     /** @todo These two types should not result in files, but pure I/O streams.
                      *        possibly char device too.  */
                     case RTFS_TYPE_FIFO:
-                        rc = fVfsFlags & RTVFSOBJ_F_OPEN_FIFO      ? VINF_SUCCESS : VERR_IS_A_FIFO;
+                        rc = fObjFlags & RTVFSOBJ_F_OPEN_FIFO      ? VINF_SUCCESS : VERR_IS_A_FIFO;
                         break;
                     case RTFS_TYPE_SOCKET:
-                        rc = fVfsFlags & RTVFSOBJ_F_OPEN_SOCKET    ? VINF_SUCCESS : VERR_IS_A_SOCKET;
+                        rc = fObjFlags & RTVFSOBJ_F_OPEN_SOCKET    ? VINF_SUCCESS : VERR_IS_A_SOCKET;
                         break;
                     default:
@@ -355,5 +355,5 @@
 
             case RTFS_TYPE_SYMLINK:
-                if (fVfsFlags & RTVFSOBJ_F_OPEN_SYMLINK)
+                if (fObjFlags & RTVFSOBJ_F_OPEN_SYMLINK)
                 {
                     uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
@@ -398,8 +398,8 @@
                 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
                 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
-            && (fVfsFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
+            && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
         {
 
-            if ((fVfsFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
+            if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
             {
                 RTFILE hFile;
@@ -419,9 +419,9 @@
                 }
             }
-            else if ((fVfsFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
+            else if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
             {
                 RTDIR hSubDir;
                 rc = RTDirRelDirCreate(pThis->hDir, pszEntry, (fFileOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT,
-                                       0 /* fVfsFlags */, &hSubDir);
+                                       0 /* fFlags */, &hSubDir);
                 if (RT_SUCCESS(rc))
                 {
@@ -449,4 +449,16 @@
 
 /**
+ * @interface_method_impl{RTVFSDIROPS,pfnFollowAbsoluteSymlink}
+ */
+static DECLCALLBACK(int) rtVfsStdDir_FollowAbsoluteSymlink(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir)
+{
+    //PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
+    RT_NOREF(pvThis);
+    /** @todo walking restriction. */
+    return RTVfsDirOpenNormal(pszRoot, 0 /*fFlags*/, phVfsDir);
+}
+
+
+/**
  * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
  */
@@ -668,4 +680,5 @@
     },
     rtVfsStdDir_Open,
+    rtVfsStdDir_FollowAbsoluteSymlink,
     rtVfsStdDir_OpenFile,
     rtVfsStdDir_OpenDir,
