Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 66601)
+++ /trunk/include/iprt/err.h	(revision 66602)
@@ -1931,26 +1931,29 @@
  * directory (dir) objects. */
 #define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS_OR_DIR      (-22144)
+/** VFS chain element only provides file, I/O stream (ios), or
+ * directory (dir) objects. */
+#define VERR_VFS_CHAIN_ONLY_DIR_OR_VFS              (-22145)
 /** VFS chain element takes a file object as input. */
-#define VERR_VFS_CHAIN_TAKES_FILE                   (-22145)
+#define VERR_VFS_CHAIN_TAKES_FILE                   (-22146)
 /** VFS chain element takes a file or I/O stream (ios) object as input. */
-#define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS            (-22146)
+#define VERR_VFS_CHAIN_TAKES_FILE_OR_IOS            (-22147)
 /** VFS chain element takes a directory (dir) object as input. */
-#define VERR_VFS_CHAIN_TAKES_DIR                    (-22147)
+#define VERR_VFS_CHAIN_TAKES_DIR                    (-22148)
 /** VFS chain element takes a file system stream (fss) object as input. */
-#define VERR_VFS_CHAIN_TAKES_FSS                    (-22148)
+#define VERR_VFS_CHAIN_TAKES_FSS                    (-22149)
 /** VFS chain element takes a file system (vfs) object as input. */
-#define VERR_VFS_CHAIN_TAKES_VFS                    (-22149)
+#define VERR_VFS_CHAIN_TAKES_VFS                    (-22150)
 /** VFS chain element takes a directory (dir) or file system (vfs)
  * object as input. */
-#define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS             (-22150)
+#define VERR_VFS_CHAIN_TAKES_DIR_OR_VFS             (-22151)
 /** VFS chain element takes a directory (dir), file system stream (fss),
  * or file system (vfs) object as input. */
-#define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS      (-22151)
+#define VERR_VFS_CHAIN_TAKES_DIR_OR_FSS_OR_VFS      (-22152)
 /** VFS chain element only provides a read-only I/O stream, while the chain
  * requires write access. */
-#define VERR_VFS_CHAIN_READ_ONLY_IOS                (-22152)
+#define VERR_VFS_CHAIN_READ_ONLY_IOS                (-22153)
 /** VFS chain element only provides a read-only I/O stream, while the chain
  * read access. */
-#define VERR_VFS_CHAIN_WRITE_ONLY_IOS               (-22153)
+#define VERR_VFS_CHAIN_WRITE_ONLY_IOS               (-22154)
 /** @} */
 
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 66601)
+++ /trunk/include/iprt/mangling.h	(revision 66602)
@@ -2281,4 +2281,6 @@
 # define RTVfsChainElementRegisterProvider              RT_MANGLER(RTVfsChainElementRegisterProvider)
 # define RTVfsChainIsSpec                               RT_MANGLER(RTVfsChainIsSpec)
+# define RTVfsChainMsgError                             RT_MANGLER(RTVfsChainMsgError)
+# define RTVfsChainMsgErrorExitFailure                  RT_MANGLER(RTVfsChainMsgErrorExitFailure)
 # define RTVfsChainOpenFile                             RT_MANGLER(RTVfsChainOpenFile)
 # define RTVfsChainOpenIoStream                         RT_MANGLER(RTVfsChainOpenIoStream)
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 66601)
+++ /trunk/include/iprt/vfs.h	(revision 66602)
@@ -1140,10 +1140,10 @@
 #define RTVFSCHAIN_SPEC_PREFIX   ":iprtvfs:"
 
-RTDECL(int) RTVfsChainOpenVfs(      const char *pszSpec,                 PRTVFS          phVfs,     const char **ppszError);
-RTDECL(int) RTVfsChainOpenFsStream( const char *pszSpec,                 PRTVFSFSSTREAM  phVfsFss,  const char **ppszError);
-RTDECL(int) RTVfsChainOpenDir(      const char *pszSpec, uint64_t fOpen, PRTVFSDIR       phVfsDir,  const char **ppszError);
-RTDECL(int) RTVfsChainOpenFile(     const char *pszSpec, uint64_t fOpen, PRTVFSFILE      phVfsFile, const char **ppszError);
-RTDECL(int) RTVfsChainOpenIoStream( const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM  phVfsIos,  const char **ppszError);
-RTDECL(int) RTVfsChainOpenSymlink(  const char *pszSpec,                 PRTVFSSYMLINK   phVfsSym,  const char **ppszError);
+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);
+RTDECL(int) RTVfsChainOpenDir(const char *pszSpec, uint64_t fOpen, PRTVFSDIR phVfsDir, uint32_t *poffError, PRTERRINFO pErrInfo);
+RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint64_t fOpen, PRTVFSFILE phVfsFile, uint32_t *poffError, PRTERRINFO pErrInfo);
+RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos, uint32_t *poffError, PRTERRINFO pErrInfo);
+RTDECL(int) RTVfsChainOpenSymlink(const char *pszSpec, PRTVFSSYMLINK phVfsSym, uint32_t *poffError, PRTERRINFO pErrInfo);
 
 /**
@@ -1153,5 +1153,39 @@
  * @param   pszSpec         The alleged chain spec.
  */
-RTDECL(bool)    RTVfsChainIsSpec(const char *pszSpec);
+RTDECL(bool) RTVfsChainIsSpec(const char *pszSpec);
+
+/**
+ * Common code for reporting errors of a RTVfsChainOpen* API.
+ *
+ * @param   pszFunction The API called.
+ * @param   pszSpec     The VFS chain specification or file path passed to the.
+ * @param   rc          The return code.
+ * @param   offError    The error offset value returned (0 if not captured).
+ * @param   pErrInfo    Additional error information.  Optional.
+ *
+ * @sa      RTVfsChainMsgErrorExitFailure
+ * @sa      RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir,
+ *          RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink
+ */
+RTDECL(void) RTVfsChainMsgError(const char *pszFunction, const char *pszSpec, int rc, uint32_t offError, PRTERRINFO pErrInfo);
+
+/**
+ * Common code for reporting errors of a RTVfsChainOpen* API.
+ *
+ * @returns RTEXITCODE_FAILURE
+ *
+ * @param   pszFunction The API called.
+ * @param   pszSpec     The VFS chain specification or file path passed to the.
+ * @param   rc          The return code.
+ * @param   offError    The error offset value returned (0 if not captured).
+ * @param   pErrInfo    Additional error information.  Optional.
+ *
+ * @sa      RTVfsChainMsgError
+ * @sa      RTVfsChainOpenVfs, RTVfsChainOpenFsStream, RTVfsChainOpenDir,
+ *          RTVfsChainOpenFile, RTVfsChainOpenIoStream, RTVfsChainOpenSymlink
+ */
+RTDECL(RTEXITCODE) RTVfsChainMsgErrorExitFailure(const char *pszFunction, const char *pszSpec,
+                                                 int rc, uint32_t offError, PRTERRINFO pErrInfo);
+
 
 /** @} */
Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 66601)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 66602)
@@ -1079,7 +1079,9 @@
      *                          set to the pElement->offSpec on input, so it only
      *                          needs to be adjusted if an argument is at fault.
+     * @param   pErrInfo        Where to return additional error information, if
+     *                          available.  Optional.
      */
     DECLCALLBACKMEMBER(int, pfnValidate)(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                         PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError);
+                                         PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo);
 
     /**
@@ -1096,8 +1098,10 @@
      *                          set to the pElement->offSpec on input, so it only
      *                          needs to be adjusted if an argument is at fault.
+     * @param   pErrInfo        Where to return additional error information, if
+     *                          available.  Optional.
      */
     DECLCALLBACKMEMBER(int, pfnInstantiate)(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                             PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                            PRTVFSOBJ phVfsObj, uint32_t *poffError);
+                                            PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo);
 
     /**
@@ -1141,9 +1145,11 @@
  *                          RTVfsChainSpecFree.  Will always be set (unless
  *                          invalid parameters.)
- * @param   ppszError       On failure, this will point at the error location in
- *                          @a pszSpec.  Optional.
+ * @param   poffError       Where to return the offset into the input
+ *                          specification of what's causing trouble.  Always
+ *                          set, unless this argument causes an invalid pointer
+ *                          error.
  */
 RTDECL(int) RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType,
-                                PRTVFSCHAINSPEC *ppSpec, const char **ppszError);
+                                PRTVFSCHAINSPEC *ppSpec, uint32_t *poffError);
 
 /** @name RTVfsChainSpecParse
@@ -1163,7 +1169,9 @@
  *                      of what's causing trouble.  Always set, unless this
  *                      argument causes an invalid pointer error.
+ * @param   pErrInfo    Where to return additional error information, if
+ *                      available.  Optional.
  */
 RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec,
-                                        PRTVFSOBJ phVfsObj, uint32_t *poffError);
+                                        PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo);
 
 /**
@@ -1245,11 +1253,14 @@
  *
  * @returns IPRT status code.
- * @param   pSpec           The chain specification.
- * @param   pElement        The chain element specification to validate.
- * @param   poffError       Where to return error offset on failure.  This is
- *                          set to the pElement->offSpec on input, so it only
- *                          needs to be adjusted if an argument is at fault.
- */
-RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError);
+ * @param   pSpec       The chain specification.
+ * @param   pElement    The chain element specification to validate.
+ * @param   poffError   Where to return error offset on failure.  This is set to
+ *                      the pElement->offSpec on input, so it only needs to be
+ *                      adjusted if an argument is at fault.
+ * @param   pErrInfo    Where to return additional error information, if
+ *                      available.  Optional.
+ */
+RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement,
+                                                 uint32_t *poffError, PRTERRINFO pErrInfo);
 
 
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 66601)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 66602)
@@ -428,4 +428,5 @@
 	common/filesystem/filesystem.cpp \
 	common/filesystem/filesystemext.cpp \
+	$(if-expr "$(USERNAME)"=="bird",common/filesystem/fatvfs.cpp) \
 	common/ldr/ldr.cpp \
 	common/ldr/ldrELF.cpp \
@@ -608,4 +609,5 @@
 	common/vfs/vfsmemory.cpp \
 	common/vfs/vfsmisc.cpp \
+	common/vfs/vfsmsg.cpp \
 	common/vfs/vfsreadahead.cpp \
 	common/vfs/vfsstdfile.cpp \
Index: /trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/filesystem/fatvfs.cpp	(revision 66602)
@@ -463,7 +463,7 @@
  * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
  */
-static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, PRTVFSDIR phVfsDir)
-{
-    RT_NOREF(pvThis, pszSubDir, phVfsDir);
+static DECLCALLBACK(int) rtFsFatDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
+{
+    RT_NOREF(pvThis, pszSubDir, fFlags, phVfsDir);
     return VERR_NOT_IMPLEMENTED;
 }
@@ -516,4 +516,5 @@
 static DECLCALLBACK(int) rtFsFatDir_RewindDir(void *pvThis)
 {
+    RT_NOREF(pvThis);
     return VERR_NOT_IMPLEMENTED;
 }
@@ -526,4 +527,5 @@
                                             RTFSOBJATTRADD enmAddAttr)
 {
+    RT_NOREF(pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
     return VERR_NOT_IMPLEMENTED;
 }
@@ -571,4 +573,5 @@
 static DECLCALLBACK(void) rtFsFatVol_Destroy(void *pvThis)
 {
+    RT_NOREF(pvThis);
 }
 
@@ -579,4 +582,5 @@
 static DECLCALLBACK(int) rtFsFatVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
 {
+    RT_NOREF(pvThis, phVfsDir);
     return VERR_NOT_IMPLEMENTED;
 }
@@ -604,2 +608,119 @@
 };
 
+
+
+RTDECL(int) RTFsFatVolOpen(RTVFSFILE hVfsFileIn, bool fReadOnly, PRTVFS phVfs, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(hVfsFileIn, fReadOnly, pErrInfo, phVfs);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
+ */
+static DECLCALLBACK(int) rtVfsChainFatVol_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
+                                                   PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg);
+
+    /*
+     * Basic checks.
+     */
+    if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
+        return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
+    if (   pElement->enmType != RTVFSOBJTYPE_VFS
+        && pElement->enmType != RTVFSOBJTYPE_DIR)
+        return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
+    if (pElement->cArgs > 1)
+        return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
+
+    /*
+     * Parse the flag if present, save in pElement->uProvider.
+     */
+    bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
+    if (pElement->cArgs > 0)
+    {
+        const char *psz = pElement->paArgs[0].psz;
+        if (*psz)
+        {
+            if (!strcmp(psz, "ro"))
+                fReadOnly = true;
+            else if (!strcmp(psz, "rw"))
+                fReadOnly = false;
+            else
+            {
+                *poffError = pElement->paArgs[0].offSpec;
+                return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
+            }
+        }
+    }
+
+    pElement->uProvider = fReadOnly;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
+ */
+static DECLCALLBACK(int) rtVfsChainFatVol_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
+                                                      PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
+                                                      PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, poffError);
+
+    int         rc;
+    RTVFSFILE   hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
+    if (hVfsFileIn != NIL_RTVFSFILE)
+    {
+        RTVFS hVfs;
+        rc = RTFsFatVolOpen(hVfsFileIn, pElement->uProvider != false, &hVfs, pErrInfo);
+        RTVfsFileRelease(hVfsFileIn);
+        if (RT_SUCCESS(rc))
+        {
+            *phVfsObj = RTVfsObjFromVfs(hVfs);
+            RTVfsRelease(hVfs);
+            if (*phVfsObj != NIL_RTVFSOBJ)
+                return VINF_SUCCESS;
+            rc = VERR_VFS_CHAIN_CAST_FAILED;
+        }
+    }
+    else
+        rc = VERR_VFS_CHAIN_CAST_FAILED;
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
+ */
+static DECLCALLBACK(bool) rtVfsChainFatVol_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
+                                                           PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
+                                                           PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
+{
+    RT_NOREF(pProviderReg, pSpec, pReuseSpec);
+    if (   pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
+        || !pReuseElement->paArgs[0].uProvider)
+        return true;
+    return false;
+}
+
+
+/** VFS chain element 'file'. */
+static RTVFSCHAINELEMENTREG g_rtVfsChainFatVolReg =
+{
+    /* uVersion = */            RTVFSCHAINELEMENTREG_VERSION,
+    /* fReserved = */           0,
+    /* pszName = */             "fat",
+    /* ListEntry = */           { NULL, NULL },
+    /* pszHelp = */             "Open a FAT file system, requires a file object on the left side.\n"
+                                "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
+    /* pfnValidate = */         rtVfsChainFatVol_Validate,
+    /* pfnInstantiate = */      rtVfsChainFatVol_Instantiate,
+    /* pfnCanReuseElement = */  rtVfsChainFatVol_CanReuseElement,
+    /* uEndMarker = */          RTVFSCHAINELEMENTREG_VERSION
+};
+
+RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainFatVolReg, rtVfsChainFatVolReg);
+
Index: /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 66602)
@@ -66,5 +66,6 @@
 
 
-RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+RTDECL(int) RTVfsChainValidateOpenFileOrIoStream(PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement,
+                                                 uint32_t *poffError, PRTERRINFO pErrInfo)
 {
     if (pElement->cArgs < 1)
@@ -101,11 +102,22 @@
     if (   pElement->cArgs == 2
         || RT_FAILURE(RTFileModeToFlagsEx(pszAccess, "open-create", "", &pElement->uProvider)))
+    {
         *poffError = pElement->paArgs[1].offSpec;
+        rc = RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected valid access flags: 'r', 'rw', or 'w'");
+    }
     else if (   pElement->cArgs == 3
              || RT_FAILURE(RTFileModeToFlagsEx(pszAccess, pszDisp, "", &pElement->uProvider)))
+    {
         *poffError = pElement->paArgs[2].offSpec;
+        rc = RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT,
+                          "Expected valid open disposition: create, create-replace, open, open-create, open-append, open-truncate");
+    }
     else
+    {
         *poffError = pElement->paArgs[3].offSpec;
-    return VERR_VFS_CHAIN_INVALID_ARGUMENT;
+        rc = RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected valid sharing flags: nr, nw, nrw, d");
+
+    }
+    return rc;
 }
 
@@ -115,5 +127,5 @@
  */
 static DECLCALLBACK(int) rtVfsChainOpen_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
 {
     RT_NOREF(pProviderReg);
@@ -140,5 +152,5 @@
             {
                 pElement->pProvider = pNewProvider;
-                return pNewProvider->pfnValidate(pNewProvider, pSpec, pElement, poffError);
+                return pNewProvider->pfnValidate(pNewProvider, pSpec, pElement, poffError, pErrInfo);
             }
             return VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT;
@@ -154,5 +166,5 @@
         && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
     {
-        int rc = RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError);
+        int rc = RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo);
         if (RT_SUCCESS(rc))
         {
@@ -181,7 +193,7 @@
 static DECLCALLBACK(int) rtVfsChainOpen_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                                     PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                                    PRTVFSOBJ phVfsObj, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+                                                    PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError, pErrInfo);
     AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
 
@@ -595,9 +607,11 @@
 
 RTDECL(int) RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType,
-                                PRTVFSCHAINSPEC *ppSpec, const char **ppszError)
-{
-    AssertPtrNullReturn(ppszError, VERR_INVALID_POINTER);
-    if (ppszError)
-        *ppszError = NULL;
+                                PRTVFSCHAINSPEC *ppSpec, uint32_t *poffError)
+{
+    if (poffError)
+    {
+        AssertPtrReturn(poffError, VERR_INVALID_POINTER);
+        *poffError = 0;
+    }
     AssertPtrReturn(ppSpec, VERR_INVALID_POINTER);
     *ppSpec = NULL;
@@ -729,5 +743,8 @@
     }
 
-#if 1
+#if 0
+    /*
+     * Dump the chain.  Useful for debugging the above code.
+     */
     RTAssertMsg2("dbg: cElements=%d rc=%Rrc\n", pSpec->cElements, rc);
     for (uint32_t i = 0; i < pSpec->cElements; i++)
@@ -739,5 +756,5 @@
             RTAssertMsg2(j == 0 ? (cArgs > 1 ? " [%s" : " [%s]") : j + 1 < cArgs ? ", %s" : ", %s]",
                          pSpec->paElements[i].paArgs[j].psz);
-        //RTAssertMsg2(" offSpec=%d cchSpec=%d", pSpec->paElements[i].offSpec, pSpec->paElements[i].cchSpec);
+        RTAssertMsg2(" offSpec=%d cchSpec=%d", pSpec->paElements[i].offSpec, pSpec->paElements[i].cchSpec);
         RTAssertMsg2(" spec: %.*s\n", pSpec->paElements[i].cchSpec, &pszSpec[pSpec->paElements[i].offSpec]);
     }
@@ -752,6 +769,6 @@
     else
     {
-        if (ppszError)
-            *ppszError = pszSrc;
+        if (poffError)
+            *poffError = (uint32_t)(pszSrc - pszSpec);
         RTVfsChainSpecFree(pSpec);
     }
@@ -811,5 +828,5 @@
 
 RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec,
-                                        PRTVFSOBJ phVfsObj, uint32_t *poffError)
+                                        PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
 {
     AssertPtrReturn(poffError, VERR_INVALID_POINTER);
@@ -818,4 +835,5 @@
     *phVfsObj = NIL_RTVFSOBJ;
     AssertPtrReturn(pSpec, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER);
 
     /*
@@ -837,5 +855,5 @@
             if (pElement->pProvider)
             {
-                rc = pElement->pProvider->pfnValidate(pElement->pProvider, pSpec, pElement, poffError);
+                rc = pElement->pProvider->pfnValidate(pElement->pProvider, pSpec, pElement, poffError, pErrInfo);
                 if (RT_SUCCESS(rc))
                     continue;
@@ -916,5 +934,6 @@
                  */
                 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
-                rc = pElement->pProvider->pfnInstantiate(pElement->pProvider, pSpec, pElement, hPrevVfsObj, &hVfsObj, poffError);
+                rc = pElement->pProvider->pfnInstantiate(pElement->pProvider, pSpec, pElement, hPrevVfsObj,
+                                                         &hVfsObj, poffError, pErrInfo);
                 if (RT_FAILURE(rc))
                     break;
@@ -986,11 +1005,15 @@
 
 
-RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint64_t fOpen, PRTVFSFILE phVfsFile, const char **ppszError)
-{
+RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint64_t fOpen,
+                               PRTVFSFILE phVfsFile, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    uint32_t offErrorIgn;
+    if (!poffError)
+        poffError = &offErrorIgn;
+    *poffError = 0;
     AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
     AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER);
     AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
-    if (ppszError)
-        *ppszError = NULL;
+    AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER);
 
     /*
@@ -1015,12 +1038,11 @@
     {
         PRTVFSCHAINSPEC pSpec;
-        rc = RTVfsChainSpecParse(pszSpec,  0 /*fFlags*/, RTVFSOBJTYPE_FILE, &pSpec, ppszError);
+        rc = RTVfsChainSpecParse(pszSpec,  0 /*fFlags*/, RTVFSOBJTYPE_FILE, &pSpec, poffError);
         if (RT_SUCCESS(rc))
         {
             pSpec->fOpenFile = fOpen;
 
-            uint32_t offError = 0;
             RTVFSOBJ hVfsObj  = NIL_RTVFSOBJ;
-            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &offError);
+            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, poffError, pErrInfo);
             if (RT_SUCCESS(rc))
             {
@@ -1032,6 +1054,4 @@
                 RTVfsObjRelease(hVfsObj);
             }
-            else if (ppszError)
-                *ppszError = &pszSpec[offError];
 
             RTVfsChainSpecFree(pSpec);
@@ -1042,12 +1062,15 @@
 
 
-RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos, const char **ppszError)
-{
-    if (ppszError)
-        *ppszError = NULL;
-
+RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint64_t fOpen,
+                                   PRTVFSIOSTREAM phVfsIos, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    uint32_t offErrorIgn;
+    if (!poffError)
+        poffError = &offErrorIgn;
+    *poffError = 0;
     AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
     AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER);
     AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pErrInfo, VERR_INVALID_POINTER);
 
     /*
@@ -1078,12 +1101,11 @@
     {
         PRTVFSCHAINSPEC pSpec;
-        rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_IO_STREAM, &pSpec, ppszError);
+        rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_IO_STREAM, &pSpec, poffError);
         if (RT_SUCCESS(rc))
         {
             pSpec->fOpenFile = fOpen;
 
-            uint32_t offError = 0;
             RTVFSOBJ hVfsObj  = NIL_RTVFSOBJ;
-            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &offError);
+            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, poffError, pErrInfo);
             if (RT_SUCCESS(rc))
             {
@@ -1095,7 +1117,4 @@
                 RTVfsObjRelease(hVfsObj);
             }
-            else if (ppszError)
-                *ppszError = &pszSpec[offError];
-
             RTVfsChainSpecFree(pSpec);
         }
Index: /trunk/src/VBox/Runtime/common/vfs/vfsmsg.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsmsg.cpp	(revision 66602)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsmsg.cpp	(revision 66602)
@@ -0,0 +1,68 @@
+/* $Id$ */
+/** @file
+ * IPRT - Virtual File System, Error Messaging for Chains.
+ */
+
+/*
+ * Copyright (C) 2010-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/vfs.h>
+
+#include <iprt/err.h>
+#include <iprt/message.h>
+
+
+RTDECL(void) RTVfsChainMsgError(const char *pszFunction, const char *pszSpec, int rc, uint32_t offError, PRTERRINFO pErrInfo)
+{
+    if (RTErrInfoIsSet(pErrInfo))
+    {
+        if (offError > 0)
+            RTMsgError("%s failed with rc=%Rrc: %s\n"
+                       "    '%s'\n"
+                       "     %*s^\n",
+                       pszFunction, rc, pErrInfo->pszMsg, pszSpec, offError, "");
+        else
+            RTMsgError("%s failed to open '%s': %Rrc: %s\n", pszFunction, pszSpec, rc, pErrInfo->pszMsg);
+    }
+    else
+    {
+        if (offError > 0)
+            RTMsgError("%s failed with rc=%Rrc:\n"
+                       "    '%s'\n"
+                       "     %*s^\n",
+                       pszFunction, rc, pszSpec, offError, "");
+        else
+            RTMsgError("%s failed to open '%s': %Rrc\n", pszFunction, pszSpec, rc);
+    }
+}
+
+
+RTDECL(RTEXITCODE) RTVfsChainMsgErrorExitFailure(const char *pszFunction, const char *pszSpec,
+                                                 int rc, uint32_t offError, PRTERRINFO pErrInfo)
+{
+    RTVfsChainMsgError(pszFunction, pszSpec, rc, offError, pErrInfo);
+    return RTEXITCODE_FAILURE;
+}
+
Index: /trunk/src/VBox/Runtime/common/vfs/vfsreadahead.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsreadahead.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsreadahead.cpp	(revision 66602)
@@ -819,7 +819,7 @@
  */
 static DECLCALLBACK(int) rtVfsChainReadAhead_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                                      PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, poffError);
+                                                      PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, poffError, pErrInfo);
 
     /*
@@ -886,7 +886,7 @@
 static DECLCALLBACK(int) rtVfsChainReadAhead_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                                          PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                                         PRTVFSOBJ phVfsObj, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+                                                         PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError, pErrInfo);
     AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
 
Index: /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 66602)
@@ -517,5 +517,5 @@
  */
 static DECLCALLBACK(int) rtVfsChainStdFile_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                                    PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+                                                    PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
 {
     RT_NOREF(pProviderReg);
@@ -534,5 +534,5 @@
      * Join common cause with the 'open' provider.
      */
-    return RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError);
+    return RTVfsChainValidateOpenFileOrIoStream(pSpec, pElement, poffError, pErrInfo);
 }
 
@@ -543,7 +543,7 @@
 static DECLCALLBACK(int) rtVfsChainStdFile_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                                        PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                                       PRTVFSOBJ phVfsObj, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, pSpec, poffError);
+                                                       PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
     AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
 
Index: /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp	(revision 66602)
@@ -835,7 +835,7 @@
  */
 static DECLCALLBACK(int) rtVfsChainGunzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                                   PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, poffError);
+                                                   PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, poffError, pErrInfo);
 
     if (pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
@@ -860,7 +860,7 @@
 static DECLCALLBACK(int) rtVfsChainGunzip_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                                       PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                                      PRTVFSOBJ phVfsObj, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+                                                      PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError, pErrInfo);
     AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
 
@@ -918,5 +918,5 @@
  */
 static DECLCALLBACK(int) rtVfsChainGzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
-                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
 {
     RT_NOREF(pProviderReg);
@@ -955,5 +955,5 @@
         {
             *poffError = pElement->paArgs[0].offSpec;
-            return VERR_VFS_CHAIN_INVALID_ARGUMENT;
+            return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected compression level: 1-9, default, or fast");
         }
     }
@@ -970,7 +970,7 @@
 static DECLCALLBACK(int) rtVfsChainGzip_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
                                                     PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
-                                                    PRTVFSOBJ phVfsObj, uint32_t *poffError)
-{
-    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+                                                    PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError, pErrInfo);
     AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
 
Index: /trunk/src/VBox/Runtime/common/zip/tarcmd.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/zip/tarcmd.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/zip/tarcmd.cpp	(revision 66602)
@@ -195,20 +195,10 @@
         && strcmp(pOpts->pszFile, "-") != 0)
     {
-        const char *pszError;
-        rc = RTVfsChainOpenIoStream(pOpts->pszFile,
-                                    RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
-                                    &hVfsIos,
-                                    &pszError);
+        uint32_t        offError = 0;
+        RTERRINFOSTATIC ErrInfo;
+        rc = RTVfsChainOpenIoStream(pOpts->pszFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
+                                    &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_FAILURE(rc))
-        {
-            if (pszError && *pszError)
-                return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                      "    '%s'\n"
-                                      "     %*s^\n",
-                                      rc, pOpts->pszFile, pszError - pOpts->pszFile, "");
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "Failed with %Rrc opening the input archive '%s'", rc, pOpts->pszFile);
-        }
+            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pOpts->pszFile, rc, offError, &ErrInfo.Core);
     }
     else
Index: /trunk/src/VBox/Runtime/common/zip/unzipcmd.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/zip/unzipcmd.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/common/zip/unzipcmd.cpp	(revision 66602)
@@ -256,21 +256,11 @@
      * Open the input file.
      */
-    RTVFSIOSTREAM hVfsIos;
-    const char    *pszError;
-    int rc = RTVfsChainOpenIoStream(pOpts->pszFile,
-                                    RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
-                                    &hVfsIos,
-                                    &pszError);
-    if (RT_FAILURE(rc))
-    {
-        if (pszError && *pszError)
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                  "    '%s'\n"
-                                  "     %*s^\n",
-                                  rc, pOpts->pszFile, pszError - pOpts->pszFile, "");
-        return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                              "Failed with %Rrc opening the input archive '%s'", rc, pOpts->pszFile);
-    }
+    RTVFSIOSTREAM   hVfsIos;
+    uint32_t        offError = 0;
+    RTERRINFOSTATIC ErrInfo;
+    int rc = RTVfsChainOpenIoStream(pOpts->pszFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
+                                    &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
+    if (RT_FAILURE(rc))
+        return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pOpts->pszFile, rc, offError, &ErrInfo.Core);
 
     rc = RTZipPkzipFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, phVfsFss);
Index: /trunk/src/VBox/Runtime/tools/RTCat.cpp
===================================================================
--- /trunk/src/VBox/Runtime/tools/RTCat.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/tools/RTCat.cpp	(revision 66602)
@@ -131,18 +131,10 @@
     else
     {
-        const char *pszError;
-        rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, phVfsIos, &pszError);
+        uint32_t        offError = 0;
+        RTERRINFOSTATIC ErrInfo;
+        rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
+                                    phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_FAILURE(rc))
-        {
-            if (pszError && *pszError)
-                return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                      "    '%s'\n"
-                                      "     %*s^\n",
-                                      rc, pszFile, pszError - pszFile, "");
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'",
-                                  rc, pszFile);
-        }
+            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
     }
 
Index: /trunk/src/VBox/Runtime/tools/RTGzip.cpp
===================================================================
--- /trunk/src/VBox/Runtime/tools/RTGzip.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/tools/RTGzip.cpp	(revision 66602)
@@ -407,18 +407,10 @@
     else
     {
-        const char *pszError;
-        rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, phVfsIos, &pszError);
+        uint32_t        offError = 0;
+        RTERRINFOSTATIC ErrInfo;
+        rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
+                                    phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_FAILURE(rc))
-        {
-            if (pszError && *pszError)
-                return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                      "    '%s'\n"
-                                      "     %*s^\n",
-                                      rc, pszFile, pszError - pszFile, "");
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'",
-                                  rc, pszFile);
-        }
+            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
     }
 
Index: /trunk/src/VBox/Runtime/tools/RTManifest.cpp
===================================================================
--- /trunk/src/VBox/Runtime/tools/RTManifest.cpp	(revision 66601)
+++ /trunk/src/VBox/Runtime/tools/RTManifest.cpp	(revision 66602)
@@ -71,17 +71,10 @@
     else
     {
-        const char *pszError;
-        rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError);
+        uint32_t        offError = 0;
+        RTERRINFOSTATIC ErrInfo;
+        rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
+                                    &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_FAILURE(rc))
-        {
-            if (pszError && *pszError)
-                return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                      "    '%s'\n"
-                                      "     %*s^\n",
-                                      rc, pszManifest, pszError - pszManifest, "");
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "Failed with %Rrc opening the input manifest '%s'", rc, pszManifest);
-        }
+            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszManifest, rc, offError, &ErrInfo.Core);
     }
 
@@ -147,15 +140,11 @@
 {
     RTVFSIOSTREAM   hVfsIos;
-    const char     *pszError;
-    int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError);
+    uint32_t        offError = 0;
+    RTERRINFOSTATIC ErrInfo;
+    int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
+                                    &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
     if (RT_FAILURE(rc))
     {
-        if (pszError && *pszError)
-            RTMsgError("RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                       "    '%s'\n"
-                       "     %*s^\n",
-                       rc, pszFilename, pszError - pszFilename, "");
-        else
-            RTMsgError("Failed with %Rrc opening '%s'", rc, pszFilename);
+        RTVfsChainMsgError("RTVfsChainOpenIoStream", pszFilename, rc, offError, &ErrInfo.Core);
         return rc;
     }
@@ -201,18 +190,10 @@
     else
     {
-        const char *pszError;
+        RTERRINFOSTATIC ErrInfo;
+        uint32_t        offError;
         rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
-                                    &hVfsIos, &pszError);
+                                    &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
         if (RT_FAILURE(rc))
-        {
-            if (pszError && *pszError)
-                return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
-                                      "    '%s'\n"
-                                      "     %*s^\n",
-                                      rc, pszManifest, pszError - pszManifest, "");
-            return RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                  "Failed with %Rrc opening the manifest '%s'", rc, pszManifest);
-        }
+            return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszManifest, rc, offError, &ErrInfo.Core);
     }
 
