Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 69812)
+++ /trunk/include/iprt/err.h	(revision 69813)
@@ -1198,4 +1198,14 @@
 /** Symbolic link not allowed. */
 #define VERR_SYMLINK_NOT_ALLOWED            (-159)
+/** Is a symbolic link. */
+#define VERR_IS_A_SYMLINK                   (-160)
+/** Is a FIFO. */
+#define VERR_IS_A_FIFO                      (-161)
+/** Is a socket. */
+#define VERR_IS_A_SOCKET                    (-162)
+/** Is a block device. */
+#define VERR_IS_A_BLOCK_DEVICE              (-163)
+/** Is a character device. */
+#define VERR_IS_A_CHAR_DEVICE               (-164)
 /** @} */
 
@@ -2786,4 +2796,6 @@
 /** Unsupported file system format. */
 #define VERR_VFS_UNSUPPORTED_FORMAT                 (-24803)
+/** Unsupported create type in an RTVfsObjOpen or RTVfsDirOpenObj call.  */
+#define VERR_VFS_UNSUPPORTED_CREATE_TYPE            (-24804)
 /** @} */
 
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 69812)
+++ /trunk/include/iprt/mangling.h	(revision 69813)
@@ -2421,4 +2421,5 @@
 # define RTVfsChainMsgError                             RT_MANGLER(RTVfsChainMsgError)
 # define RTVfsChainMsgErrorExitFailure                  RT_MANGLER(RTVfsChainMsgErrorExitFailure)
+# define RTVfsChainOpenObj                              RT_MANGLER(RTVfsChainOpenObj)
 # define RTVfsChainOpenDir                              RT_MANGLER(RTVfsChainOpenDir)
 # define RTVfsChainOpenParentDir                        RT_MANGLER(RTVfsChainOpenParentDir)
@@ -2440,7 +2441,9 @@
 # define RTVfsDirOpenFile                               RT_MANGLER(RTVfsDirOpenFile)
 # define RTVfsDirOpenFileAsIoStream                     RT_MANGLER(RTVfsDirOpenFileAsIoStream)
+# define RTVfsDirOpenObj                                RT_MANGLER(RTVfsDirOpenObj)
 # define RTVfsDirQueryPathInfo                          RT_MANGLER(RTVfsDirQueryPathInfo)
 # define RTVfsDirReadEx                                 RT_MANGLER(RTVfsDirReadEx)
 # define RTVfsDirRemoveDir                              RT_MANGLER(RTVfsDirRemoveDir)
+# define RTVfsDirSetPathMode                            RT_MANGLER(RTVfsDirSetPathMode)
 # define RTVfsFileFlush                                 RT_MANGLER(RTVfsFileFlush)
 # define RTVfsFileFromBuffer                            RT_MANGLER(RTVfsFileFromBuffer)
@@ -2527,8 +2530,13 @@
 # define RTVfsObjFromSymlink                            RT_MANGLER(RTVfsObjFromSymlink)
 # define RTVfsObjFromVfs                                RT_MANGLER(RTVfsObjFromVfs)
+# define RTVfsObjGetType                                RT_MANGLER(RTVfsObjGetType)
+# define RTVfsObjOpen                                   RT_MANGLER(RTVfsObjOpen)
 # define RTVfsObjQueryInfo                              RT_MANGLER(RTVfsObjQueryInfo)
 # define RTVfsObjRelease                                RT_MANGLER(RTVfsObjRelease)
 # define RTVfsObjRetain                                 RT_MANGLER(RTVfsObjRetain)
 # define RTVfsObjRetainDebug                            RT_MANGLER(RTVfsObjRetainDebug)
+# define RTVfsObjSetMode                                RT_MANGLER(RTVfsObjSetMode)
+# define RTVfsObjSetOwner                               RT_MANGLER(RTVfsObjSetOwner)
+# define RTVfsObjSetTimes                               RT_MANGLER(RTVfsObjSetTimes)
 # define RTVfsObjToDir                                  RT_MANGLER(RTVfsObjToDir)
 # define RTVfsObjToFile                                 RT_MANGLER(RTVfsObjToFile)
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 69812)
+++ /trunk/include/iprt/vfs.h	(revision 69813)
@@ -166,4 +166,62 @@
 RTDECL(uint32_t)        RTVfsObjRelease(RTVFSOBJ hVfsObj);
 
+/** @name RTVFSOBJ_F_XXX - Flags or RTVfsObjOpen and RTVfsDirOpenObj.
+ * @note Must leave space for RTPATH_F_XXX.
+ * @{ */
+/** Directory (RTFS_TYPE_DIRECTORY). */
+#define RTVFSOBJ_F_OPEN_DIRECTORY           RT_BIT_32(8)
+/** Symbolic link (RTFS_TYPE_SYMLINK). */
+#define RTVFSOBJ_F_OPEN_SYMLINK             RT_BIT_32(9)
+/** Regular file (RTFS_TYPE_FILE). */
+#define RTVFSOBJ_F_OPEN_FILE                RT_BIT_32(10)
+/** Character device (RTFS_TYPE_DEV_CHAR). */
+#define RTVFSOBJ_F_OPEN_DEV_CHAR            RT_BIT_32(11)
+/** Block device (RTFS_TYPE_DEV_BLOCK). */
+#define RTVFSOBJ_F_OPEN_DEV_BLOCK           RT_BIT_32(12)
+/** Named pipe (fifo) (RTFS_TYPE_FIFO). */
+#define RTVFSOBJ_F_OPEN_FIFO                RT_BIT_32(13)
+/** Socket (RTFS_TYPE_SOCKET). */
+#define RTVFSOBJ_F_OPEN_SOCKET              RT_BIT_32(14)
+/** Mask object types we wish to open. */
+#define RTVFSOBJ_F_OPEN_MASK                UINT32_C(0x00003f00)
+/** Any kind of object that translates to RTVFSOBJTYPE_FILE. */
+#define RTVFSOBJ_F_OPEN_ANY_FILE            (RTVFSOBJ_F_FILE | RTVFSOBJ_F_DEV_BLOCK)
+/** Any kind of object that translates to RTVFSOBJTYPE_IOS or
+ *  RTVFSOBJTYPE_FILE. */
+#define RTVFSOBJ_F_OPEN_ANY_IO_STREAM       (RTVFSOBJ_F_ANY_FILE | RTVFSOBJ_F_DEV_BLOCK | RTVFSOBJ_F_FIFO | RTVFSOBJ_F_SOCKET)
+/** Any kind of object. */
+#define RTVFSOBJ_F_OPEN_ANY                 RTVFSOBJ_F_OPEN_MASK
+
+/** Do't create anything, return file not found. */
+#define RTVFSOBJ_F_CREATE_NOTHING           UINT32_C(0x00000000)
+/** Create a file if the if the object was not found and the RTFILE_O_XXX
+ * flags allows it. */
+#define RTVFSOBJ_F_CREATE_FILE              UINT32_C(0x00010000)
+/** Create a directory if the object was not found and the RTFILE_O_XXX
+ * flags allows it. */
+#define RTVFSOBJ_F_CREATE_DIRECTORY         UINT32_C(0x00020000)
+/** The creation type mask. */
+#define RTVFSOBJ_F_CREATE_MASK              UINT32_C(0x00070000)
+
+/** Indicate that this call is for traversal.
+ * @internal only  */
+#define RTVFSOBJ_F_TRAVERSAL                RT_BIT_32(31)
+/** Valid mask for external callers. */
+#define RTVFSOBJ_F_VALID_MASK               UINT32_C(0x00003f00)
+/** @} */
+
+/**
+ * Opens any file system object in the given VFS.
+ *
+ * @returns IPRT status code.
+ * @param   hVfs            The VFS to open the object within.
+ * @param   pszPath         Path to the file.
+ * @param   fFileOpen       RTFILE_O_XXX flags.
+ * @param   fObjFlags       More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX.
+ * @param   phVfsObj        Where to return the object handle.
+ * @sa      RTVfsDirOpenObj, RTVfsDirOpenDir, RTVfsDirOpenFile
+ */
+RTDECL(int)             RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj);
+
 /**
  * Query information about the object.
@@ -181,4 +239,66 @@
 RTDECL(int)             RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr);
 
+/**
+ * Sets the file mode for the given VFS object.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_INVALID_FUNCTION if the object type has no file mode to set.
+ *          Only directories, files and symbolic links support this operation.
+ *
+ * @param   hVfsObj         The VFS object handle.
+ * @param   fMode           The mode mask.
+ * @param   fMask           The bits in the mode mask which should be changed.
+ */
+RTDECL(int)             RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask);
+
+/**
+ * Sets one or more timestamps for the given VFS object.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_INVALID_FUNCTION if the object type has no file mode to set.
+ *          Only directories, files and symbolic links support this operation.
+ *
+ * @param   hVfsObj             The VFS object handle.
+ * @param   pAccessTime         Pointer to the new access time. NULL if not to
+ *                              be changed.
+ * @param   pModificationTime   Pointer to the new modifcation time. NULL if not
+ *                              to be changed.
+ * @param   pChangeTime         Pointer to the new change time. NULL if not to
+ *                              be changed.
+ * @param   pBirthTime          Pointer to the new time of birth. NULL if not to
+ *                              be changed.
+ *
+ * @remarks See RTFileSetTimes for restrictions and behavior imposed by the
+ *          host OS or underlying VFS provider.
+ * @sa      RTFileSetTimes, RTPathSetTimes
+ */
+RTDECL(int)             RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+                                         PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime);
+
+/**
+ * Set the unix style owner and group on the given VFS object.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_INVALID_FUNCTION if the object type has no file mode to set.
+ *          Only directories, files and symbolic links support this operation.
+ *
+ * @param   hVfsObj         The VFS object handle.
+ * @param   uid             The user ID of the new owner.  NIL_RTUID if
+ *                          unchanged.
+ * @param   gid             The group ID of the new owner group. NIL_RTGID if
+ *                          unchanged.
+ *
+ * @sa      RTFileSetOwner, RTPathSetOwner.
+ */
+RTDECL(int)             RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid);
+
+
+/**
+ * Gets the type of a VFS object.
+ *
+ * @returns The VFS object type on success, RTVFSOBJTYPE_INVALID on failure.
+ * @param   hVfsObj         The VFS base object handle.
+ */
+RTDECL(RTVFSOBJTYPE)    RTVfsObjGetType(RTVFSOBJ hVfsObj);
 
 /**
@@ -440,4 +560,18 @@
 
 /**
+ * Opens any file system object in or under the given directory.
+ *
+ * @returns IPRT status code.
+ * @param   hVfsDir         The VFS directory start walking the @a pszPath
+ *                          relative to.
+ * @param   pszPath         Path to the file.
+ * @param   fFileOpen       RTFILE_O_XXX flags.
+ * @param   fObjFlags       More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX.
+ * @param   phVfsObj        Where to return the object handle.
+ * @sa      RTVfsObjOpen, RTVfsDirOpenDir, RTVfsDirOpenFile
+ */
+RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj);
+
+/**
  * Opens a file in or under the given directory.
  *
@@ -1559,4 +1693,21 @@
 RTDECL(int) RTVfsChainOpenVfs(const char *pszSpec, PRTVFS phVfs, uint32_t *poffError, PRTERRINFO pErrInfo);
 RTDECL(int) RTVfsChainOpenFsStream(const char *pszSpec, PRTVFSFSSTREAM  phVfsFss, uint32_t *poffError, PRTERRINFO pErrInfo);
+
+/**
+ * Opens any kind of file system object.
+ *
+ * @returns IPRT status code.
+ * @param   pszSpec         The VFS chain specification or plain path.
+ * @param   fFileOpen       RTFILE_O_XXX flags.
+ * @param   fObjFlags       More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX.
+ * @param   phVfsObj        Where to return the handle to the opened object.
+ * @param   poffError       Where to on error return an offset into @a pszSpec
+ *                          of what cause the error.  Optional.
+ * @param   pErrInfo        Where to return additional error information.
+ *                          Optional.
+ */
+RTDECL(int) RTVfsChainOpenObj(const char *pszSpec, uint64_t fFileOpen, uint32_t fObjOpen,
+                              PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo);
+
 RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo);
 RTDECL(int) RTVfsChainOpenParentDir(const char *pszSpec, uint32_t fOpen, PRTVFSDIR phVfsDir, const char **ppszChild,
Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 69812)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 69813)
@@ -523,4 +523,45 @@
 
     /**
+     * Generic method for opening any kind of file system object.
+     *
+     * Can also create files and directories.  Symbolic links, devices and such
+     * needs to be created using special methods or this would end up being way more
+     * complicated than it already is.
+     *
+     * There are optional specializations available.
+     *
+     * @returns IPRT status code.
+     * @retval  VERR_PATH_NOT_FOUND or VERR_FILE_NOT_FOUND if @a pszEntry was not
+     *          found.
+     * @retval  VERR_IS_A_FILE if @a pszEntry is a file or similar but @a fFlags
+     *          indicates that the type of object should not be opened.
+     * @retval  VERR_IS_A_DIRECTORY if @a pszEntry is a directory but @a fFlags
+     *          indicates that directories should not be opened.
+     * @retval  VERR_IS_A_SYMLINK if @a pszEntry is a symbolic link but @a fFlags
+     *          indicates that symbolic links should not be opened (or followed).
+     * @retval  VERR_IS_A_FIFO if @a pszEntry is a FIFO but @a fFlags indicates that
+     *          FIFOs should not be opened.
+     * @retval  VERR_IS_A_SOCKET if @a pszEntry is a socket but @a fFlags indicates
+     *          that sockets should not be opened.
+     * @retval  VERR_IS_A_BLOCK_DEVICE if @a pszEntry is a block device but
+     *          @a fFlags indicates that block devices should not be opened.
+     * @retval  VERR_IS_A_BLOCK_DEVICE if @a pszEntry is a character device but
+     *          @a fFlags indicates that character devices should not be opened.
+     *
+     * @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   fObjFlags   More flags: RTVFSOBJ_F_XXX, RTPATH_F_XXX.
+     *                      The meaning of RTPATH_F_FOLLOW_LINK differs here, if
+     *                      @a pszEntry is a symlink it should be opened for
+     *                      traversal rather than according to @a fOpenFile.
+     * @param   phVfsObj    Where to return the handle to the opened object.
+     * @sa      RTFileOpen, RTDirOpen
+     */
+    DECLCALLBACKMEMBER(int, pfnOpen)(void *pvThis, const char *pszEntry, uint64_t fOpenFile,
+                                     uint32_t fObjFlags, PRTVFSOBJ phVfsObj);
+
+    /**
      * Opens a directory entry for traversal purposes.
      *
@@ -542,4 +583,5 @@
      * @todo    Should com dir, symlinks and mount points using some common
      *          ancestor "class".
+     * @note    Will be replaced by pfnOpenObj.
      */
     DECLCALLBACKMEMBER(int, pfnTraversalOpen)(void *pvThis, const char *pszEntry, PRTVFSDIR phVfsDir,
@@ -553,8 +595,9 @@
      * @param   pszFilename The name of the immediate file to open or create.
      * @param   fOpen       The open flags (RTFILE_O_XXX).
-     * @param   phVfsFile   Where to return the thandle to the opened file.
+     * @param   phVfsFile   Where to return the handle to the opened file.
+     * @note    Optional.  RTVFSDIROPS::pfnOpenObj will be used if NULL.
      * @sa      RTFileOpen.
      */
-    DECLCALLBACKMEMBER(int, pfnOpenFile)(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile);
+    DECLCALLBACKMEMBER(int, pfnOpenFile)(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile);
 
     /**
@@ -567,4 +610,5 @@
      * @param   phVfsDir    Where to return the handle to the opened directory.
      *                      Optional.
+     * @note    Optional.  RTVFSDIROPS::pfnOpenObj will be used if NULL.
      * @sa      RTDirOpen.
      */
@@ -580,4 +624,5 @@
      * @param   phVfsDir    Where to optionally return the handle to the newly
      *                      create directory.
+     * @note    Optional.  RTVFSDIROPS::pfnOpenObj will be used if NULL.
      * @sa      RTDirCreate.
      */
@@ -592,4 +637,5 @@
      * @param   phVfsSymlink    Where to optionally return the handle to the
      *                      newly create symbolic link.
+     * @note    Optional.  RTVFSDIROPS::pfnOpenObj will be used if NULL.
      * @sa      RTSymlinkCreate.
      */
@@ -619,5 +665,6 @@
      * @param   pObjInfo    Where to return the info on success.
      * @param   enmAddAttr  Which set of additional attributes to request.
-     *
+     * @note    Optional.  RTVFSDIROPS::pfnOpenObj and RTVFSOBJOPS::pfnQueryInfo
+     *          will be used if NULL.
      * @sa      RTPathQueryInfo, RTVFSOBJOPS::pfnQueryInfo
      */
@@ -1169,5 +1216,5 @@
 {
     /** Open directory flags (RTFILE_O_XXX). */
-    uint32_t                fOpenFile;
+    uint64_t                fOpenFile;
     /** To be defined. */
     uint32_t                fOpenDir;
Index: /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmvfs.cpp	(revision 69813)
@@ -736,11 +736,11 @@
 
 /**
- * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
- */
-static DECLCALLBACK(int) rtDvmVfsDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
+ * @interface_method_impl{RTVFSDIROPS,pfnOpen}
+ */
+static DECLCALLBACK(int) rtDvmVfsDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen, uint32_t fFlags, PRTVFSOBJ phVfsObj)
 {
     PRTDVMVFSDIR pThis = (PRTDVMVFSDIR)pvThis;
     RTDVMVOLUME  hVolume;
-    int rc = rtDvmVfsDir_FindEntry(pThis, pszFilename, &hVolume);
+    int rc = rtDvmVfsDir_FindEntry(pThis, pszEntry, &hVolume);
     if (RT_SUCCESS(rc))
     {
@@ -749,13 +749,43 @@
             || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
         {
-            if (   !(fOpen & RTFILE_O_WRITE)
-                || !pThis->pVfsVol->fReadOnly)
-                rc = rtDvmVfsCreateFileForVolume(pThis->pVfsVol, hVolume, fOpen, phVfsFile);
+            if (fFlags & (RTVFSOBJ_F_OPEN_FILE | RTVFSOBJ_F_OPEN_DEV_BLOCK))
+            {
+                if (   !(fOpen & RTFILE_O_WRITE)
+                    || !pThis->pVfsVol->fReadOnly)
+                {
+                    RTVFSFILE hVfsFile;
+                    rc = rtDvmVfsCreateFileForVolume(pThis->pVfsVol, hVolume, fOpen, &hVfsFile);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                        RTVfsFileRelease(hVfsFile);
+                        AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                    }
+                }
+                else
+                    rc = VERR_WRITE_PROTECT;
+            }
             else
-                rc = VERR_WRITE_PROTECT;
+                rc = VERR_IS_A_FILE;
         }
         else
             rc = VERR_ALREADY_EXISTS;
         RTDvmVolumeRelease(hVolume);
+    }
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
+ */
+static DECLCALLBACK(int) rtDvmVfsDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
+{
+    RTVFSOBJ hVfsObj;
+    int rc = rtDvmVfsDir_Open(pvThis, pszFilename, fOpen, RTVFSOBJ_F_OPEN_FILE, &hVfsObj);
+    if (RT_SUCCESS(rc))
+    {
+        *phVfsFile = RTVfsObjToFile(hVfsObj);
+        RTVfsObjRelease(hVfsObj);
     }
     return rc;
@@ -983,4 +1013,5 @@
         RTVFSOBJSETOPS_VERSION
     },
+    rtDvmVfsDir_Open,
     rtDvmVfsDir_TraversalOpen,
     rtDvmVfsDir_OpenFile,
Index: /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/fs/fatvfs.cpp	(revision 69813)
@@ -2074,4 +2074,5 @@
 static int rtFsFatObj_SetMode(PRTFSFATOBJ pThis, RTFMODE fMode, RTFMODE fMask)
 {
+    __debugbreak();
 #if 0
     if (fMask != ~RTFS_TYPE_MASK)
@@ -4054,7 +4055,145 @@
 
 /**
+ * @interface_method_impl{RTVFSDIROPS,pfnOpen}
+ */
+static DECLCALLBACK(int) rtFsFatDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
+                                         uint32_t fFlags, PRTVFSOBJ phVfsObj)
+{
+    PRTFSFATDIR     pThis   = (PRTFSFATDIR)pvThis;
+    PRTFSFATDIRSHRD pShared = pThis->pShared;
+
+    /*
+     * Try open existing file.
+     */
+    uint32_t    offEntryInDir;
+    bool        fLong;
+    FATDIRENTRY DirEntry;
+    int rc = rtFsFatDirShrd_FindEntry(pShared, pszEntry, &offEntryInDir, &fLong, &DirEntry);
+    if (RT_SUCCESS(rc))
+    {
+        switch (DirEntry.fAttrib & (FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME))
+        {
+            case 0:
+                if (fFlags & RTVFSOBJ_F_OPEN_FILE)
+                {
+                    if (   !(DirEntry.fAttrib & FAT_ATTR_READONLY)
+                        || !(fOpen & RTFILE_O_WRITE))
+                    {
+                        if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
+                            || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
+                            || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+                        {
+                            RTVFSFILE hVfsFile;
+                            rc = rtFsFatFile_New(pShared->Core.pVol, pShared, &DirEntry, offEntryInDir, fOpen, &hVfsFile);
+                            if (RT_SUCCESS(rc))
+                            {
+                                *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                                RTVfsFileRelease(hVfsFile);
+                                AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                            }
+                        }
+                        else
+                            rc = VERR_ALREADY_EXISTS;
+                    }
+                    else
+                        rc = VERR_ACCESS_DENIED;
+                }
+                else
+                    rc = VERR_IS_A_FILE;
+                break;
+
+            case FAT_ATTR_DIRECTORY:
+                if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
+                {
+                    if (   !(DirEntry.fAttrib & FAT_ATTR_READONLY)
+                        || !(fOpen & RTFILE_O_WRITE))
+                    {
+                        if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
+                            || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
+                        {
+                            RTVFSDIR hVfsDir;
+                            rc = rtFsFatDir_New(pShared->Core.pVol, pShared, &DirEntry, offEntryInDir,
+                                                RTFSFAT_GET_CLUSTER(&DirEntry, pShared->Core.pVol), UINT64_MAX /*offDisk*/,
+                                                DirEntry.cbFile, &hVfsDir);
+                            if (RT_SUCCESS(rc))
+                            {
+                                *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                                RTVfsDirRelease(hVfsDir);
+                                AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                            }
+                        }
+                        else if ((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+                            rc = VERR_INVALID_FUNCTION;
+                        else
+                            rc = VERR_ALREADY_EXISTS;
+                    }
+                    else
+                        rc = VERR_ACCESS_DENIED;
+                }
+                else
+                    rc = VERR_IS_A_DIRECTORY;
+                break;
+
+            default:
+                rc = VERR_PATH_NOT_FOUND;
+                break;
+        }
+    }
+    /*
+     * Create a file or directory?
+     */
+    else if (rc == VERR_FILE_NOT_FOUND)
+    {
+        if (   (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
+                || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
+                || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+            && (fFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
+        {
+            if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
+            {
+                rc = rtFsFatDirShrd_CreateEntry(pShared, pszEntry, FAT_ATTR_ARCHIVE, 0 /*cbInitial*/, &offEntryInDir, &DirEntry);
+                if (RT_SUCCESS(rc))
+                {
+                    RTVFSFILE hVfsFile;
+                    rc = rtFsFatFile_New(pShared->Core.pVol, pShared, &DirEntry, offEntryInDir, fOpen, &hVfsFile);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                        RTVfsFileRelease(hVfsFile);
+                        AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                    }
+                }
+            }
+            else if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
+            {
+                rc = rtFsFatDirShrd_CreateEntry(pShared, pszEntry, FAT_ATTR_ARCHIVE | FAT_ATTR_DIRECTORY,
+                                                pShared->Core.pVol->cbCluster, &offEntryInDir, &DirEntry);
+                if (RT_SUCCESS(rc))
+                {
+                    RTVFSDIR hVfsDir;
+                    rc = rtFsFatDir_New(pShared->Core.pVol, pShared, &DirEntry, offEntryInDir,
+                                        RTFSFAT_GET_CLUSTER(&DirEntry, pShared->Core.pVol), UINT64_MAX /*offDisk*/,
+                                        DirEntry.cbFile, &hVfsDir);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                        RTVfsDirRelease(hVfsDir);
+                        AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                    }
+                }
+            }
+            else
+                rc = VERR_VFS_UNSUPPORTED_CREATE_TYPE;
+        }
+    }
+
+    return rc;
+}
+
+
+/**
  * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
  */
-static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
+static DECLCALLBACK(int) rtFsFatDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
 {
     PRTFSFATDIR     pThis   = (PRTFSFATDIR)pvThis;
@@ -4639,4 +4778,5 @@
         RTVFSOBJSETOPS_VERSION
     },
+    rtFsFatDir_Open,
     rtFsFatDir_TraversalOpen,
     rtFsFatDir_OpenFile,
Index: /trunk/src/VBox/Runtime/common/fs/isovfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fs/isovfs.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/fs/isovfs.cpp	(revision 69813)
@@ -2993,7 +2993,146 @@
 
 /**
+ * @interface_method_impl{RTVFSDIROPS,pfnOpen}
+ */
+static DECLCALLBACK(int) rtFsIsoDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
+                                         uint32_t fFlags, PRTVFSOBJ phVfsObj)
+{
+    PRTFSISODIROBJ  pThis   = (PRTFSISODIROBJ)pvThis;
+    PRTFSISODIRSHRD pShared = pThis->pShared;
+
+    /*
+     * We cannot create or replace anything, just open stuff.
+     */
+    if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
+        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+        return VERR_WRITE_PROTECT;
+
+    /*
+     * Try open whatever it is.
+     */
+    int rc;
+    if (pShared->Core.pVol->enmType != RTFSISOVOLTYPE_UDF)
+    {
+        /*
+         * ISO 9660
+         */
+        PCISO9660DIRREC pDirRec;
+        uint64_t        offDirRec;
+        uint32_t        cDirRecs;
+        RTFMODE         fMode;
+        uint32_t        uVersion;
+        rc = rtFsIsoDir_FindEntry9660(pShared, pszEntry, &offDirRec, &pDirRec, &cDirRecs, &fMode, &uVersion);
+        Log2(("rtFsIsoDir_Open: FindEntry9660(,%s,) -> %Rrc\n", pszEntry, rc));
+        if (RT_SUCCESS(rc))
+        {
+            switch (fMode & RTFS_TYPE_MASK)
+            {
+                case RTFS_TYPE_FILE:
+                    if (fFlags & RTVFSOBJ_F_OPEN_FILE)
+                    {
+                        RTVFSFILE hVfsFile;
+                        rc = rtFsIsoFile_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs,
+                                                 offDirRec, fOpen, uVersion, &hVfsFile);
+                        if (RT_SUCCESS(rc))
+                        {
+                            *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                            RTVfsFileRelease(hVfsFile);
+                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                        }
+                    }
+                    else
+                        rc = VERR_IS_A_FILE;
+                    break;
+
+                case RTFS_TYPE_DIRECTORY:
+                    if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
+                    {
+                        RTVFSDIR hVfsDir;
+                        rc = rtFsIsoDir_New9660(pShared->Core.pVol, pShared, pDirRec, cDirRecs, offDirRec, &hVfsDir);
+                        if (RT_SUCCESS(rc))
+                        {
+                            *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                            RTVfsDirRelease(hVfsDir);
+                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                        }
+                    }
+                    else
+                        rc = VERR_IS_A_DIRECTORY;
+                    break;
+
+                case RTFS_TYPE_SYMLINK:
+                case RTFS_TYPE_DEV_BLOCK:
+                case RTFS_TYPE_DEV_CHAR:
+                case RTFS_TYPE_FIFO:
+                case RTFS_TYPE_SOCKET:
+                case RTFS_TYPE_WHITEOUT:
+                    rc = VERR_NOT_IMPLEMENTED;
+                    break;
+
+                default:
+                    rc = VERR_PATH_NOT_FOUND;
+                    break;
+            }
+        }
+    }
+    else
+    {
+        /*
+         * UDF
+         */
+        PCUDFFILEIDDESC pFid;
+        rc = rtFsIsoDir_FindEntryUdf(pShared, pszEntry, &pFid);
+        Log2(("rtFsIsoDir_Open: FindEntryUdf(,%s,) -> %Rrc\n", pszEntry, rc));
+        if (RT_SUCCESS(rc))
+        {
+            if (!(pFid->fFlags & UDF_FILE_FLAGS_DELETED))
+            {
+                if (!(pFid->fFlags & UDF_FILE_FLAGS_DIRECTORY))
+                {
+                    if (fFlags & RTVFSOBJ_F_OPEN_FILE)
+                    {
+                        RTVFSFILE hVfsFile;
+                        rc = rtFsIsoFile_NewUdf(pShared->Core.pVol, pShared, pFid, fOpen, &hVfsFile);
+                        if (RT_SUCCESS(rc))
+                        {
+                            *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                            RTVfsFileRelease(hVfsFile);
+                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                        }
+                    }
+                    else
+                        rc = VERR_IS_A_FILE;
+                }
+                else
+                {
+                    if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
+                    {
+                        RTVFSDIR hVfsDir;
+                        rc = rtFsIsoDir_NewUdf(pShared->Core.pVol, pShared, pFid, &hVfsDir);
+                        if (RT_SUCCESS(rc))
+                        {
+                            *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                            RTVfsDirRelease(hVfsDir);
+                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                        }
+                    }
+                    else
+                        rc = VERR_IS_A_DIRECTORY;
+                }
+            }
+            /* We treat UDF_FILE_FLAGS_DELETED like RTFS_TYPE_WHITEOUT for now. */
+            else
+                rc = VERR_PATH_NOT_FOUND;
+        }
+    }
+    return rc;
+
+}
+
+
+/**
  * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
  */
-static DECLCALLBACK(int) rtFsIsoDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
+static DECLCALLBACK(int) rtFsIsoDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
 {
     PRTFSISODIROBJ  pThis   = (PRTFSISODIROBJ)pvThis;
@@ -3654,4 +3793,5 @@
         RTVFSOBJSETOPS_VERSION
     },
+    rtFsIsoDir_Open,
     rtFsIsoDir_TraversalOpen,
     rtFsIsoDir_OpenFile,
Index: /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 69813)
@@ -352,4 +352,5 @@
 *********************************************************************************************************************************/
 DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis);
+static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir);
 
 
@@ -966,4 +967,17 @@
 
 
+RTDECL(RTVFSOBJTYPE)    RTVfsObjGetType(RTVFSOBJ hVfsObj)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    if (pThis != NIL_RTVFSOBJ)
+    {
+        AssertPtrReturn(pThis, RTVFSOBJTYPE_INVALID);
+        AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, RTVFSOBJTYPE_INVALID);
+        return pThis->pOps->enmType;
+    }
+    return RTVFSOBJTYPE_INVALID;
+}
+
+
 RTDECL(RTVFS)           RTVfsObjToVfs(RTVFSOBJ hVfsObj)
 {
@@ -1167,4 +1181,92 @@
 
 
+RTDECL(int)             RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
+{
+    /*
+     * Validate input.
+     */
+    RTVFSINTERNAL *pThis = hVfs;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
+
+    int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
+    if (RT_FAILURE(rc))
+        return rc;
+    AssertMsgReturn(   RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
+                    && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
+                    ("fObjFlags=%#x\n", fObjFlags),
+                    VERR_INVALID_FLAGS);
+    /*
+     * Parse the path, assume current directory is root since we've got no
+     * caller context here.
+     */
+    PRTVFSPARSEDPATH pPath;
+    rc = RTVfsParsePathA(pszPath, "/", &pPath);
+    if (RT_SUCCESS(rc))
+    {
+        if (pPath->cComponents > 0)
+        {
+            /*
+             * Tranverse the path, resolving the parent node, not
+             * checking for symbolic links in the final element.
+             */
+            RTVFSDIRINTERNAL *pVfsParentDir;
+            rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
+            if (RT_SUCCESS(rc))
+            {
+                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
+
+                /*
+                 * If we've got a trailing directory slash, use pfnOpenDir
+                 * instead of pfnOpenObj.
+                 */
+                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);
+                    }
+                }
+                else
+                {
+                    RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
+                    rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, phVfsObj);
+                    RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
+                }
+                RTVfsDirRelease(pVfsParentDir);
+            }
+        }
+        /*
+         * 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);
+    }
+    return rc;
+}
+
 
 RTDECL(int)         RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
@@ -1180,4 +1282,83 @@
 }
 
+
+/**
+ * Gets the RTVFSOBJSETOPS for the given base object.
+ *
+ * @returns Pointer to the vtable if supported by the type, otherwise NULL.
+ * @param   pThis               The base object.
+ */
+static PCRTVFSOBJSETOPS rtVfsObjGetSetOps(RTVFSOBJINTERNAL *pThis)
+{
+    switch (pThis->pOps->enmType)
+    {
+        case RTVFSOBJTYPE_DIR:
+            return &RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->pOps->ObjSet;
+        case RTVFSOBJTYPE_FILE:
+            return &RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->pOps->ObjSet;
+        case RTVFSOBJTYPE_SYMLINK:
+            return &RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->pOps->ObjSet;
+        default:
+            return NULL;
+    }
+}
+
+
+RTDECL(int)         RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
+
+    fMode = rtFsModeNormalize(fMode, NULL, 0);
+    if (!rtFsModeIsValid(fMode))
+        return VERR_INVALID_PARAMETER;
+
+    PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
+    AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
+
+    RTVfsLockAcquireWrite(pThis->hLock);
+    int rc = pObjSetOps->pfnSetMode(pThis->pvThis, fMode, fMask);
+    RTVfsLockReleaseWrite(pThis->hLock);
+    return rc;
+}
+
+
+RTDECL(int)         RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
+                                     PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
+
+    AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
+
+    PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
+    AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
+
+    RTVfsLockAcquireWrite(pThis->hLock);
+    int rc = pObjSetOps->pfnSetTimes(pThis->pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
+    RTVfsLockReleaseWrite(pThis->hLock);
+    return rc;
+}
+
+
+RTDECL(int)         RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
+
+    PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
+    AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
+
+    RTVfsLockAcquireWrite(pThis->hLock);
+    int rc = pObjSetOps->pfnSetOwner(pThis->pvThis, uid, gid);
+    RTVfsLockReleaseWrite(pThis->hLock);
+    return rc;
+}
 
 
@@ -2426,6 +2607,5 @@
 
     /*
-     * Parse the path, assume current directory is root since we've got no
-     * caller context here.
+     * Parse the relative path.
      */
     PRTVFSPARSEDPATH pPath;
@@ -2481,4 +2661,92 @@
 }
 
+
+RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
+{
+    /*
+     * Validate input.
+     */
+    RTVFSDIRINTERNAL *pThis = hVfsDir;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
+    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+    AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
+
+    int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
+    if (RT_FAILURE(rc))
+        return rc;
+    AssertMsgReturn(   RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
+                    && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
+                    ("fObjFlags=%#x\n", fObjFlags),
+                    VERR_INVALID_FLAGS);
+
+    /*
+     * Parse the relative path.
+     */
+    PRTVFSPARSEDPATH pPath;
+    rc = RTVfsParsePathA(pszPath, NULL, &pPath);
+    if (RT_SUCCESS(rc))
+    {
+        if (pPath->cComponents > 0)
+        {
+            /*
+             * Tranverse the path, resolving the parent node, not
+             * checking for symbolic links in the final element.
+             */
+            RTVFSDIRINTERNAL *pVfsParentDir;
+            rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
+            if (RT_SUCCESS(rc))
+            {
+                const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
+
+                /*
+                 * If we've got a trailing directory slash, use pfnOpenDir
+                 * instead of pfnOpenObj.
+                 */
+                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);
+                    }
+                }
+                else
+                {
+                    RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
+                    rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, phVfsObj);
+                    RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
+                }
+                RTVfsDirRelease(pVfsParentDir);
+            }
+        }
+        /*
+         * 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;
+            RTVfsLockAcquireWrite(pThis->Base.hLock);
+            rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", 0 /** @todo fFlags*/, &hVfsDir);
+            RTVfsLockReleaseWrite(pThis->Base.hLock);
+            if (RT_SUCCESS(rc))
+            {
+                *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                RTVfsDirRelease(hVfsDir);
+                AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+            }
+        }
+
+        RTVfsParsePathFree(pPath);
+    }
+    return rc;
+}
 
 
@@ -3245,5 +3513,5 @@
     RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
     Assert(cbInstance > 0);
-    Assert(fOpen & RTFILE_O_ACCESS_MASK);
+    Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
     AssertPtr(ppvInstance);
     AssertPtr(phVfsFile);
Index: /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 69813)
@@ -1114,4 +1114,118 @@
 
 
+RTDECL(int) RTVfsChainOpenObj(const char *pszSpec, uint64_t fFileOpen, uint32_t fObjFlags,
+                              PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    /*
+     * Validate input.
+     */
+    uint32_t offErrorIgn;
+    if (!poffError)
+        poffError = &offErrorIgn;
+    *poffError = 0;
+    AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
+    AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER);
+
+    int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
+    if (RT_FAILURE(rc))
+        return rc;
+    AssertMsgReturn(   RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
+                    && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
+                    ("fObjFlags=%#x\n", fObjFlags),
+                    VERR_INVALID_FLAGS);
+
+    /*
+     * Try for a VFS chain first, falling back on regular file system stuff if it's just a path.
+     */
+    PRTVFSCHAINSPEC pSpec = NULL;
+    if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1) == 0)
+    {
+        rc = RTVfsChainSpecParse(pszSpec,  0 /*fFlags*/, RTVFSOBJTYPE_DIR, &pSpec, poffError);
+        if (RT_FAILURE(rc))
+            return rc;
+
+        Assert(pSpec->cElements > 0);
+        if (   pSpec->cElements > 1
+            || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END)
+        {
+            const char *pszFinal = NULL;
+            RTVFSOBJ    hVfsObj  = NIL_RTVFSOBJ;
+            pSpec->fOpenFile = fFileOpen;
+            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &pszFinal, poffError, pErrInfo);
+            if (RT_SUCCESS(rc))
+            {
+                if (!pszFinal)
+                {
+                    *phVfsObj = hVfsObj;
+                    rc = VINF_SUCCESS;
+                }
+                else
+                {
+                    /*
+                     * Do a file open with the final path on the returned object.
+                     */
+                    RTVFS           hVfs    = RTVfsObjToVfs(hVfsObj);
+                    RTVFSDIR        hVfsDir = RTVfsObjToDir(hVfsObj);
+                    RTVFSFSSTREAM   hVfsFss = RTVfsObjToFsStream(hVfsObj);
+                    if (hVfs != NIL_RTVFS)
+                        rc = RTVfsObjOpen(hVfs, pszFinal, fFileOpen, fObjFlags, phVfsObj);
+                    else if (hVfsDir != NIL_RTVFSDIR)
+                        rc = RTVfsDirOpenObj(hVfsDir, pszFinal, fFileOpen, fObjFlags, phVfsObj);
+                    else if (hVfsFss != NIL_RTVFSFSSTREAM)
+                        rc = VERR_NOT_IMPLEMENTED;
+                    else
+                        rc = VERR_VFS_CHAIN_TYPE_MISMATCH_PATH_ONLY;
+                    RTVfsRelease(hVfs);
+                    RTVfsDirRelease(hVfsDir);
+                    RTVfsFsStrmRelease(hVfsFss);
+                    RTVfsObjRelease(hVfsObj);
+                }
+            }
+
+            RTVfsChainSpecFree(pSpec);
+            return rc;
+        }
+
+        /* Only a path element. */
+        pszSpec = pSpec->paElements[0].paArgs[0].psz;
+    }
+
+    /*
+     * Path to regular file system.
+     * Go via the directory VFS wrapper to avoid duplicating code.
+     */
+    RTVFSDIR hVfsParentDir = NIL_RTVFSDIR;
+    const char *pszFilename;
+    if (RTPathHasPath(pszSpec))
+    {
+        char *pszCopy = RTStrDup(pszSpec);
+        if (pszCopy)
+        {
+            RTPathStripFilename(pszCopy);
+            rc = RTVfsDirOpenNormal(pszCopy, 0 /*fOpen*/, &hVfsParentDir);
+            RTStrFree(pszCopy);
+        }
+        else
+            rc = VERR_NO_STR_MEMORY;
+        pszFilename = RTPathFilename(pszSpec);
+    }
+    else
+    {
+        pszFilename = pszSpec;
+        rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsParentDir);
+    }
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTVfsDirOpenObj(hVfsParentDir, pszFilename, fFileOpen, fObjFlags, phVfsObj);
+        RTVfsDirRelease(hVfsParentDir);
+    }
+
+    RTVfsChainSpecFree(pSpec);
+    return rc;
+}
+
+
 RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint32_t fOpen,
                               PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo)
@@ -1141,5 +1255,4 @@
             || pSpec->paElements[0].enmType != RTVFSOBJTYPE_END)
         {
-
             const char *pszFinal = NULL;
             RTVFSOBJ    hVfsObj  = NIL_RTVFSOBJ;
@@ -1150,5 +1263,5 @@
                 if (!pszFinal)
                 {
-                    /* Try convert it to a file object and we're done. */
+                    /* Try convert it to a directory object and we're done. */
                     *phVfsDir = RTVfsObjToDir(hVfsObj);
                     if (*phVfsDir)
@@ -1195,5 +1308,4 @@
     RTVfsChainSpecFree(pSpec);
     return rc;
-
 }
 
@@ -1630,5 +1742,5 @@
 {
     return pszSpec
-        && strcmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX) == 0;
+        && strncmp(pszSpec, RT_STR_TUPLE(RTVFSCHAIN_SPEC_PREFIX)) == 0;
 }
 
Index: /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp	(revision 69813)
@@ -305,7 +305,204 @@
 
 /**
+ * @interface_method_impl{RTVFSDIROPS,pfnOpenObj}
+ */
+static DECLCALLBACK(int) rtVfsStdDir_OpenObj(void *pvThis, const char *pszEntry, uint64_t fOpen,
+                                             uint32_t fFlags, PRTVFSOBJ phVfsObj)
+{
+    PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
+
+    /*
+     * This is subject to race conditions, but we haven't too much of a choice
+     * without going platform specific here (we'll do that eventually).
+     */
+    RTFSOBJINFO  ObjInfo;
+    int rc = RTDirRelPathQueryInfo(pThis->hDir, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+    if (RT_SUCCESS(rc))
+    {
+        switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+        {
+            case RTFS_TYPE_DIRECTORY:
+                if (!(fFlags & RTVFSOBJ_F_OPEN_DIRECTORY))
+                {
+                    if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
+                        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
+                        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+                    {
+                        RTDIR hSubDir;
+                        rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, fFlags, &hSubDir);
+                        if (RT_SUCCESS(rc))
+                        {
+                            RTVFSDIR hVfsDir;
+                            rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
+                            if (RT_SUCCESS(rc))
+                            {
+                                *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                                RTVfsDirRelease(hVfsDir);
+                                AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                            }
+                            else
+                                RTDirClose(hSubDir);
+                        }
+                    }
+                    else
+                        rc = VERR_ALREADY_EXISTS;
+                }
+                else
+                    rc = VERR_IS_A_DIRECTORY;
+                break;
+
+            case RTFS_TYPE_FILE:
+            case RTFS_TYPE_DEV_BLOCK:
+            case RTFS_TYPE_DEV_CHAR:
+            case RTFS_TYPE_FIFO:
+            case RTFS_TYPE_SOCKET:
+                switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+                {
+                    case RTFS_TYPE_FILE:
+                        rc = fFlags & RTVFSOBJ_F_OPEN_FILE      ? VINF_SUCCESS : VERR_IS_A_FILE;
+                        break;
+                    case RTFS_TYPE_DEV_BLOCK:
+                        rc = fFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
+                        break;
+                    case RTFS_TYPE_DEV_CHAR:
+                        rc = fFlags & 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 = fFlags & RTVFSOBJ_F_OPEN_FIFO      ? VINF_SUCCESS : VERR_IS_A_FIFO;
+                        break;
+                    case RTFS_TYPE_SOCKET:
+                        rc = fFlags & RTVFSOBJ_F_OPEN_SOCKET    ? VINF_SUCCESS : VERR_IS_A_SOCKET;
+                        break;
+                    default:
+                        rc = VERR_INVALID_FLAGS;
+                        break;
+                }
+                if (RT_SUCCESS(rc))
+                {
+                    if (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
+                        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
+                        || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+                    {
+                        RTFILE hFile;
+                        rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fOpen, &hFile);
+                        if (RT_SUCCESS(rc))
+                        {
+                            RTVFSFILE hVfsFile;
+                            rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
+                            if (RT_SUCCESS(rc))
+                            {
+                                *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                                RTVfsFileRelease(hVfsFile);
+                                AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                            }
+                            else
+                                RTFileClose(hFile);
+                        }
+                    }
+                    else
+                        rc = VERR_ALREADY_EXISTS;
+                }
+                break;
+
+            case RTFS_TYPE_SYMLINK:
+                if (fFlags & RTVFSOBJ_F_OPEN_SYMLINK)
+                {
+                    uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
+                    if (cRefs != UINT32_MAX)
+                    {
+                        RTVFSSYMLINK     hVfsSymlink;
+                        PRTVFSSTDSYMLINK pNewSymlink;
+                        size_t           cchSymlink = strlen(pszEntry);
+                        rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
+                                             NIL_RTVFS, NIL_RTVFSLOCK, &hVfsSymlink, (void **)&pNewSymlink);
+                        if (RT_SUCCESS(rc))
+                        {
+                            memcpy(pNewSymlink->szSymlink, pszEntry, cchSymlink);
+                            pNewSymlink->szSymlink[cchSymlink] = '\0';
+                            pNewSymlink->pDir = pThis;
+
+                            *phVfsObj = RTVfsObjFromSymlink(hVfsSymlink);
+                            RTVfsSymlinkRelease(hVfsSymlink);
+                            AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                        }
+                        else
+                            RTVfsDirRelease(pThis->hSelf);
+                    }
+                    else
+                        rc = VERR_INTERNAL_ERROR_2;
+                }
+                else
+                    rc = VERR_IS_A_SYMLINK;
+                break;
+
+            default:
+                break;
+        }
+    }
+    else if (   rc == VERR_FILE_NOT_FOUND
+             || rc == VERR_PATH_NOT_FOUND)
+    {
+        /*
+         * Consider file or directory creation.
+         */
+        if (   (   (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
+                || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
+                || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
+            && (fFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
+        {
+
+            if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
+            {
+                RTFILE hFile;
+                rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fOpen, &hFile);
+                if (RT_SUCCESS(rc))
+                {
+                    RTVFSFILE hVfsFile;
+                    rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *phVfsObj = RTVfsObjFromFile(hVfsFile);
+                        RTVfsFileRelease(hVfsFile);
+                        AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                    }
+                    else
+                        RTFileClose(hFile);
+                }
+            }
+            else if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
+            {
+                RTDIR hSubDir;
+                rc = RTDirRelDirCreate(pThis->hDir, pszEntry, (fOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT,
+                                       0 /* fFlags */, &hSubDir);
+                if (RT_SUCCESS(rc))
+                {
+                    RTVFSDIR hVfsDir;
+                    rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *phVfsObj = RTVfsObjFromDir(hVfsDir);
+                        RTVfsDirRelease(hVfsDir);
+                        AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
+                    }
+                    else
+                        RTDirClose(hSubDir);
+                }
+            }
+            else
+                rc = VERR_VFS_UNSUPPORTED_CREATE_TYPE;
+        }
+        else
+            rc = VERR_FILE_NOT_FOUND;
+    }
+    return rc;
+}
+
+
+/**
  * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
  */
-static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
+static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
 {
     PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
@@ -523,4 +720,5 @@
         RTVFSOBJSETOPS_VERSION
     },
+    rtVfsStdDir_OpenObj,
     rtVfsStdDir_TraversalOpen,
     rtVfsStdDir_OpenFile,
Index: /trunk/src/VBox/Runtime/tools/RTChMod.cpp
===================================================================
--- /trunk/src/VBox/Runtime/tools/RTChMod.cpp	(revision 69812)
+++ /trunk/src/VBox/Runtime/tools/RTChMod.cpp	(revision 69813)
@@ -29,14 +29,14 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
-#include <iprt/path.h>
+#include <iprt/buildconfig.h>
 #include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
 #include <iprt/initterm.h>
 #include <iprt/message.h>
-
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
 #include <iprt/vfs.h>
-#include <iprt/string.h>
-#include <iprt/stream.h>
-#include <iprt/getopt.h>
-#include <iprt/buildconfig.h>
 
 
@@ -64,4 +64,5 @@
     kRTCmdChModNoise_Verbose
 } RTCMDCHMODNOISE;
+
 
 typedef struct RTCMDCHMODOPTS
@@ -131,13 +132,13 @@
     else
     {
-        /* Try via parent first as that's generally faster and more reliable. */
-        RTVFSDIR        hVfsDir;
-        const char     *pszChild;
+        RTVFSOBJ        hVfsObj;
         uint32_t        offError;
         RTERRINFOSTATIC ErrInfo;
-        rc = RTVfsChainOpenParentDir(pszPath, 0 /*fOpen*/, &hVfsDir, &pszChild, &offError, RTErrInfoInitStatic(&ErrInfo));
+        rc = RTVfsChainOpenObj(pszPath, RTFILE_O_ACCESS_ATTR_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
+                               RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_FOLLOW_LINK,
+                               &hVfsObj, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_SUCCESS(rc))
         {
-            rc = RTVfsDirQueryPathInfo(hVfsDir, pszChild, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+            rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
             if (RT_SUCCESS(rc))
             {
@@ -146,33 +147,15 @@
                 if (fChanges)
                 {
-                    rc = VERR_NOT_IMPLEMENTED; //rc = RTVfsDirSetPathMode(hVfsDir, pszChild, fNewMode, RTPATH_F_FOLLOW_LINK);
+                    rc = RTVfsObjSetMode(hVfsObj, fNewMode, RTCHMOD_SET_ALL_MASK);
                     if (RT_FAILURE(rc))
-                        RTMsgError("RTVfsDirSetPathMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
-                }
-            }
-            RTVfsDirRelease(hVfsDir);
-        }
-        /* If we have no child part, work on the chain as a whole. */
-        else if (   rc == VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT
-                 || rc == VERR_VFS_CHAIN_NOT_PATH_ONLY)
-        {
-            rc = RTVfsChainQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
-                                     &offError, RTErrInfoInitStatic(&ErrInfo));
-            if (RT_SUCCESS(rc))
-            {
-                RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
-                fChanges = fNewMode != ObjInfo.Attr.fMode;
-                if (fChanges)
-                {
-                    rc = VERR_NOT_IMPLEMENTED; //rc = RTVfsChainSetMode(pszPath, fNewMode, &offError, RTErrInfoInitStatic(&ErrInfo));
-                    if (RT_FAILURE(rc))
-                        RTMsgError("RTVfsChainSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
+                        RTMsgError("RTVfsObjSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
                 }
             }
             else
-                RTVfsChainMsgError("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
+                RTVfsChainMsgError("RTVfsObjQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
+            RTVfsObjRelease(hVfsObj);
         }
-        else /** @todo we could implement a fallback here so we don't require a final path element. */
-            RTVfsChainMsgError("RTVfsChainOpenParentDir", pszPath, rc, offError, &ErrInfo.Core);
+        else
+            RTVfsChainMsgError("RTVfsChainOpenObject", pszPath, rc, offError, &ErrInfo.Core);
     }
 
@@ -219,7 +202,15 @@
 
     if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
-        return rtCmdChModOne(pOpts, pszPath);
-
-    /** @todo do root detection. */
+    {
+        /*
+         * Don't bother redoing the above work if its not necessary.
+         */
+        RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
+        if (fNewMode != ObjInfo.Attr.fMode)
+            return rtCmdChModOne(pOpts, pszPath);
+        if (pOpts->enmNoiseLevel >= kRTCmdChModNoise_Verbose)
+            RTPrintf("%s\n", pszPath);
+        return RTEXITCODE_SUCCESS;
+    }
 
     /*
