Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 33944)
+++ /trunk/include/iprt/err.h	(revision 33945)
@@ -4,5 +4,5 @@
 
 /*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -30,8 +30,13 @@
 #include <iprt/types.h>
 
-RT_C_DECLS_BEGIN
 
 /** @defgroup grp_rt_err            RTErr - Status Codes
  * @ingroup grp_rt
+ *
+ * The IPRT status codes are in two ranges: {0..999} and {22000..32766}.  The
+ * IPRT users are free to use the range {1000..21999}.  See RTERR_RANGE1_FIRST,
+ * RTERR_RANGE1_LAST, RTERR_RANGE2_FIRST, RTERR_RANGE2_LAST, RTERR_USER_FIRST
+ * and RTERR_USER_LAST.
+ *
  * @{
  */
@@ -176,4 +181,6 @@
  */
 #define RT_FAILURE_NP(rc)   ( !RT_SUCCESS_NP(rc) )
+
+RT_C_DECLS_BEGIN
 
 /**
@@ -386,5 +393,25 @@
 #endif /* IN_RING3 */
 
-/** @} */
+RT_C_DECLS_END
+
+/** @} */
+
+/** @name Status Code Ranges
+ * @{ */
+/** The first status code in the primary IPRT range. */
+#define RTERR_RANGE1_FIRST                  0
+/** The last status code in the primary IPRT range. */
+#define RTERR_RANGE1_LAST                   999
+
+/** The first status code in the secondary IPRT range. */
+#define RTERR_RANGE2_FIRST                  22000
+/** The last status code in the secondary IPRT range. */
+#define RTERR_RANGE2_LAST                   32766
+
+/** The first status code in the user range. */
+#define RTERR_USER_FIRST                    1000
+/** The last status code in the user range. */
+#define RTERR_USER_LAST                     21999
+/** @}  */
 
 
@@ -1281,19 +1308,46 @@
 /** @} */
 
-
 /** @name RTZip status codes
  * @{ */
 /** Generic zip error. */
-#define VERR_ZIP_ERROR                          (-950)
+#define VERR_ZIP_ERROR                          (-22000)
 /** The compressed data was corrupted. */
-#define VERR_ZIP_CORRUPTED                      (-951)
+#define VERR_ZIP_CORRUPTED                      (-22001)
 /** Ran out of memory while compressing or uncompressing. */
-#define VERR_ZIP_NO_MEMORY                      (-952)
+#define VERR_ZIP_NO_MEMORY                      (-22002)
 /** The compression format version is unsupported. */
-#define VERR_ZIP_UNSUPPORTED_VERSION            (-953)
+#define VERR_ZIP_UNSUPPORTED_VERSION            (-22003)
 /** The compression method is unsupported. */
-#define VERR_ZIP_UNSUPPORTED_METHOD             (-954)
+#define VERR_ZIP_UNSUPPORTED_METHOD             (-22004)
 /** The compressed data started with a bad header. */
-#define VERR_ZIP_BAD_HEADER                     (-955)
+#define VERR_ZIP_BAD_HEADER                     (-22005)
+/** @} */
+
+/** @name RTVfs status codes
+ * @{ */
+/** The VFS chain specification does not have a valid prefix. */
+#define VERR_VFS_CHAIN_NO_PREFIX                (-22100)
+/** The VFS chain specification is empty. */
+#define VERR_VFS_CHAIN_EMPTY                        (-22101)
+/** Expected an element. */
+#define VERR_VFS_CHAIN_EXPECTED_ELEMENT              (-22102)
+/** The VFS object type is not known. */
+#define VERR_VFS_CHAIN_UNKNOWN_TYPE                 (-22103)
+/** Expected a left paranthese. */
+#define VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES    (-22104)
+/** Expected a right paranthese. */
+#define VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES   (-22105)
+/** Expected a provider name. */
+#define VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME       (-22106)
+/** Expected an action (> or |). */
+#define VERR_VFS_CHAIN_EXPECTED_ACTION              (-22107)
+/** Only one action element is currently supported. */
+#define VERR_VFS_CHAIN_MULTIPLE_ACTIONS             (-22108)
+/** Expected to find a driving action (>), but there is none. */
+#define VERR_VFS_CHAIN_NO_ACTION                    (-22109)
+/** Expected pipe action. */
+#define VERR_VFS_CHAIN_EXPECTED_PIPE                (-22110)
+/** Unexpected action type. */
+#define VERR_VFS_CHAIN_UNEXPECTED_ACTION_TYPE       (-22111)
 /** @} */
 
@@ -1302,6 +1356,4 @@
 /** @} */
 
-RT_C_DECLS_END
-
 #endif
 
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 33944)
+++ /trunk/include/iprt/vfs.h	(revision 33945)
@@ -61,6 +61,13 @@
 /** Pointer to a VFS handle. */
 typedef RTVFS                          *PRTVFS;
-/** A NIL VFS directory handle. */
+/** A NIL VFS handle. */
 #define NIL_RTVFS                       ((RTVFS)~(uintptr_t)0)
+
+/** Virtual Filesystem base object handle. */
+typedef struct RTVFSOBJINTERNAL        *RTVFSOBJ;
+/** Pointer to a VFS base object handle. */
+typedef RTVFSOBJ                       *PRTVFSOBJ;
+/** A NIL VFS base object handle. */
+#define NIL_RTVFSOBJ                    ((RTVFSOBJ)~(uintptr_t)0)
 
 /** Virtual Filesystem directory handle. */
@@ -70,4 +77,11 @@
 /** A NIL VFS directory handle. */
 #define NIL_RTVFSDIR                    ((RTVFSDIR)~(uintptr_t)0)
+
+/** Virtual Filesystem filesystem stream handle. */
+typedef struct RTVFSFSSTREAMINTERNAL   *RTVFSFSSTREAM;
+/** Pointer to a VFS filesystem stream handle. */
+typedef RTVFSFSSTREAM                  *PRTVFSFSSTREAM;
+/** A NIL VFS filesystem stream handle. */
+#define NIL_RTVFSFSSTREAM               ((RTVFSFSSTREAM)~(uintptr_t)0)
 
 /** Virtual Filesystem I/O stream handle. */
@@ -119,4 +133,25 @@
 RTDECL(int)         RTVfsGetAttachment(RTVFS hVfs, uint32_t iOrdinal, PRTVFS *phVfsAttached, uint32_t *pfFlags,
                                        char *pszMountPoint, size_t cbMountPoint);
+
+
+/** @defgroup grp_vfs_dir           VFS Directory API
+ * @{
+ */
+
+RTDECL(RTVFS)           RTVfsObjToVfs(RTVFSOBJ hVfsObj);
+RTDECL(RTVFSFSSTREAM)   RTVfsObjToFsStream(RTVFSOBJ hVfsObj);
+RTDECL(RTVFSDIR)        RTVfsObjToDir(RTVFSOBJ hVfsObj);
+RTDECL(RTVFSIOSTREAM)   RTVfsObjToIoStream(RTVFSOBJ hVfsObj);
+RTDECL(RTVFSFILE)       RTVfsObjToFile(RTVFSOBJ hVfsObj);
+RTDECL(RTVFSSYMLINK)    RTVfsObjToSymlink(RTVFSOBJ hVfsObj);
+
+RTDECL(RTVFSOBJ)        RTVfsObjFromVfs(RTVFS hVfs);
+RTDECL(RTVFSOBJ)        RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss);
+RTDECL(RTVFSOBJ)        RTVfsObjFromDir(RTVFSDIR hVfsDir);
+RTDECL(RTVFSOBJ)        RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos);
+RTDECL(RTVFSOBJ)        RTVfsObjFromFile(RTVFSFILE hVfsFile);
+RTDECL(RTVFSOBJ)        RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym);
+
+/** @} */
 
 
@@ -399,4 +434,33 @@
 /** @} */
 
+
+/** @defgroup grp_rt_vfs_chain  VFS Chains
+ *
+ * VFS chains is for doing pipe like things with VFS objects from the command
+ * line.  Imagine you want to cat the readme.gz of an ISO you could do
+ * something like:
+ *      RTCat :iprtvfs:vfs(isofs,./mycd.iso)|ios(open,readme.gz)|ios(gunzip)
+ * or
+ *      RTCat :iprtvfs:ios(isofs,./mycd.iso,/readme.gz)|ios(gunzip)
+ *
+ * The "isofs", "open" and "gunzip" bits in the above examples are chain
+ * element providers registered with IPRT.  See RTVFSCHAINELEMENTREG for how
+ * these works.
+ *
+ * @{ */
+
+/** The path prefix used to identify an VFS chain specification. */
+#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, uint32_t fOpen, PRTVFSDIR       phVfsDir,  const char **ppszError);
+RTDECL(int) RTVfsChainOpenFile(     const char *pszSpec, uint32_t fOpen, PRTVFSFILE      phVfsFile, const char **ppszError);
+RTDECL(int) RTVfsChainOpenSymlink(  const char *pszSpec,                 PRTVFSSYMLINK   phVfsSym,  const char **ppszError);
+RTDECL(int) RTVfsChainOpenIoStream( const char *pszSpec, uint32_t fOpen, PRTVFSIOSTREAM  phVfsIos,  const char **ppszError);
+
+/** @}  */
+
+
 /** @} */
 
Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 33944)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 33945)
@@ -28,4 +28,6 @@
 
 #include <iprt/vfs.h>
+#include <iprt/err.h>
+#include <iprt/list.h>
 #include <iprt/param.h>
 
@@ -107,8 +109,16 @@
     /** Invalid type. */
     RTVFSOBJTYPE_INVALID = 0,
+    /** Pure base object.
+     * This is returned by the filesystem stream to represent directories,
+     * devices, fifos and similar that needs to be created. */
+    RTVFSOBJTYPE_BASE,
+    /** Virtual filesystem. */
+    RTVFSOBJTYPE_VFS,
+    /** Filesystem stream. */
+    RTVFSOBJTYPE_FS_STREAM,
+    /** Pure I/O stream. */
+    RTVFSOBJTYPE_IO_STREAM,
     /** Directory. */
     RTVFSOBJTYPE_DIR,
-    /** Pure I/O stream. */
-    RTVFSOBJTYPE_IOSTREAM,
     /** File. */
     RTVFSOBJTYPE_FILE,
@@ -120,4 +130,7 @@
     RTVFSOBJTYPE_32BIT_HACK = 0x7fffffff
 } RTVFSOBJTYPE;
+/** Pointer to a VFS object type. */
+typedef RTVFSOBJTYPE *PRTVFSOBJTYPE;
+
 
 /**
@@ -228,4 +241,43 @@
 
 /**
+ * The filesystem stream operations.
+ *
+ * @extends RTVFSOBJOPS
+ */
+typedef struct RTVFSFSSTREAMOPS
+{
+    /** The basic object operation.  */
+    RTVFSOBJOPS             Obj;
+    /** The structure version (RTVFSFSSTREAMOPS_VERSION). */
+    uint32_t                uVersion;
+    /** Reserved field, MBZ. */
+    uint32_t                fReserved;
+
+    /**
+     * Gets the next object in the stream.
+     *
+     * @returns IPRT status code.
+     * @retval  VINF_SUCCESS if a new object was retrieved.
+     * @retval  VERR_EOF when there are no more objects.
+     * @param   pvThis      The implementation specific directory data.
+     * @param   ppszName    Where to return the object name.  Must be freed by
+     *                      calling RTStrFree.
+     * @param   penmType    Where to return the object type.
+     * @param   hVfsObj     Where to return the object handle (referenced).
+     *                      This must be cast to the desired type before use.
+     */
+    DECLCALLBACKMEMBER(int, pfnNext)(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj);
+
+    /** Marks the end of the structure (RTVFSFSSTREAMOPS_VERSION). */
+    uintptr_t               uEndMarker;
+} RTVFSFSSTREAMOPS;
+/** Pointer to const object attribute setter operations. */
+typedef RTVFSFSSTREAMOPS const *PCRTVFSFSSTREAMOPS;
+
+/** The RTVFSFSSTREAMOPS structure version. */
+#define RTVFSFSSTREAMOPS_VERSION    RT_MAKE_U32_FROM_U8(0xff,0x3f,1,0)
+
+
+/**
  * The directory operations.
  *
@@ -365,5 +417,4 @@
     DECLCALLBACKMEMBER(int, pfnReadDir)(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr);
 
-
     /** Marks the end of the structure (RTVFSDIROPS_VERSION). */
     uintptr_t               uEndMarker;
@@ -372,5 +423,5 @@
 typedef RTVFSDIROPS const *PCRTVFSDIROPS;
 /** The RTVFSDIROPS structure version. */
-#define RTVFSDIROPS_VERSION         RT_MAKE_U32_FROM_U8(0xff,0x3f,1,0)
+#define RTVFSDIROPS_VERSION         RT_MAKE_U32_FROM_U8(0xff,0x4f,1,0)
 
 
@@ -409,5 +460,5 @@
 typedef RTVFSSYMLINKOPS const *PCRTVFSSYMLINKOPS;
 /** The RTVFSSYMLINKOPS structure version. */
-#define RTVFSSYMLINKOPS_VERSION     RT_MAKE_U32_FROM_U8(0xff,0x4f,1,0)
+#define RTVFSSYMLINKOPS_VERSION     RT_MAKE_U32_FROM_U8(0xff,0x5f,1,0)
 
 
@@ -524,5 +575,5 @@
 
 /** The RTVFSIOSTREAMOPS structure version. */
-#define RTVFSIOSTREAMOPS_VERSION    RT_MAKE_U32_FROM_U8(0xff,0x5f,1,0)
+#define RTVFSIOSTREAMOPS_VERSION    RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0)
 
 
@@ -596,5 +647,5 @@
 
 /** The RTVFSFILEOPS structure version. */
-#define RTVFSFILEOPS_VERSION        RT_MAKE_U32_FROM_U8(0xff,0x6f,1,0)
+#define RTVFSFILEOPS_VERSION        RT_MAKE_U32_FROM_U8(0xff,0x7f,1,0)
 
 /**
@@ -703,4 +754,259 @@
 /** @}  */
 
+
+/** @defgroup grp_rt_vfs_lowlevel_chain     VFS Chains
+ * @ref grp_rt_vfs_chain
+ * @{
+ */
+
+
+/**
+ * Chain element input actions.
+ */
+typedef enum RTVFSCHAINACTION
+{
+    /** Invalid action. */
+    RTVFSCHAINACTION_INVALID,
+    /** No action (start of the chain). */
+    RTVFSCHAINACTION_NONE,
+    /** Passive filtering (expressed by pipe symbol). */
+    RTVFSCHAINACTION_PASSIVE,
+    /** Push filtering (expressed by redirection-out symbol). */
+    RTVFSCHAINACTION_PUSH,
+    /** The end of the valid actions. */
+    RTVFSCHAINACTION_END,
+    /** Make sure it's a 32-bit type. */
+    RTVFSCHAINACTION_32BIT_HACK = 0x7fffffff
+} RTVFSCHAINACTION;
+
+
+/**
+ * VFS chain element specification.
+ */
+typedef struct RTVFSCHAINELEMSPEC
+{
+    /** The provider name. */
+    char               *pszProvider;
+    /** The input type. */
+    RTVFSOBJTYPE        enmTypeIn;
+    /** The output type. */
+    RTVFSOBJTYPE        enmTypeOut;
+    /** The action to take (or not). */
+    RTVFSCHAINACTION    enmAction;
+    /** The number of arguments. */
+    uint32_t            cArgs;
+    /** Arguments. */
+    char               **papszArgs;
+} RTVFSCHAINELEMSPEC;
+/** Pointer to a chain element specification. */
+typedef RTVFSCHAINELEMSPEC *PRTVFSCHAINELEMSPEC;
+/** Pointer to a const chain element specification. */
+typedef RTVFSCHAINELEMSPEC const *PCRTVFSCHAINELEMSPEC;
+
+
+/**
+ * Parsed VFS chain specification.
+ */
+typedef struct RTVFSCHAINSPEC
+{
+    /** The action element, UINT32_MAX if none.
+     * Currently we only support one action element (RTVFSCHAINACTION_PASSIVE
+     * is not considered). */
+    uint32_t            iActionElement;
+    /** The number of elements. */
+    uint32_t            cElements;
+    /** The elements. */
+    PRTVFSCHAINELEMSPEC paElements;
+} RTVFSCHAINSPEC;
+/** Pointer to a parsed VFS chain specification. */
+typedef RTVFSCHAINSPEC *PRTVFSCHAINSPEC;
+/** Pointer to a const, parsed VFS chain specification. */
+typedef RTVFSCHAINSPEC const *PCRTVFSCHAINSPEC;
+
+
+/**
+ * A chain element provider registration record.
+ */
+typedef struct RTVFSCHAINELEMENTREG
+{
+    /** The version (RTVFSCHAINELEMENTREG_VERSION). */
+    uint32_t                uVersion;
+    /** Reserved, MBZ. */
+    uint32_t                fReserved;
+    /** The provider name (unique). */
+    const char             *pszName;
+    /** For chaining the providers. */
+    RTLISTNODE              ListEntry;
+
+    /**
+     * Create a VFS from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   phVfs           Where to returned the VFS handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenVfs)(     PCRTVFSCHAINELEMSPEC pSpec,                 PRTVFS           phVfs);
+
+    /**
+     * Open a directory from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   phVfsDir        Where to returned the directory handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenDir)(     PCRTVFSCHAINELEMSPEC pSpec,                 PRTVFSDIR        phVfsDir);
+
+    /**
+     * Open a file from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   fOpen           The open flag.  Can be zero and the
+     *                          specification may modify it.
+     * @param   phVfsFile       Where to returned the file handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenFile)(    PCRTVFSCHAINELEMSPEC pSpec, uint32_t fOpen, PRTVFSFILE       phVfsFile);
+
+    /**
+     * Open a symlink from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   phVfsSym        Where to returned the symlink handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenSymlink)( PCRTVFSCHAINELEMSPEC pSpec,                 PRTVFSSYMLINK    phVfsSym);
+
+    /**
+     * Open a I/O stream from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   fOpen           The open flag.  Can be zero and the
+     *                          specification may modify it.
+     * @param   phVfsIos        Where to returned the I/O stream handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenIoStream)(PCRTVFSCHAINELEMSPEC pSpec, uint32_t fOpen, PRTVFSIOSTREAM   phVfsIos);
+
+    /**
+     * Open a filesystem stream from the given chain element specficiation.
+     *
+     * @returns IPRT status code.
+     * @param   pSpec           The chain element specification.
+     * @param   phVfsFss        Where to returned the filesystem stream handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnOpenFsStream)(PCRTVFSCHAINELEMSPEC pSpec,                 PRTVFSFSSTREAM   phVfsFss);
+
+    /** End marker (RTVFSCHAINELEMENTREG_VERSION). */
+    uintptr_t               uEndMarker;
+} RTVFSCHAINELEMENTREG;
+/** Pointer to a VFS chain element registration record. */
+typedef RTVFSCHAINELEMENTREG *PRTVFSCHAINELEMENTREG;
+/** Pointer to a const VFS chain element registration record. */
+typedef RTVFSCHAINELEMENTREG const *PCRTVFSCHAINELEMENTREG;
+
+/** The VFS chain element registration record version number. */
+#define RTVFSCHAINELEMENTREG_VERSION        RT_MAKE_U32_FROM_U8(0xff, 0x7f, 1, 0)
+
+
+/**
+ * Parses the specification.
+ *
+ * @returns IPRT status code.
+ * @param   pszSpec             The specification string to parse.
+ * @param   fFlags              Flags, see RTVFSCHAIN_PF_XXX.
+ * @param   enmLeadingAction    The only allowed leading action type.
+ * @param   enmTrailingAction   The only allowed trailing action type.
+ * @param   ppSpec              Where to return the pointer to the parsed
+ *                              specification.  This must be freed by calling
+ *                              RTVfsChainSpecFree.  Will always be set (unless
+ *                              invalid parameters.)
+ * @param   ppszError           On failure, this will point at the error
+ *                              location in @a pszSpec.  Optional.
+ */
+RTDECL(int)             RTVfsChainSpecParse(const char *pszSpec, RTVFSCHAINACTION enmLeadingAction,
+                                            RTVFSCHAINACTION enmTrailingAction,
+                                            PRTVFSCHAINSPEC *ppSpec, const char *ppszError);
+
+/** @name RTVfsChainSpecParse
+ * @{ */
+/** No real action is permitted, i.e. only passive filtering (aka pipe).  */
+#define RTVFSCHAIN_PF_NO_REAL_ACTION            RT_BIT_32(0)
+/** The specified leading action is optional. */
+#define RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL   RT_BIT_32(1)
+/** The specified trailing action is optional. */
+#define RTVFSCHAIN_PF_TRAILING_ACTION_OPTIONAL  RT_BIT_32(2)
+/** Mask of valid flags. */
+#define RTVFSCHAIN_PF_VALID_MASK                UINT32_C(0x00000007)
+/** @}*/
+
+/**
+ * Frees a parsed chain specification.
+ *
+ * @param   pSpec               What RTVfsChainSpecParse returned.  NULL is
+ *                              quietly ignored.
+ */
+RTDECL(void)            RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec);
+
+/**
+ * Registers a chain element provider.
+ *
+ * @returns IPRT status code
+ * @param   pRegRec             The registration record.
+ * @param   fFromCtor           Indicates where we're called from.
+ */
+RTDECL(int) RTVfsChainElementRegisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromCtor);
+
+/**
+ * Deregisters a chain element provider.
+ *
+ * @returns IPRT status code
+ * @param   pRegRec             The registration record.
+ * @param   fFromDtor           Indicates where we're called from.
+ */
+RTDECL(int) RTVfsChainElementDeregisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromDtor);
+
+
+/** @def RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER
+ * Automatically registers a chain element provider using a global constructor
+ * and destructor hack.
+ *
+ * @param   pRegRec     Pointer to the registration record.
+ * @param   name        Some unique variable name prefix.
+ */
+
+#ifdef __cplusplus
+/**
+ * Class used for registering a VFS chain element provider.
+ */
+class RTVfsChainElementAutoRegisterHack
+{
+    PRTVFSCHAINELEMENTREG m_pRegRec;
+    RTVfsChainElementAutoRegisterHack(PRTVFSCHAINELEMENTREG a_pRegRec)
+        : m_pRegRec(a_pRegRec)
+    {
+        int rc = RTVfsChainElementRegisterProvider(m_pRegRec, true);
+        if (RT_FAILURE(rc))
+            m_pRegRec = NULL;
+    }
+    ~RTVfsChainElementAutoRegisterHack()
+    {
+        RTVfsChainElementDeregisterProvider(m_pRegRec, true);
+        m_pRegRec = NULL;
+    }
+};
+
+# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \
+    static RTVfsChainElementAutoRegisterHack name ## AutoRegistrationHack(pRegRec)
+
+#else
+# define RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(pRegRec, name) \
+    extern void *name ## AutoRegistrationHack = \
+        &Sorry_but_RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER_does_not_work_in_c_source_files
+#endif
+
+
+/** @}  */
+
+
 /** @} */
 
@@ -709,5 +1015,2 @@
 #endif /* !___iprt_vfslowlevel_h */
 
-
-
-
Index: /trunk/src/VBox/Main/Global.cpp
===================================================================
--- /trunk/src/VBox/Main/Global.cpp	(revision 33944)
+++ /trunk/src/VBox/Main/Global.cpp	(revision 33945)
@@ -492,5 +492,7 @@
 
             /* try categorize it */
-            if (aVBoxStatus < 0 && aVBoxStatus > -1000)
+            if (   aVBoxStatus < 0
+                && (   aVBoxStatus > -1000
+                    || (aVBoxStatus < -22000 && aVBoxStatus > -32766) )
                 return VBOX_E_IPRT_ERROR;
             if (    aVBoxStatus <  VERR_PDM_NO_SUCH_LUN / 100 * 10
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 33944)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 33945)
@@ -370,4 +370,5 @@
 	common/time/timesup.cpp \
 	common/vfs/vfsbase.cpp \
+	common/vfs/vfschain.cpp \
 	common/vfs/vfsstdfile.cpp \
 	common/zip/zipgzip.cpp \
Index: /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 33944)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 33945)
@@ -48,13 +48,17 @@
 *   Defined Constants And Macros                                               *
 *******************************************************************************/
-#define RTVFS_MAGIC                 UINT32_C(0x11112222)
+#define RTVFSOBJ_MAGIC              UINT32_C(0x20109901)
+#define RTVFSOBJ_MAGIC_DEAD         (~RTVFSOBJ_MAGIC)
+#define RTVFS_MAGIC                 UINT32_C(0x20109902)
 #define RTVFS_MAGIC_DEAD            (~RTVFS_MAGIC)
-#define RTVFSDIR_MAGIC              UINT32_C(0x77778888)
+#define RTVFSFSSTREAM_MAGIC         UINT32_C(0x20109903)
+#define RTVFSFSSTREAM_MAGIC_DEAD    (~RTVFSFSSTREAM_MAGIC)
+#define RTVFSDIR_MAGIC              UINT32_C(0x20109904)
 #define RTVFSDIR_MAGIC_DEAD         (~RTVFSDIR_MAGIC)
-#define RTVFSFILE_MAGIC             UINT32_C(0x55556666)
+#define RTVFSFILE_MAGIC             UINT32_C(0x20109905)
 #define RTVFSFILE_MAGIC_DEAD        (~RTVFSFILE_MAGIC)
-#define RTVFSIOSTREAM_MAGIC         UINT32_C(0x33334444)
+#define RTVFSIOSTREAM_MAGIC         UINT32_C(0x20109906)
 #define RTVFSIOSTREAM_MAGIC_DEAD    (~RTVFSIOSTREAM_MAGIC)
-#define RTVFSSYMLINK_MAGIC          UINT32_C(0x9999aaaa)
+#define RTVFSSYMLINK_MAGIC          UINT32_C(0x20109907)
 #define RTVFSSYMLINK_MAGIC_DEAD     (~RTVFSSYMLINK_MAGIC)
 
@@ -65,44 +69,4 @@
 #define RTVFS_MAX_LINKS             20U
 
-
-/** Takes a write lock. */
-#define RTVFS_WRITE_LOCK(hSemRW)  \
-    do { \
-        if ((hSemRW) != NIL_RTSEMRW) \
-        { \
-            int rcSemEnter = RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT); \
-            AssertRC(rcSemEnter); \
-        } \
-    } while (0)
-
-/** Releases a write lock. */
-#define RTVFS_WRITE_UNLOCK(hSemRW)  \
-    do { \
-        if ((hSemRW) != NIL_RTSEMRW) \
-        { \
-            int rcSemLeave = RTSemRWReleaseWrite(hSemRW); \
-            AssertRC(rcSemLeave); \
-        } \
-    } while (0)
-
-/** Takes a read lock. */
-#define RTVFS_READ_LOCK(hSemRW)  \
-    do { \
-        if ((hSemRW) != NIL_RTSEMRW) \
-        { \
-            int rcSemEnter = RTSemRWRequestRead(hSemRW, RT_INDEFINITE_WAIT); \
-            AssertRC(rcSemEnter); \
-        } \
-    } while (0)
-
-/** Releases a read lock. */
-#define RTVFS_READ_UNLOCK(hSemRW)  \
-    do { \
-        if ((hSemRW) != NIL_RTSEMRW) \
-        { \
-            int rcSemLeave = RTSemRWReleaseRead(hSemRW); \
-            AssertRC(rcSemLeave); \
-        } \
-    } while (0)
 
 
@@ -113,5 +77,49 @@
 
 /**
+ * The VFS base object handle data.
+ *
+ * All other VFS handles are derived from this one.  The final handle type is
+ * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
+ */
+typedef struct RTVFSOBJINTERNAL
+{
+    /** The VFS magic (RTVFSOBJ_MAGIC). */
+    uint32_t                uMagic;
+    /** The number of references to this VFS object. */
+    uint32_t volatile       cRefs;
+    /** Pointer to the instance data. */
+    void                   *pvThis;
+    /** The vtable. */
+    PCRTVFSOBJOPS           pOps;
+    /** Read-write semaphore protecting all access to the VFS
+     * Only valid RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTSEMRW. */
+    RTSEMRW                 hSemRW;
+    /** Reference back to the VFS containing this object. */
+    RTVFS                   hVfs;
+} RTVFSOBJINTERNAL;
+
+
+/**
+ * The VFS filesystem stream handle data.
+ *
+ * @extends RTVFSOBJINTERNAL
+ */
+typedef struct RTVFSFSSTREAMINTERNAL
+{
+    /** The VFS magic (RTVFSFSTREAM_MAGIC). */
+    uint32_t                uMagic;
+    /** File open flags, at a minimum the access mask. */
+    uint32_t                fFlags;
+    /** The vtable. */
+    PCRTVFSFSSTREAMOPS      pOps;
+    /** The base object handle data. */
+    RTVFSOBJINTERNAL        Base;
+} RTVFSFSSTREAMINTERNAL;
+
+
+/**
  * The VFS handle data.
+ *
+ * @extends RTVFSOBJINTERNAL
  */
 typedef struct RTVFSINTERNAL
@@ -121,15 +129,8 @@
     /** Creation flags (RTVFS_C_XXX). */
     uint32_t                fFlags;
-    /** Pointer to the instance data. */
-    void                   *pvThis;
     /** The vtable. */
     PCRTVFSOPS              pOps;
-    /** Read-write semaphore protecting all access to the VFS
-     * Only valid RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTSEMRW. */
-    RTSEMRW                 hSemRW;
-    /** The number of references to this VFS.
-     * This count includes objects within the file system, so that the VFS
-     * won't be destroyed before all objects are closed. */
-    uint32_t volatile       cRefs;
+    /** The base object handle data. */
+    RTVFSOBJINTERNAL        Base;
 } RTVFSINTERNAL;
 
@@ -137,4 +138,6 @@
 /**
  * The VFS directory handle data.
+ *
+ * @extends RTVFSOBJINTERNAL
  */
 typedef struct RTVFSDIRINTERNAL
@@ -144,15 +147,8 @@
     /** Reserved for flags or something. */
     uint32_t                fReserved;
-    /** Pointer to the instance data. */
-    void                   *pvThis;
     /** The vtable. */
     PCRTVFSDIROPS           pOps;
-    /** The VFS RW sem if serialized. */
-    RTSEMRW                 hSemRW;
-    /** Reference back to the VFS containing this directory. */
-    RTVFS                   hVfs;
-    /** The number of references to this directory handle.  This does not
-     * include files or anything. */
-    uint32_t volatile       cRefs;
+    /** The base object handle data. */
+    RTVFSOBJINTERNAL        Base;
 } RTVFSDIRINTERNAL;
 
@@ -160,4 +156,6 @@
 /**
  * The VFS symbolic link handle data.
+ *
+ * @extends RTVFSOBJINTERNAL
  */
 typedef struct RTVFSSYMLINKINTERNAL
@@ -167,14 +165,8 @@
     /** Reserved for flags or something. */
     uint32_t                fReserved;
-    /** Pointer to the instance data. */
-    void                   *pvThis;
     /** The vtable. */
     PCRTVFSSYMLINKOPS       pOps;
-    /** The VFS RW sem if serialized. */
-    RTSEMRW                 hSemRW;
-    /** Reference back to the VFS containing this symbolic link. */
-    RTVFS                   hVfs;
-    /** The number of references to this symbolic link handle. */
-    uint32_t volatile       cRefs;
+    /** The base object handle data. */
+    RTVFSOBJINTERNAL        Base;
 } RTVFSSYMLINKINTERNAL;
 
@@ -183,5 +175,7 @@
  * The VFS I/O stream handle data.
  *
- * This is normally part of a type specific handle, like a file or pipe.
+ * This is often part of a type specific handle, like a file or pipe.
+ *
+ * @extends RTVFSOBJINTERNAL
  */
 typedef struct RTVFSIOSTREAMINTERNAL
@@ -191,14 +185,8 @@
     /** File open flags, at a minimum the access mask. */
     uint32_t                fFlags;
-    /** Pointer to the instance data. */
-    void                   *pvThis;
     /** The vtable. */
     PCRTVFSIOSTREAMOPS      pOps;
-    /** The VFS RW sem if serialized. */
-    RTSEMRW                 hSemRW;
-    /** Reference back to the VFS containing this directory. */
-    RTVFS                   hVfs;
-    /** The number of references to this file VFS. */
-    uint32_t volatile       cRefs;
+    /** The base object handle data. */
+    RTVFSOBJINTERNAL        Base;
 } RTVFSIOSTREAMINTERNAL;
 
@@ -221,43 +209,237 @@
 } RTVFSFILEINTERNAL;
 
+#if 0 /* later */
+
+/**
+ * The VFS pipe handle data.
+ *
+ * @extends RTVFSIOSTREAMINTERNAL
+ */
+typedef struct RTVFSPIPEINTERNAL
+{
+    /** The VFS magic (RTVFSPIPE_MAGIC). */
+    uint32_t                uMagic;
+    /** Reserved for flags or something. */
+    uint32_t                fReserved;
+    /** The vtable. */
+    PCRTVFSPIPEOPS          pOps;
+    /** The stream handle data. */
+    RTVFSIOSTREAMINTERNAL   Stream;
+} RTVFSPIPEINTERNAL;
+
+
+/**
+ * The VFS socket handle data.
+ *
+ * @extends RTVFSIOSTREAMINTERNAL
+ */
+typedef struct RTVFSSOCKETINTERNAL
+{
+    /** The VFS magic (RTVFSSOCKET_MAGIC). */
+    uint32_t                uMagic;
+    /** Reserved for flags or something. */
+    uint32_t                fReserved;
+    /** The vtable. */
+    PCRTVFSSOCKETOPS        pOps;
+    /** The stream handle data. */
+    RTVFSIOSTREAMINTERNAL   Stream;
+} RTVFSSOCKETINTERNAL;
+
+#endif /* later */
+
+
+/*
+ *
+ *  B A S E   O B J E C T
+ *  B A S E   O B J E C T
+ *  B A S E   O B J E C T
+ *
+ */
+
+/**
+ * Write locks the object.
+ *
+ * @param   pThis               The object to lock.
+ */
+DECLINLINE(void) rtVfsObjWriteLock(RTVFSOBJINTERNAL *pThis)
+{
+    if (pThis->hSemRW != NIL_RTSEMRW)
+    {
+        int rc = RTSemRWRequestWrite(pThis->hSemRW, RT_INDEFINITE_WAIT);
+        AssertRC(rc);
+    }
+}
+
+
+/**
+ * Undoing the effects of rtVfsObjWriteLock.
+ *
+ * @param   pThis               The object to lock.
+ */
+DECLINLINE(void) rtVfsObjWriteUnlock(RTVFSOBJINTERNAL *pThis)
+{
+    if (pThis->hSemRW != NIL_RTSEMRW)
+    {
+        int rc = RTSemRWReleaseWrite(pThis->hSemRW);
+        AssertRC(rc);
+    }
+}
+
+/**
+ * Read locks the object.
+ *
+ * @param   pThis               The object to lock.
+ */
+DECLINLINE(void) rtVfsObjReadLock(RTVFSOBJINTERNAL *pThis)
+{
+    if (pThis->hSemRW != NIL_RTSEMRW)
+    {
+        int rc = RTSemRWRequestRead(pThis->hSemRW, RT_INDEFINITE_WAIT);
+        AssertRC(rc);
+    }
+}
+
+
+/**
+ * Undoing the effects of rtVfsObjReadLock.
+ *
+ * @param   pThis               The object to lock.
+ */
+DECLINLINE(void) rtVfsObjReadUnlock(RTVFSOBJINTERNAL *pThis)
+{
+    if (pThis->hSemRW != NIL_RTSEMRW)
+    {
+        int rc = RTSemRWReleaseRead(pThis->hSemRW);
+        AssertRC(rc);
+    }
+}
+
 
 
 /**
  * Internal object retainer that asserts sanity in strict builds.
+ *
+ * @returns The new reference count.
+ * @param   pThis               The base object handle data.
+ */
+DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
+{
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    AssertMsg(cRefs > 1 && cRefs < _1M,
+              ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
+    return cRefs;
+}
+
+
+/**
+ * Internal object retainer that asserts sanity in strict builds.
+ *
+ * @param   pThis               The base object handle data.
+ */
+DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis)
+{
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    AssertMsg(cRefs > 1 && cRefs < _1M,
+              ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
+    NOREF(cRefs);
+}
+
+
+RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
+
+    return rtVfsObjRetain(pThis);
+}
+
+
+/**
+ * Does the actual object destruction for rtVfsObjRelease().
+ *
+ * @param   pThis               The object to destroy.
+ */
+static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
+{
+    RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
+
+    /*
+     * Invalidate the object.
+     */
+    rtVfsObjWriteLock(pThis);           /* paranoia */
+    switch (enmType)
+    {
+        case RTVFSOBJTYPE_BASE:
+            break;
+
+        case RTVFSOBJTYPE_VFS:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_FS_STREAM:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_IO_STREAM:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_DIR:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_FILE:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_SYMLINK:
+            ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
+            break;
+
+        case RTVFSOBJTYPE_INVALID:
+        case RTVFSOBJTYPE_END:
+        case RTVFSOBJTYPE_32BIT_HACK:
+            AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
+            break;
+        /* no default as we want gcc warnings. */
+    }
+    ASMAtomicWriteU32(&pThis->uMagic, RTVFSOBJ_MAGIC_DEAD);
+    rtVfsObjWriteUnlock(pThis);
+
+    /*
+     * Close the object and free the handle.
+     */
+    int rc = pThis->pOps->pfnClose(pThis->pvThis);
+    AssertRC(rc);
+    RTMemFree(pThis);
+}
+
+
+/**
+ * Internal object releaser that asserts sanity in strict builds.
  *
  * @returns The new reference count.
  * @param   pcRefs              The reference counter.
  */
-DECLINLINE(uint32_t) rtVfsRetain(uint32_t volatile *pcRefs)
-{
-    uint32_t cRefs = ASMAtomicIncU32(pcRefs);
-    AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x\n", cRefs));
+DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
+{
+    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+    AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
+    if (cRefs == 0)
+        rtVfsObjDestroy(pThis);
     return cRefs;
 }
 
 
-/**
- * Internal object retainer that asserts sanity in strict builds.
- *
- * @param   pcRefs              The reference counter.
- */
-DECLINLINE(void) rtVfsRetainVoid(uint32_t volatile *pcRefs)
-{
-    (void)rtVfsRetain(pcRefs);
-}
-
-
-/**
- * Internal object releaser that asserts sanity in strict builds.
- *
- * @returns The new reference count.
- * @param   pcRefs              The reference counter.
- */
-DECLINLINE(uint32_t) rtVfsRelease(uint32_t volatile *pcRefs)
-{
-    uint32_t cRefs = ASMAtomicDecU32(pcRefs);
-    AssertMsg(cRefs < _1M, ("%#x\n", cRefs));
-    return cRefs;
-}
+RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
+{
+    RTVFSOBJINTERNAL *pThis = hVfsObj;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
+    return rtVfsObjRelease(pThis);
+}
+
 
 
@@ -527,5 +709,5 @@
     AssertPtr(pThis);
     Assert(pThis->uMagic == RTVFS_MAGIC);
-    Assert(pThis->cRefs > 0);
+    Assert(pThis->Base.cRefs > 0);
     AssertPtr(pPath);
     AssertPtr(ppVfsParentDir);
@@ -538,7 +720,7 @@
     /** @todo Union mounts, traversal optimization methods, races, ++ */
     RTVFSDIRINTERNAL *pCurDir;
-    RTVFS_READ_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnOpenRoot(pThis->pvThis, &pCurDir);
-    RTVFS_READ_UNLOCK(pThis->hSemRW);
+    rtVfsObjReadLock(&pThis->Base);
+    int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pCurDir);
+    rtVfsObjReadUnlock(&pThis->Base);
     if (RT_FAILURE(rc))
         return rc;
@@ -573,7 +755,7 @@
         if (fFinal)
         {
-            RTVFS_READ_LOCK(pCurDir->hSemRW);
-            rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->pvThis, pszEntry, NULL, &hSymlink, NULL);
-            RTVFS_READ_UNLOCK(pCurDir->hSemRW);
+            rtVfsObjReadLock(&pCurDir->Base);
+            rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, NULL, &hSymlink, NULL);
+            rtVfsObjReadUnlock(&pCurDir->Base);
             *pszEntryEnd = '\0';
             if (rc == VERR_PATH_NOT_FOUND)
@@ -590,7 +772,7 @@
         else
         {
-            RTVFS_READ_LOCK(pCurDir->hSemRW);
-            rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
-            RTVFS_READ_UNLOCK(pCurDir->hSemRW);
+            rtVfsObjReadLock(&pCurDir->Base);
+            rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
+            rtVfsObjReadUnlock(&pCurDir->Base);
             *pszEntryEnd = '/';
             if (RT_FAILURE(rc))
@@ -641,7 +823,7 @@
                 /* Must restart from the root (optimize this). */
                 RTVfsDirRelease(pCurDir);
-                RTVFS_READ_LOCK(pThis->hSemRW);
-                rc = pThis->pOps->pfnOpenRoot(pThis->pvThis, &pCurDir);
-                RTVFS_READ_UNLOCK(pThis->hSemRW);
+                rtVfsObjReadLock(&pThis->Base);
+                rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pCurDir);
+                rtVfsObjReadUnlock(&pThis->Base);
                 if (RT_FAILURE(rc))
                 {
@@ -658,7 +840,7 @@
              */
             RTVfsDirRelease(pCurDir);
-            RTVFS_READ_LOCK(hVfsMnt->hSemRW);
-            rc = pThis->pOps->pfnOpenRoot(hVfsMnt->pvThis, &pCurDir);
-            RTVFS_READ_UNLOCK(hVfsMnt->hSemRW);
+            rtVfsObjReadLock(&hVfsMnt->Base);
+            rc = pThis->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
+            rtVfsObjReadUnlock(&hVfsMnt->Base);
             if (RT_FAILURE(rc))
             {
@@ -692,5 +874,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
-    return rtVfsRetain(&pThis->cRefs);
+    return rtVfsObjRetain(&pThis->Base);
 }
 
@@ -701,16 +883,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
-
-    uint32_t cRefs = rtVfsRelease(&pThis->cRefs);
-    if (!cRefs)
-    {
-        RTVFS_WRITE_LOCK(pThis->hSemRW);
-        ASMAtomicWriteU32(&pThis->uMagic, RTVFSDIR_MAGIC_DEAD);
-        RTVFS_WRITE_UNLOCK(pThis->hSemRW);
-        pThis->pOps->Obj.pfnClose(pThis->pvThis);
-        RTMemFree(pThis);
-    }
-
-    return cRefs;
+    return rtVfsObjRelease(&pThis->Base);
 }
 
@@ -730,5 +901,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
-    return rtVfsRetain(&pThis->cRefs);
+    return rtVfsObjRetain(&pThis->Base);
 }
 
@@ -739,16 +910,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
-
-    uint32_t cRefs = rtVfsRelease(&pThis->cRefs);
-    if (!cRefs)
-    {
-        RTVFS_WRITE_LOCK(pThis->hSemRW);
-        ASMAtomicWriteU32(&pThis->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
-        RTVFS_WRITE_UNLOCK(pThis->hSemRW);
-        pThis->pOps->Obj.pfnClose(pThis->pvThis);
-        RTMemFree(pThis);
-    }
-
-    return cRefs;
+    return rtVfsObjRelease(&pThis->Base);
 }
 
@@ -760,7 +920,7 @@
     AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnRead(pThis->pvThis, pszTarget, cbTarget);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
+    rtVfsObjWriteUnlock(&pThis->Base);
 
     return rc;
@@ -809,16 +969,17 @@
         return VERR_NO_MEMORY;
 
-    pThis->uMagic   = RTVFSIOSTREAM_MAGIC;
-    pThis->fFlags   = fOpen;
-    pThis->pvThis   = (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT);
-    pThis->pOps     = pIoStreamOps;
-    pThis->hSemRW   = hSemRW != NIL_RTSEMRW ? hSemRW : pVfs ? pVfs->hSemRW : NIL_RTSEMRW;
-    pThis->hVfs     = hVfs;
-    pThis->cRefs    = 1;
+    pThis->uMagic       = RTVFSIOSTREAM_MAGIC;
+    pThis->fFlags       = fOpen;
+    pThis->pOps         = pIoStreamOps;
+    pThis->Base.uMagic  = RTVFSOBJ_MAGIC;
+    pThis->Base.pvThis  = (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT);
+    pThis->Base.hSemRW  = hSemRW != NIL_RTSEMRW ? hSemRW : pVfs ? pVfs->Base.hSemRW : NIL_RTSEMRW;
+    pThis->Base.hVfs    = hVfs;
+    pThis->Base.cRefs   = 1;
     if (hVfs != NIL_RTVFS)
-        rtVfsRetainVoid(&pVfs->cRefs);
+        rtVfsObjRetainVoid(&pVfs->Base);
 
     *phVfsIos    = pThis;
-    *ppvInstance = pThis->pvThis;
+    *ppvInstance = pThis->Base.pvThis;
     return VINF_SUCCESS;
 }
@@ -830,5 +991,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
-    return rtVfsRetain(&pThis->cRefs);
+    return rtVfsObjRetain(&pThis->Base);
 }
 
@@ -839,44 +1000,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
-
-    uint32_t cRefs = rtVfsRelease(&pThis->cRefs);
-    if (!cRefs)
-    {
-        /*
-         * That was the last reference, close the stream.
-         *
-         * This is a little bit more complicated than when releasing a file or
-         * directory handle because the I/O stream can be a sub-object and we
-         * need to get to the real one before handing it to RTMemFree.
-         */
-        RTVFS_WRITE_LOCK(pThis->hSemRW);
-        ASMAtomicWriteU32(&pThis->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
-        RTVFS_WRITE_UNLOCK(pThis->hSemRW);
-        pThis->pOps->Obj.pfnClose(pThis->pvThis);
-
-        switch (pThis->pOps->Obj.enmType)
-        {
-            case RTVFSOBJTYPE_IOSTREAM:
-                RTMemFree(pThis);
-                break;
-
-            case RTVFSOBJTYPE_FILE:
-            {
-                RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
-                ASMAtomicWriteU32(&pThisFile->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
-                RTMemFree(pThisFile);
-                break;
-            }
-
-            /* Add new I/O stream compatible handle types here. */
-
-            default:
-                AssertMsgFailed(("%d\n", pThis->pOps->Obj.enmType));
-                break;
-        }
-    }
-
-    return cRefs;
-
+    return rtVfsObjRelease(&pThis->Base);
 }
 
@@ -890,5 +1012,5 @@
     if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
     {
-        rtVfsRetainVoid(&pThis->cRefs);
+        rtVfsObjRetainVoid(&pThis->Base);
         return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
     }
@@ -905,7 +1027,7 @@
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
 
-    RTVFS_READ_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->Obj.pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
-    RTVFS_READ_UNLOCK(pThis->hSemRW);
+    rtVfsObjReadLock(&pThis->Base);
+    int rc = pThis->pOps->Obj.pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
+    rtVfsObjReadUnlock(&pThis->Base);
     return rc;
 }
@@ -925,7 +1047,7 @@
     RTSgBufInit(&SgBuf, &Seg, 1);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnRead(pThis->pvThis, -1 /*off*/, &SgBuf, pcbRead == NULL /*fBlocking*/, pcbRead);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, pcbRead == NULL /*fBlocking*/, pcbRead);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -945,7 +1067,7 @@
     RTSgBufInit(&SgBuf, &Seg, 1);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnWrite(pThis->pvThis, -1 /*off*/, &SgBuf, pcbWritten == NULL /*fBlocking*/, pcbWritten);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, pcbWritten == NULL /*fBlocking*/, pcbWritten);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -963,7 +1085,7 @@
     AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnRead(pThis->pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -981,7 +1103,7 @@
     AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnWrite(pThis->pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -994,7 +1116,7 @@
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnFlush(pThis->pvThis);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -1008,7 +1130,7 @@
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
 
-    RTVFS_WRITE_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnPollOne(pThis->pvThis, fEvents, cMillies, fIntr, pfRetEvents);
-    RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+    rtVfsObjWriteLock(&pThis->Base);
+    int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
+    rtVfsObjWriteUnlock(&pThis->Base);
     return rc;
 }
@@ -1022,7 +1144,7 @@
 
     RTFOFF off;
-    RTVFS_READ_LOCK(pThis->hSemRW);
-    int rc = pThis->pOps->pfnTell(pThis->pvThis, &off);
-    RTVFS_READ_UNLOCK(pThis->hSemRW);
+    rtVfsObjReadLock(&pThis->Base);
+    int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
+    rtVfsObjReadUnlock(&pThis->Base);
     if (RT_FAILURE(rc))
         off = rc;
@@ -1041,7 +1163,7 @@
     if (pThis->pOps->pfnSkip)
     {
-        RTVFS_WRITE_LOCK(pThis->hSemRW);
-        rc = pThis->pOps->pfnSkip(pThis->pvThis, cb);
-        RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+        rtVfsObjWriteLock(&pThis->Base);
+        rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
+        rtVfsObjWriteUnlock(&pThis->Base);
     }
     else
@@ -1054,7 +1176,7 @@
             {
                 size_t cbToRead = RT_MIN(cb, _64K);
-                RTVFS_WRITE_LOCK(pThis->hSemRW);
+                rtVfsObjWriteLock(&pThis->Base);
                 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, NULL);
-                RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+                rtVfsObjWriteUnlock(&pThis->Base);
                 if (RT_FAILURE(rc))
                     break;
@@ -1080,7 +1202,7 @@
     if (pThis->pOps->pfnSkip)
     {
-        RTVFS_WRITE_LOCK(pThis->hSemRW);
-        rc = pThis->pOps->pfnZeroFill(pThis->pvThis, cb);
-        RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+        rtVfsObjWriteLock(&pThis->Base);
+        rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
+        rtVfsObjWriteUnlock(&pThis->Base);
     }
     else
@@ -1093,7 +1215,7 @@
             {
                 size_t cbToWrite = RT_MIN(cb, _64K);
-                RTVFS_WRITE_LOCK(pThis->hSemRW);
+                rtVfsObjWriteLock(&pThis->Base);
                 rc = RTVfsIoStrmWrite(hVfsIos, pvBuf, cbToWrite, NULL);
-                RTVFS_WRITE_UNLOCK(pThis->hSemRW);
+                rtVfsObjWriteUnlock(&pThis->Base);
                 if (RT_FAILURE(rc))
                     break;
@@ -1154,19 +1276,19 @@
         return VERR_NO_MEMORY;
 
-    pThis->uMagic           = RTVFSFILE_MAGIC;
-    pThis->fReserved        = 0;
-    pThis->pOps             = pFileOps;
-    pThis->Stream.uMagic    = RTVFSIOSTREAM_MAGIC;
-    pThis->Stream.fFlags    = fOpen;
-    pThis->Stream.pvThis    = (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT);
-    pThis->Stream.pOps      = &pFileOps->Stream;
-    pThis->Stream.hSemRW    = pVfs ? pVfs->hSemRW : NIL_RTSEMRW;
-    pThis->Stream.hVfs      = hVfs;
-    pThis->Stream.cRefs     = 1;
+    pThis->uMagic               = RTVFSFILE_MAGIC;
+    pThis->fReserved            = 0;
+    pThis->pOps                 = pFileOps;
+    pThis->Stream.uMagic        = RTVFSIOSTREAM_MAGIC;
+    pThis->Stream.fFlags        = fOpen;
+    pThis->Stream.pOps          = &pFileOps->Stream;
+    pThis->Stream.Base.pvThis   = (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT);
+    pThis->Stream.Base.hSemRW   = pVfs ? pVfs->Base.hSemRW : NIL_RTSEMRW;
+    pThis->Stream.Base.hVfs     = hVfs;
+    pThis->Stream.Base.cRefs    = 1;
     if (hVfs != NIL_RTVFS)
-        rtVfsRetainVoid(&pVfs->cRefs);
+        rtVfsObjRetainVoid(&pVfs->Base);
 
     *phVfsFile   = pThis;
-    *ppvInstance = pThis->Stream.pvThis;
+    *ppvInstance = pThis->Stream.Base.pvThis;
     return VINF_SUCCESS;
 }
@@ -1209,7 +1331,7 @@
 
                 /** @todo there is a symlink creation race here. */
-                RTVFS_WRITE_LOCK(pVfsParentDir->hSemRW);
-                rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->pvThis, pszEntryName, fOpen, phVfsFile);
-                RTVFS_WRITE_UNLOCK(pVfsParentDir->hSemRW);
+                rtVfsObjWriteLock(&pVfsParentDir->Base);
+                rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
+                rtVfsObjWriteUnlock(&pVfsParentDir->Base);
 
                 RTVfsDirRelease(pVfsParentDir);
@@ -1235,5 +1357,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
-    return rtVfsRetain(&pThis->Stream.cRefs);
+    return rtVfsObjRetain(&pThis->Stream.Base);
 }
 
@@ -1244,18 +1366,5 @@
     AssertPtrReturn(pThis, UINT32_MAX);
     AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
-
-    uint32_t cRefs = rtVfsRelease(&pThis->Stream.cRefs);
-    if (!cRefs)
-    {
-        RTVFS_WRITE_LOCK(pThis->Stream.hSemRW);
-        ASMAtomicWriteU32(&pThis->uMagic, RTVFSFILE_MAGIC_DEAD);
-        ASMAtomicWriteU32(&pThis->Stream.uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
-        RTVFS_WRITE_UNLOCK(pThis->Stream.hSemRW);
-
-        pThis->pOps->Stream.Obj.pfnClose(pThis->Stream.pvThis);
-        RTMemFree(pThis);
-    }
-
-    return cRefs;
+    return rtVfsObjRelease(&pThis->Stream.Base);
 }
 
@@ -1267,58 +1376,7 @@
     AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
 
-    rtVfsRetainVoid(&pThis->Stream.cRefs);
+    rtVfsObjRetainVoid(&pThis->Stream.Base);
     return &pThis->Stream;
 }
 
 
-
-#if 0 /* unfinished code => laptop */
-
-/*
- *
- *  V F S   c h a i n   s p e c i f i c a t i o n s
- *  V F S   c h a i n   s p e c i f i c a t i o n s
- *  V F S   c h a i n   s p e c i f i c a t i o n s
- *
- */
-
-/**
- * A parsed VFS setup specficiation.
- *
- * Some specification examples.
- *   :iprtvfs:ios(stdfile="./foo.tgz")|ios(gzip)|vfs(tar)
- */
-typedef struct RTVFSPARSEDSPEC
-{
-    uint32_t    cElements;
-} RTVFSPARSEDSPEC;
-/** Pointer to a parse VFS setup specification. */
-typedef RTVFSPARSEDSPEC *PRTVFSPARSEDSPEC;
-
-
-/**
- * Parses the VFS setup specficiation.
- *
- * @returns
- * @param   pInfo       The output.
- * @param   pszSpec     The input.  This needs some more work but the basic
- *                      are that anything that does not start with ":iprtvfs:"
- *                      will be treated like a file.  ":iprtvfs:" prefixed
- *                      specifications will be understood as a VFS chain
- *                      specification and parsed and constructured (by the
- *                      caller).
- * @param
- */
-static int rtVfsSpecParse(PRTVFSPARSEDSPEC pInfo, const char *pszSpec)
-{
-
-}
-
-
-RTDECL(int) RTVfsOpenIoStreamFromSpec(const char *pszSpec, uint32_t fOpen, RTVFSIOSTREAM hVfs)
-{
-
-}
-
-#endif
-
Index: /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 33945)
+++ /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 33945)
@@ -0,0 +1,658 @@
+/* $Id$ */
+/** @file
+ * IPRT - Virtual File System, Chains.
+ */
+
+/*
+ * Copyright (C) 2010 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/vfslowlevel.h>
+
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/once.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+
+#include "internal/file.h"
+#include "internal/magics.h"
+//#include "internal/vfs.h"
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Init the critical section once. */
+static RTONCE       g_rtVfsChainElementInitOnce;
+/** Critical section protecting g_rtVfsChainElementProviderList. */
+static RTCRITSECT   g_rtVfsChainElementCritSect;
+/** List of VFS chain element providers. */
+static RTLISTNODE   g_rtVfsChainElementProviderList;
+
+
+/**
+ * Initializes the globals via RTOnce.
+ *
+ * @returns IPRT status code
+ * @param   pvUser1             Unused, ignored.
+ * @param   pvUser2             Unused, ignored.
+ */
+static DECLCALLBACK(int) rtVfsChainElementRegisterInit(void *pvUser1, void *pvUser2)
+{
+    NOREF(pvUser1);
+    NOREF(pvUser2);
+    return RTCritSectInit(&g_rtVfsChainElementCritSect);
+}
+
+
+RTDECL(int) RTVfsChainElementRegisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromCtor)
+{
+    int rc;
+
+    /*
+     * Input validation.
+     */
+    AssertPtrReturn(pRegRec, VERR_INVALID_POINTER);
+    AssertMsgReturn(pRegRec->uVersion   == RTVFSCHAINELEMENTREG_VERSION, ("%#x", pRegRec->uVersion),    VERR_INVALID_POINTER);
+    AssertMsgReturn(pRegRec->uEndMarker == RTVFSCHAINELEMENTREG_VERSION, ("%#zx", pRegRec->uEndMarker), VERR_INVALID_POINTER);
+    AssertReturn(pRegRec->fReserved == 0, VERR_INVALID_POINTER);
+    AssertPtrReturn(pRegRec->pszName, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pRegRec->pfnOpenVfs,      VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pRegRec->pfnOpenDir,      VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pRegRec->pfnOpenFile,     VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pRegRec->pfnOpenIoStream, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pRegRec->pfnOpenFsStream, VERR_INVALID_POINTER);
+
+    /*
+     * Init and take the lock.
+     */
+    if (!fFromCtor)
+    {
+        rc = RTOnce(&g_rtVfsChainElementInitOnce, rtVfsChainElementRegisterInit, NULL, NULL);
+        if (RT_FAILURE(rc))
+            return rc;
+        rc = RTCritSectEnter(&g_rtVfsChainElementCritSect);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /*
+     * Duplicate name?
+     */
+    rc = VINF_SUCCESS;
+    PRTVFSCHAINELEMENTREG pIterator, pIterNext;
+    RTListForEachSafe(&g_rtVfsChainElementProviderList, pIterator, pIterNext, RTVFSCHAINELEMENTREG, ListEntry)
+    {
+        if (!strcmp(pIterator->pszName, pRegRec->pszName))
+        {
+            AssertMsgFailed(("duplicate name '%s' old=%p new=%p\n",  pIterator->pszName, pIterator, pRegRec));
+            rc = VERR_ALREADY_EXISTS;
+            break;
+        }
+    }
+
+    /*
+     * If not, append the record to the list.
+     */
+    if (RT_SUCCESS(rc))
+        RTListAppend(&g_rtVfsChainElementProviderList, &pRegRec->ListEntry);
+
+    /*
+     * Leave the lock and return.
+     */
+    if (!fFromCtor)
+        RTCritSectLeave(&g_rtVfsChainElementCritSect);
+    return rc;
+}
+
+
+/**
+ * Allocates and initializes an empty spec
+ *
+ * @returns Pointer to the spec on success, NULL on failure.
+ */
+static PRTVFSCHAINSPEC rtVfsChainSpecAlloc(void)
+{
+    PRTVFSCHAINSPEC pSpec = (PRTVFSCHAINSPEC)RTMemTmpAlloc(sizeof(*pSpec));
+    if (pSpec)
+    {
+        pSpec->iActionElement = UINT32_MAX;
+        pSpec->cElements      = 0;
+        pSpec->paElements     = NULL;
+    }
+    return pSpec;
+}
+
+
+/**
+ * Duplicate a spec string.
+ *
+ * This differs from RTStrDupN in that it uses RTMemTmpAlloc instead of
+ * RTMemAlloc.
+ *
+ * @returns String copy on success, NULL on failure.
+ * @param   psz         The string to duplicate.
+ * @param   cch         The number of bytes to duplicate.
+ * @param   prc         The status code variable to set on failure. (Leeps the
+ *                      code shorter. -lazy bird)
+ */
+DECLINLINE(char *) rtVfsChainSpecDupStrN(const char *psz, size_t cch, int *prc)
+{
+    char *pszCopy = (char *)RTMemTmpAlloc(cch + 1);
+    if (pszCopy)
+    {
+        if (!memchr(psz, '\\', cch))
+        {
+            /* Plain string, copy it raw. */
+            memcpy(pszCopy, psz, cch);
+            pszCopy[cch] = '\0';
+        }
+        else
+        {
+            /* Has escape sequences, must unescape it. */
+            char *pszDst = pszCopy;
+            while (cch)
+            {
+                char ch = *psz++;
+                if (ch == '\\')
+                {
+                    char ch2 = psz[2];
+                    if (ch2 == '(' || ch2 == ')' || ch2 == '\\' || ch2 == ',')
+                    {
+                        psz++;
+                        ch = ch2;
+                    }
+                }
+                *pszDst++ = ch;
+            }
+            *pszDst = '\0';
+        }
+    }
+    else
+        *prc = VERR_NO_TMP_MEMORY;
+    return pszCopy;
+}
+
+
+/**
+ * Adds an empty element to the chain specification.
+ *
+ * The caller is responsible for filling it the element attributes.
+ *
+ * @returns Pointer to the new element on success, NULL on failure.  The
+ *          pointer is only valid till the next call to this function.
+ * @param   pSpec       The chain specification.
+ * @param   prc         The status code variable to set on failure. (Leeps the
+ *                      code shorter. -lazy bird)
+ */
+static PRTVFSCHAINELEMSPEC rtVfsChainSpecAddElement(PRTVFSCHAINSPEC pSpec, int *prc)
+{
+    AssertPtr(pSpec);
+
+    /*
+     * Resize the element table if necessary.
+     */
+    uint32_t const iElement = pSpec->cElements;
+    if ((iElement % 32) == 0)
+    {
+        PRTVFSCHAINELEMSPEC paNew = (PRTVFSCHAINELEMSPEC)RTMemTmpAlloc((iElement + 32) * sizeof(paNew[0]));
+        if (!paNew)
+        {
+            *prc = VERR_NO_TMP_MEMORY;
+            return NULL;
+        }
+
+        memcpy(paNew, pSpec->paElements, iElement * sizeof(paNew[0]));
+        RTMemTmpFree(pSpec->paElements);
+        pSpec->paElements = paNew;
+    }
+
+    /*
+     * Initialize and add the new element.
+     */
+    PRTVFSCHAINELEMSPEC pElement = &pSpec->paElements[iElement];
+    pElement->pszProvider = NULL;
+    pElement->enmTypeIn   = iElement ? pSpec->paElements[iElement - 1].enmTypeOut : RTVFSOBJTYPE_INVALID;
+    pElement->enmTypeOut  = RTVFSOBJTYPE_INVALID;
+    pElement->enmAction   = RTVFSCHAINACTION_INVALID;
+    pElement->cArgs       = 0;
+    pElement->papszArgs   = 0;
+
+    pSpec->cElements  = iElement + 1;
+    return pElement;
+}
+
+
+/**
+ * Adds an argument to the element spec.
+ *
+ * @returns IPRT status code.
+ * @param   pElement            The element.
+ * @param   psz                 The start of the argument string.
+ * @param   cch                 The length of the argument string, escape
+ *                              sequences counted twice.
+ */
+static int rtVfsChainSpecElementAddArg(PRTVFSCHAINELEMSPEC pElement, const char *psz, size_t cch)
+{
+    uint32_t iArg = pElement->cArgs;
+    if ((iArg % 32) == 0)
+    {
+        char **papszNew = (char **)RTMemTmpAlloc((iArg + 32 + 1) * sizeof(papszNew[0]));
+        if (!papszNew)
+            return VERR_NO_TMP_MEMORY;
+        memcpy(papszNew, pElement->papszArgs, iArg * sizeof(papszNew[0]));
+        RTMemTmpFree(pElement->papszArgs);
+        pElement->papszArgs = papszNew;
+    }
+
+    int rc = VINF_SUCCESS;
+    pElement->papszArgs[iArg] = rtVfsChainSpecDupStrN(psz, cch, &rc);
+    pElement->papszArgs[iArg + 1] = NULL;
+    pElement->cArgs = iArg + 1;
+    return rc;
+}
+
+
+RTDECL(void)    RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec)
+{
+    if (!pSpec)
+        return;
+
+    uint32_t i = pSpec->cElements;
+    while (i-- > 0)
+    {
+        uint32_t iArg = pSpec->paElements[i].cArgs;
+        while (iArg-- > 0)
+            RTMemTmpFree(pSpec->paElements[i].papszArgs[iArg]);
+        RTMemTmpFree(pSpec->paElements[i].papszArgs);
+        RTMemTmpFree(pSpec->paElements[i].pszProvider);
+    }
+
+    RTMemTmpFree(pSpec->paElements);
+    pSpec->paElements = NULL;
+    RTMemTmpFree(pSpec);
+}
+
+
+/**
+ * Finds the end of the argument string.
+ *
+ * @returns The offset of the end character relative to @a psz.
+ * @param   psz                 The argument string.
+ */
+static size_t rtVfsChainSpecFindArgEnd(const char *psz)
+{
+    char ch;
+    size_t off = 0;
+    while (  (ch = psz[off]) != '\0'
+           && ch != ','
+           && ch != ')'
+           && ch != '(')
+    {
+        /* check for escape sequences. */
+        if (   ch == '\\'
+            && (psz[off+1] == '(' || psz[off+1] == ')' || psz[off+1] == '\\' || psz[off+1] == ','))
+            off++;
+        off++;
+    }
+    return off;
+}
+
+/**
+ * Look for action.
+ *
+ * @returns Action.
+ * @param   pszSpec             The current spec position.
+ * @param   pcchAction          Where to return the length of the action
+ *                              string.
+ */
+static RTVFSCHAINACTION rtVfsChainSpecEatAction(const char *pszSpec, size_t *pcchAction)
+{
+    switch (*pszSpec)
+    {
+        case '|':
+            *pcchAction = 1;
+            return RTVFSCHAINACTION_PASSIVE;
+        case '>':
+            *pcchAction = 1;
+            return RTVFSCHAINACTION_PUSH;
+        default:
+            *pcchAction = 0;
+            return RTVFSCHAINACTION_NONE;
+    }
+}
+
+
+RTDECL(int)     RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSCHAINACTION enmLeadingAction,
+                                    RTVFSCHAINACTION enmTrailingAction,
+                                    PRTVFSCHAINSPEC *ppSpec, const char **ppszError)
+{
+    AssertPtrNullReturn(ppszError, VERR_INVALID_POINTER);
+    if (ppszError)
+        *ppszError = NULL;
+    AssertPtrReturn(ppSpec, VERR_INVALID_POINTER);
+    *ppSpec = NULL;
+    AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
+    AssertPtrReturn(!(fFlags & ~RTVFSCHAIN_PF_VALID_MASK), VERR_INVALID_PARAMETER);
+    AssertPtrReturn(enmLeadingAction > RTVFSCHAINACTION_INVALID && enmLeadingAction < RTVFSCHAINACTION_END, VERR_INVALID_PARAMETER);
+
+    /*
+     * Check the start of the specification and allocate an empty return spec.
+     */
+    if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1))
+        return VERR_VFS_CHAIN_NO_PREFIX;
+    pszSpec = RTStrStripL(pszSpec + sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1);
+    if (!*pszSpec)
+        return VERR_VFS_CHAIN_EMPTY;
+
+    PRTVFSCHAINSPEC pSpec = rtVfsChainSpecAlloc();
+    if (!pSpec)
+        return VERR_NO_TMP_MEMORY;
+
+    /*
+     * Parse the spec one element at a time.
+     */
+    int         rc     = VINF_SUCCESS;
+    const char *pszSrc = pszSpec;
+    while (*pszSrc && RT_SUCCESS(rc))
+    {
+        /*
+         * Pipe or redirection action symbol, except maybe the first time.
+         * The pipe symbol may occur at the end of the spec.
+         */
+        size_t           cch;
+        RTVFSCHAINACTION enmAction = rtVfsChainSpecEatAction(pszSpec, &cch);
+        if (enmAction != RTVFSCHAINACTION_NONE)
+        {
+            pszSrc = RTStrStripL(pszSrc + cch);
+            if (!*pszSrc)
+            {
+                /* Fail if the caller does not approve of a trailing pipe (all
+                   other actions non-trailing). */
+                if (   enmAction != enmTrailingAction
+                    && !(fFlags & RTVFSCHAIN_PF_TRAILING_ACTION_OPTIONAL))
+                    rc = VERR_VFS_CHAIN_EXPECTED_ELEMENT;
+                break;
+            }
+
+            /* There can only be one real action atm. */
+            if (enmAction != RTVFSCHAINACTION_PASSIVE)
+            {
+                if (pSpec->iActionElement != UINT32_MAX)
+                {
+                    rc = VERR_VFS_CHAIN_MULTIPLE_ACTIONS;
+                    break;
+                }
+                pSpec->iActionElement = pSpec->cElements;
+            }
+        }
+        else if (pSpec->cElements > 0)
+        {
+            rc = VERR_VFS_CHAIN_EXPECTED_ACTION;
+            break;
+        }
+
+        /* Check the leading action. */
+        if (   pSpec->cElements == 0
+            && enmAction != enmLeadingAction
+            && !(fFlags & RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL))
+        {
+            rc = VERR_VFS_CHAIN_UNEXPECTED_ACTION_TYPE;
+            break;
+        }
+
+
+        /*
+         * Ok, there should be an element here so add one to the return struct.
+         */
+        PRTVFSCHAINELEMSPEC pElement = rtVfsChainSpecAddElement(pSpec, &rc);
+        if (!pElement)
+            break;
+        pElement->enmAction = enmAction;
+
+        /* First comes a type which is followed by a '('. */
+        if (strncmp(pszSrc, "base", cch = 4) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_BASE;
+        else if (strncmp(pszSrc, "vfs",  cch = 3) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_VFS;
+        else if (strncmp(pszSrc, "fss",  cch = 3) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_FS_STREAM;
+        else if (strncmp(pszSrc, "ios",  cch = 3) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_IO_STREAM;
+        else if (strncmp(pszSrc, "dir",  cch = 3) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_DIR;
+        else if (strncmp(pszSrc, "file", cch = 4) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_FILE;
+        else if (strncmp(pszSrc, "sym",  cch = 3) == 0)
+            pElement->enmTypeOut = RTVFSOBJTYPE_SYMLINK;
+        else
+        {
+            rc = VERR_VFS_CHAIN_UNKNOWN_TYPE;
+            break;
+        }
+        pszSrc += cch;
+
+        /* Check and skip the parentheses. */
+        if (*pszSrc != '(')
+        {
+            rc = VERR_VFS_CHAIN_EXPECTED_LEFT_PARENTHESES;
+            break;
+        }
+        pszSrc = RTStrStripL(pszSrc + 1);
+
+        /*
+         * The name of the element provider.
+         */
+        cch = rtVfsChainSpecFindArgEnd(pszSrc);
+        if (!cch)
+        {
+            rc = VERR_VFS_CHAIN_EXPECTED_PROVIDER_NAME;
+            break;
+        }
+        pElement->pszProvider = rtVfsChainSpecDupStrN(pszSrc, cch, &rc);
+        if (!pElement->pszProvider)
+            break;
+        pszSrc += cch;
+
+        /*
+         * The arguments.
+         */
+        while (*pszSrc == ',')
+        {
+            pszSrc = RTStrStripL(pszSrc + 1);
+            cch = rtVfsChainSpecFindArgEnd(pszSrc);
+            rc = rtVfsChainSpecElementAddArg(pElement, pszSrc, cch);
+            pszSrc += cch;
+        }
+
+        /* Must end with a right parantheses. */
+        if (*pszSrc != ')')
+        {
+            rc = VERR_VFS_CHAIN_EXPECTED_RIGHT_PARENTHESES;
+            break;
+        }
+        pszSrc = RTStrStripL(pszSrc + 1);
+    }
+
+    /*
+     * Cleanup and set the error indicator on failure.
+     */
+    if (RT_FAILURE(rc))
+    {
+        if (ppszError)
+            *ppszError = pszSrc;
+        RTVfsChainSpecFree(pSpec);
+    }
+    return rc;
+}
+
+
+
+
+
+RTDECL(int) RTVfsChainElementDeregisterProvider(PRTVFSCHAINELEMENTREG pRegRec, bool fFromDtor)
+{
+    /*
+     * Fend off wildlife.
+     */
+    if (pRegRec == NULL)
+        return VINF_SUCCESS;
+    AssertPtrReturn(pRegRec, VERR_INVALID_POINTER);
+    AssertMsgReturn(pRegRec->uVersion   == RTVFSCHAINELEMENTREG_VERSION, ("%#x", pRegRec->uVersion),    VERR_INVALID_POINTER);
+    AssertMsgReturn(pRegRec->uEndMarker == RTVFSCHAINELEMENTREG_VERSION, ("%#zx", pRegRec->uEndMarker), VERR_INVALID_POINTER);
+    AssertPtrReturn(pRegRec->pszName, VERR_INVALID_POINTER);
+
+    /*
+     * Take the lock if that's safe.
+     */
+    if (!fFromDtor)
+        RTCritSectEnter(&g_rtVfsChainElementCritSect);
+
+    /*
+     * Ok, remove it.
+     */
+    int rc = VERR_NOT_FOUND;
+    PRTVFSCHAINELEMENTREG pIterator, pIterNext;
+    RTListForEachSafe(&g_rtVfsChainElementProviderList, pIterator, pIterNext, RTVFSCHAINELEMENTREG, ListEntry)
+    {
+        if (pIterator == pRegRec)
+        {
+            RTListNodeRemove(&pRegRec->ListEntry);
+            rc = VINF_SUCCESS;
+            break;
+        }
+    }
+
+    /*
+     * Leave the lock and return.
+     */
+    if (!fFromDtor)
+        RTCritSectLeave(&g_rtVfsChainElementCritSect);
+    return rc;
+}
+
+
+RTDECL(int) RTVfsChainOpenFile(const char *pszSpec, uint32_t fOpen, PRTVFSFILE phVfsFile, const char **ppszError)
+{
+    AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
+    AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
+
+    /*
+     * If it's not a VFS chain spec, treat it as a file.
+     */
+    int rc;
+    if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1))
+    {
+        RTFILE hFile;
+        rc = RTFileOpen(&hFile, pszSpec, fOpen);
+        if (RT_SUCCESS(rc))
+        {
+            RTVFSFILE hVfsFile;
+            rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
+            if (RT_SUCCESS(rc))
+                *phVfsFile = hVfsFile;
+            else
+                RTFileClose(hFile);
+        }
+    }
+    else
+    {
+        PRTVFSCHAINSPEC pSpec;
+        rc = RTVfsChainSpecParse(pszSpec,
+                                   RTVFSCHAIN_PF_NO_REAL_ACTION
+                                 | RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL,
+                                 RTVFSCHAINACTION_PASSIVE,
+                                 RTVFSCHAINACTION_NONE,
+                                 &pSpec,
+                                 ppszError);
+        if (RT_SUCCESS(rc))
+        {
+            /** @todo implement this when needed. */
+            rc = VERR_NOT_IMPLEMENTED;
+            RTVfsChainSpecFree(pSpec);
+        }
+    }
+    return rc;
+}
+
+
+RTDECL(int) RTVfsChainOpenIoStream(const char *pszSpec, uint32_t fOpen, PRTVFSIOSTREAM phVfsIos, const char **ppszError)
+{
+    AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
+    AssertReturn(*pszSpec != '\0', VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
+
+    /*
+     * If it's not a VFS chain spec, treat it as a file.
+     */
+    int rc;
+    if (strncmp(pszSpec, RTVFSCHAIN_SPEC_PREFIX, sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1))
+    {
+        RTFILE hFile;
+        rc = RTFileOpen(&hFile, pszSpec, fOpen);
+        if (RT_SUCCESS(rc))
+        {
+            RTVFSFILE hVfsFile;
+            rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
+            if (RT_SUCCESS(rc))
+            {
+                *phVfsIos = RTVfsFileToIoStream(hVfsFile);
+                RTVfsFileRelease(hVfsFile);
+            }
+            else
+                RTFileClose(hFile);
+        }
+    }
+    else
+    {
+        PRTVFSCHAINSPEC pSpec;
+        rc = RTVfsChainSpecParse(pszSpec,
+                                   RTVFSCHAIN_PF_NO_REAL_ACTION
+                                 | RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL,
+                                 RTVFSCHAINACTION_PASSIVE,
+                                 RTVFSCHAINACTION_NONE,
+                                 &pSpec,
+                                 ppszError);
+        if (RT_SUCCESS(rc))
+        {
+
+
+            rc = VERR_NOT_IMPLEMENTED;
+            RTVfsChainSpecFree(pSpec);
+        }
+    }
+    return rc;
+}
+
+
+
Index: /trunk/src/VBox/Runtime/common/zip/zipgzip.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/zip/zipgzip.cpp	(revision 33944)
+++ /trunk/src/VBox/Runtime/common/zip/zipgzip.cpp	(revision 33945)
@@ -452,5 +452,5 @@
     { /* Obj */
         RTVFSOBJOPS_VERSION,
-        RTVFSOBJTYPE_IOSTREAM,
+        RTVFSOBJTYPE_IO_STREAM,
         "gzip",
         rtZipGzip_Close,
