Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 66593)
+++ /trunk/include/iprt/err.h	(revision 66594)
@@ -1854,14 +1854,84 @@
 /** 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)
+/** Expected an element separator (| or :). */
+#define VERR_VFS_CHAIN_EXPECTED_SEPARATOR           (-22107)
+/** Leading element separator not permitted. */
+#define VERR_VFS_CHAIN_LEADING_SEPARATOR            (-22108)
+/** Trailing element separator not permitted. */
+#define VERR_VFS_CHAIN_TRAILING_SEPARATOR           (-22109)
+/** The provider is only allowed as the first element. */
+#define VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT        (-22110)
+/** The provider cannot be the first element. */
+#define VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT      (-22111)
+/** VFS object cast failed. */
+#define VERR_VFS_CHAIN_CAST_FAILED                  (-22112)
+/** Internal error in the VFS chain code. */
+#define VERR_VFS_CHAIN_IPE                          (-22113)
+/** VFS chain element provider not found. */
+#define VERR_VFS_CHAIN_PROVIDER_NOT_FOUND           (-22114)
+/** VFS chain does not terminate with the desired object type. */
+#define VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH          (-22115)
+/** VFS chain element takes no arguments.  */
+#define VERR_VFS_CHAIN_NO_ARGS                      (-22116)
+/** VFS chain element takes exactly one argument. */
+#define VERR_VFS_CHAIN_ONE_ARG                      (-22117)
+/** VFS chain element expected at most one argument.  */
+#define VERR_VFS_CHAIN_AT_MOST_ONE_ARG              (-22118)
+/** VFS chain element expected at least one argument.  */
+#define VERR_VFS_CHAIN_AT_LEAST_ONE_ARG             (-22119)
+/** VFS chain element takes exactly two arguments. */
+#define VERR_VFS_CHAIN_TWO_ARGS                     (-22120)
+/** VFS chain element expected at least two arguments.  */
+#define VERR_VFS_CHAIN_AT_LEAST_TWO_ARGS            (-22121)
+/** VFS chain element expected at most two arguments.  */
+#define VERR_VFS_CHAIN_AT_MOST_TWO_ARGS             (-22122)
+/** VFS chain element takes exactly three arguments. */
+#define VERR_VFS_CHAIN_THREE_ARGS                   (-22123)
+/** VFS chain element expected at least three arguments.  */
+#define VERR_VFS_CHAIN_AT_LEAST_THREE_ARGS          (-22124)
+/** VFS chain element expected at most three arguments.  */
+#define VERR_VFS_CHAIN_AT_MOST_THREE_ARGS           (-22125)
+/** VFS chain element takes exactly four arguments. */
+#define VERR_VFS_CHAIN_FOUR_ARGS                    (-22126)
+/** VFS chain element expected at least four arguments.  */
+#define VERR_VFS_CHAIN_AT_LEAST_FOUR_ARGS           (-22127)
+/** VFS chain element expected at most four arguments.  */
+#define VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS            (-22128)
+/** VFS chain element takes exactly five arguments. */
+#define VERR_VFS_CHAIN_FIVE_ARGS                    (-22129)
+/** VFS chain element expected at least five arguments.  */
+#define VERR_VFS_CHAIN_AT_LEAST_FIVE_ARGS           (-22130)
+/** VFS chain element expected at most five arguments.  */
+#define VERR_VFS_CHAIN_AT_MOST_FIVE_ARGS            (-22131)
+/** VFS chain element takes exactly six arguments. */
+#define VERR_VFS_CHAIN_SIX_ARGS                     (-22132)
+/** VFS chain element expected at least six arguments.  */
+#define VERR_VFS_CHAIN_AT_LEAST_SIX_ARGS            (-22133)
+/** VFS chain element expected at most six arguments.  */
+#define VERR_VFS_CHAIN_AT_MOST_SIX_ARGS             (-22134)
+/** VFS chain element expected at most six arguments.  */
+#define VERR_VFS_CHAIN_TOO_FEW_ARGS                 (-22135)
+/** VFS chain element expected at most six arguments.  */
+#define VERR_VFS_CHAIN_TOO_MANY_ARGS                (-22136)
+/** VFS chain element expected non-empty argument. */
+#define VERR_VFS_CHAIN_EMPTY_ARG                    (-22137)
+/** Invalid argument to VFS chain element. */
+#define VERR_VFS_CHAIN_INVALID_ARGUMENT             (-22138)
+/** VFS chain element only provides file and I/O stream (ios) objects. */
+#define VERR_VFS_CHAIN_ONLY_FILE_OR_IOS             (-22139)
+/** VFS chain element only provides I/O stream (ios) objects. */
+#define VERR_VFS_CHAIN_ONLY_IOS                     (-22140)
+/** VFS chain element only provides directory (dir) objects. */
+#define VERR_VFS_CHAIN_ONLY_DIR                     (-22141)
+/** VFS chain element only provides file system stream (fss) objects. */
+#define VERR_VFS_CHAIN_ONLY_FSS                     (-22142)
+/** VFS chain element only provides file system (vfs) objects. */
+#define VERR_VFS_CHAIN_ONLY_VFS                     (-22143)
+/** VFS chain element only provides a read-only I/O stream, while the chain
+ * requires write access. */
+#define VERR_VFS_CHAIN_READ_ONLY_IOS                (-22144)
+/** VFS chain element only provides a read-only I/O stream, while the chain
+ * read access. */
+#define VERR_VFS_CHAIN_WRITE_ONLY_IOS               (-22145)
 /** @} */
 
Index: /trunk/include/iprt/formats/fat.h
===================================================================
--- /trunk/include/iprt/formats/fat.h	(revision 66593)
+++ /trunk/include/iprt/formats/fat.h	(revision 66594)
@@ -31,5 +31,4 @@
 #include <iprt/assert.h>
 
-#pragma pack(1)
 
 /** @name FAT Media byte values
@@ -47,4 +46,5 @@
  * This was the first DOS version with a BPB.
  */
+#pragma pack(1)
 typedef struct FATBPB20
 {
@@ -66,4 +66,5 @@
     uint16_t        cSectorsPerFat;
 } FATBPB20;
+#pragma pack()
 AssertCompileSize(FATBPB20, 0xd);
 /** Pointer to a DOS 2.0 BPB. */
@@ -76,4 +77,5 @@
  * The DOS 3.0 BPB changes that survived.
  */
+#pragma pack(1)
 typedef struct FATBPB30CMN
 {
@@ -85,4 +87,5 @@
     uint16_t        cTracksPerCylinder;
 } FATBPB30CMN;
+#pragma pack()
 AssertCompileSize(FATBPB30CMN, 0x11);
 
@@ -90,4 +93,5 @@
  * The DOS 3.0 BPB.
  */
+#pragma pack(1)
 typedef struct FATBPB30
 {
@@ -98,4 +102,5 @@
     uint16_t        cHiddenSectors;
 } FATBPB30;
+#pragma pack()
 AssertCompileSize(FATBPB30, 0x13);
 /** Pointer to a DOS 3.0 BPB. */
@@ -107,4 +112,5 @@
  * The DOS 3.0 BPB, flattened structure.
  */
+#pragma pack(1)
 typedef struct FATBPB30FLAT
 {
@@ -139,4 +145,5 @@
     /** @} */
 } FATBPB30FLAT;
+#pragma pack()
 AssertCompileSize(FATBPB30FLAT, 0x13);
 /** Pointer to a flattened DOS 3.0 BPB. */
@@ -149,4 +156,5 @@
  * The DOS 3.2 BPB.
  */
+#pragma pack(1)
 typedef struct FATBPB32
 {
@@ -157,4 +165,5 @@
     uint16_t        cAnotherTotalSectors;
 } FATBPB32;
+#pragma pack()
 AssertCompileSize(FATBPB32, 0x15);
 /** Pointer to a DOS 3.2 BPB. */
@@ -166,4 +175,5 @@
  * The DOS 3.2 BPB, flattened structure.
  */
+#pragma pack(1)
 typedef struct FATBPB32FLAT
 {
@@ -204,4 +214,5 @@
     /** @} */
 } FATBPB32FLAT;
+#pragma pack()
 AssertCompileSize(FATBPB32FLAT, 0x15);
 /** Pointer to a flattened DOS 3.2 BPB. */
@@ -214,4 +225,5 @@
  * The DOS 3.31 BPB.
  */
+#pragma pack(1)
 typedef struct FATBPB331
 {
@@ -226,4 +238,5 @@
     uint32_t        cTotalSectors32;
 } FATBPB331;
+#pragma pack()
 AssertCompileSize(FATBPB331, 0x19);
 /** Pointer to a DOS 3.31 BPB. */
@@ -235,4 +248,5 @@
  * The DOS 3.31 BPB, flattened structure.
  */
+#pragma pack(1)
 typedef struct FATBPB331FLAT
 {
@@ -274,4 +288,5 @@
     /** @} */
 } FATBPB331FLAT;
+#pragma pack()
 AssertCompileSize(FATBPB331FLAT, 0x19);
 /** Pointer to a flattened DOS 3.31 BPB. */
@@ -284,4 +299,5 @@
  * Extended BIOS parameter block (EBPB).
  */
+#pragma pack(1)
 typedef struct FATEBPB
 {
@@ -306,4 +322,5 @@
     char            achType[8];
 } FATEBPB;
+#pragma pack()
 AssertCompileSize(FATEBPB, 0x33);
 /** Pointer to an extended BIOS parameter block. */
@@ -329,4 +346,5 @@
  * FAT32 Extended BIOS parameter block (EBPB).
  */
+#pragma pack(1)
 typedef struct FAT32EBPB
 {
@@ -376,8 +394,11 @@
     union
     {
+        /** Type string variant.  */
         char        achType[8];
+        /** Total sector count if 4G or higher. */
         uint64_t    cTotalSectors64;
     } u;
 } FAT32EBPB;
+#pragma pack()
 AssertCompileSize(FAT32EBPB, 0x4f);
 /** Pointer to a FAT32 extended BIOS parameter block. */
@@ -393,4 +414,5 @@
  * FAT boot sector layout.
  */
+#pragma pack(1)
 typedef struct FATBOOTSECTOR
 {
@@ -417,4 +439,5 @@
     uint16_t            uSignature;
 } FATBOOTSECTOR;
+#pragma pack()
 AssertCompileSize(FATBOOTSECTOR, 0x200);
 /** Pointer to a FAT boot sector. */
@@ -426,5 +449,36 @@
 #define FATBOOTSECTOR_SIGNATURE     UINT16_C(0xaa55)
 
-#pragma pack()
+
+
+/**
+ * FAT32 info sector (follows the boot sector).
+ */
+typedef struct FAT32INFOSECTOR
+{
+    /** 0x000: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_1). */
+    uint32_t        uSignature1;
+    /** Reserved, should be zero. */
+    uint8_t         abReserved1[0x1E0];
+    /** 0x1e4: Signature \#1 (FAT32INFOSECTOR_SIGNATURE_2). */
+    uint32_t        uSignature2;
+    /** 0x1e8: Last known number of free clusters (informational). */
+    uint32_t        cFreeClusters;
+    /** 0x1ec: Last allocated cluster number (informational).  This could be used as
+     * an allocation hint when searching for a free cluster. */
+    uint32_t        cLastAllocatedCluster;
+    /** 0x1f0: Reserved, should be zero, preserve. */
+    uint8_t         abReserved2[12];
+    /** 0x1fc: Signature \#3 (FAT32INFOSECTOR_SIGNATURE_3). */
+    uint32_t        uSignature3;
+} FAT32INFOSECTOR;
+AssertCompileSize(FAT32INFOSECTOR, 0x200);
+/** Pointer to a FAT32 info sector. */
+typedef FAT32INFOSECTOR *PFAT32INFOSECTOR;
+/** Pointer to a const FAT32 info sector. */
+typedef FAT32INFOSECTOR const *PCFAT32INFOSECTOR;
+
+#define FAT32INFOSECTOR_SIGNATURE_1     UINT32_C(0x41615252)
+#define FAT32INFOSECTOR_SIGNATURE_2     UINT32_C(0x61417272)
+#define FAT32INFOSECTOR_SIGNATURE_3     UINT32_C(0xaa550000)
 
 #endif
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 66593)
+++ /trunk/include/iprt/mangling.h	(revision 66594)
@@ -1338,4 +1338,6 @@
 # define RTMsgErrorExit                                 RT_MANGLER(RTMsgErrorExit)
 # define RTMsgErrorExitV                                RT_MANGLER(RTMsgErrorExitV)
+# define RTMsgErrorExitFailure                          RT_MANGLER(RTMsgErrorExitFailure)
+# define RTMsgErrorExitFailureV                         RT_MANGLER(RTMsgErrorExitFailureV)
 # define RTMsgErrorRc                                   RT_MANGLER(RTMsgErrorRc)
 # define RTMsgErrorRcV                                  RT_MANGLER(RTMsgErrorRcV)
@@ -2281,4 +2283,5 @@
 # define RTVfsChainOpenFile                             RT_MANGLER(RTVfsChainOpenFile)
 # define RTVfsChainOpenIoStream                         RT_MANGLER(RTVfsChainOpenIoStream)
+# define RTVfsChainSpecCheckAndSetup                    RT_MANGLER(RTVfsChainSpecCheckAndSetup)
 # define RTVfsChainSpecFree                             RT_MANGLER(RTVfsChainSpecFree)
 # define RTVfsChainSpecParse                            RT_MANGLER(RTVfsChainSpecParse)
Index: /trunk/include/iprt/message.h
===================================================================
--- /trunk/include/iprt/message.h	(revision 66593)
+++ /trunk/include/iprt/message.h	(revision 66594)
@@ -98,4 +98,22 @@
 
 /**
+ * Same as RTMsgError() except for always returning RTEXITCODE_FAILURE.
+ *
+ * @returns RTEXITCODE_FAILURE
+ * @param   pszFormat       The message format string.
+ * @param   ...             Format arguments.
+ */
+RTDECL(RTEXITCODE) RTMsgErrorExitFailure(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3);
+
+/**
+ * Same as RTMsgErrorV() except for always returning RTEXITCODE_FAILURE.
+ *
+ * @returns RTEXITCODE_FAILURE
+ * @param   pszFormat       The message format string.
+ * @param   va              Format arguments.
+ */
+RTDECL(RTEXITCODE) RTMsgErrorExitFailureV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0);
+
+/**
  * Same as RTMsgError() except for the return value.
  *
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 66593)
+++ /trunk/include/iprt/vfs.h	(revision 66594)
@@ -1058,13 +1058,47 @@
  * 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)
+ *      RTCat :iprtvfs:file(stdfile,live.iso)|vfs(isofs)|iso(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.
- *
- * @{ */
+ *      RTCat :iprtvfs:file(stdfile,live.iso)|ios(isofs,readme.gz)|ios(gunzip)
+ *
+ * Or say you want to read the README.TXT on a floppy image:
+ *      RTCat :iprtvfs:file(stdfile,floppy.img,r)|vfs(fat)|ios(open,README.TXT)
+ *
+ * Or in the other direction, you want to write a STUFF.TGZ file to the above
+ * floppy image, using a lazy writer thread for compressing the data:
+ *      RTTar cf :iprtvfs:file(stdfile,floppy.img,rw)|ios(fat,STUFF.TGZ)|ios(gzip)|ios(push) .
+ *
+ *
+ * A bit more formally:
+ *      :iprtvfs:<type>(<provider>[,provider-args])[<separator><type>...]
+ *
+ * The @c type refers to VFS object that should be created by the @c provider.
+ * Valid types:
+ *      - vfs:  A virtual file system (volume).
+ *      - fss:  A file system stream (e.g. tar).
+ *      - ios:  An I/O stream.
+ *      - file: A file.
+ *      - dir:  A directory.
+ *      - sym:  A symbolic link (not sure how useful this is).
+ *
+ * The @c provider refers to registered chain element providers (see
+ * RTVFSCHAINELEMENTREG for how that works internally).  These are asked to
+ * create a VFS object of the specified type using the given arguments (if any).
+ * Default providers:
+ *      - std:      Standard file, directory and file system.
+ *      - open:     Opens a file, I/O stream or directory in a vfs or directory object.
+ *      - pull:     Read-ahead buffering thread on file or I/O stream.
+ *      - push:     Lazy-writer buffering thread on file or I/O stream.
+ *      - gzip:     Compresses an I/O stream.
+ *      - gunzip:   Decompresses an I/O stream.
+ *      - fat:      FAT file system accessor.
+ *      - isofs:    ISOFS file system accessor.
+ *
+ * As element @c separator we allow both colon (':') and the pipe character
+ * ('|'). The latter the conventional one, but since it's inconvenient on the
+ * command line, colon is provided as an alternative.
+ *
+ * @{
+ */
 
 /** The path prefix used to identify an VFS chain specification. */
@@ -1075,6 +1109,6 @@
 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) RTVfsChainOpenIoStream( const char *pszSpec, uint64_t fOpen, PRTVFSIOSTREAM  phVfsIos,  const char **ppszError);
 
 /**
@@ -1086,9 +1120,9 @@
 RTDECL(bool)    RTVfsChainIsSpec(const char *pszSpec);
 
-/** @}  */
-
-
 /** @} */
 
+
+/** @} */
+
 RT_C_DECLS_END
 
Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 66593)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 66594)
@@ -973,23 +973,23 @@
  */
 
-
-/**
- * Chain element input actions.
- */
-typedef enum RTVFSCHAINACTION
-{
-    /** Invalid action. */
-    RTVFSCHAINACTION_INVALID = 0,
-    /** 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;
+/** Pointer to a VFS chain element registration record. */
+typedef struct RTVFSCHAINELEMENTREG *PRTVFSCHAINELEMENTREG;
+/** Pointer to a const VFS chain element registration record. */
+typedef struct RTVFSCHAINELEMENTREG const *PCRTVFSCHAINELEMENTREG;
+
+/**
+ * VFS chain element argument.
+ */
+typedef struct RTVFSCHAINELEMENTARG
+{
+    /** The string argument value. */
+    char                   *psz;
+    /** The specification offset of this argument. */
+    uint16_t                offSpec;
+    /** Provider specific value. */
+    uint64_t                uProvider;
+} RTVFSCHAINELEMENTARG;
+/** Pointer to a VFS chain element argument. */
+typedef RTVFSCHAINELEMENTARG *PRTVFSCHAINELEMENTARG;
 
 
@@ -999,16 +999,23 @@
 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 provider name.  */
+    char                   *pszProvider;
+    /** The input type, RTVFSOBJTYPE_INVALID if first. */
+    RTVFSOBJTYPE            enmTypeIn;
+    /** The element type. */
+    RTVFSOBJTYPE            enmType;
+    /** The input spec offset of this element. */
+    uint16_t                offSpec;
+    /** The length of the input spec. */
+    uint16_t                cchSpec;
     /** The number of arguments. */
-    uint32_t            cArgs;
+    uint32_t                cArgs;
     /** Arguments. */
-    char              **papszArgs;
+    PRTVFSCHAINELEMENTARG   paArgs;
+
+    /** The provider. */
+    PCRTVFSCHAINELEMENTREG  pProvider;
+    /** The object (with reference). */
+    RTVFSOBJ                hVfsObj;
 } RTVFSCHAINELEMSPEC;
 /** Pointer to a chain element specification. */
@@ -1023,10 +1030,14 @@
 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;
+    /** Open directory flags (RTFILE_O_XXX). */
+    uint32_t            fOpenFile;
+    /** To be defined. */
+    uint32_t            fOpenDir;
+    /** The type desired by the caller. */
+    RTVFSOBJTYPE        enmDesiredType;
     /** The number of elements. */
     uint32_t            cElements;
+    /** Provider specific value. */
+    uint64_t            uProvider;
     /** The elements. */
     PRTVFSCHAINELEMSPEC paElements;
@@ -1051,70 +1062,67 @@
     /** 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);
+    /** Help text. */
+    const char             *pszHelp;
+
+    /**
+     * Checks the element specification.
+     *
+     * This is allowed to parse arguments and use pSpec->uProvider and
+     * pElement->paArgs[].uProvider to store information that pfnInstantiate and
+     * pfnCanReuseElement may use later on, thus avoiding duplicating work/code.
+     *
+     * @returns IPRT status code.
+     * @param   pProviderReg    Pointer to the element provider registration.
+     * @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.
+     */
+    DECLCALLBACKMEMBER(int, pfnValidate)(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
+                                         PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError);
+
+    /**
+     * Create a VFS object according to the element specification.
+     *
+     * @returns IPRT status code.
+     * @param   pProviderReg    Pointer to the element provider registration.
+     * @param   pSpec           The chain specification.
+     * @param   pElement        The chain element specification to instantiate.
+     * @param   hPrevVfsObj     Handle to the previous VFS object, NIL_RTVFSOBJ if
+     *                          first.
+     * @param   phVfsObj        Where to return the VFS object handle.
+     * @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.
+     */
+    DECLCALLBACKMEMBER(int, pfnInstantiate)(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
+                                            PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
+                                            PRTVFSOBJ phVfsObj, uint32_t *poffError);
+
+    /**
+     * Determins whether the element can be reused.
+     *
+     * This is for handling situations accessing the same file system twice, like
+     * for both the source and destiation of a copy operation.  This allows not only
+     * sharing resources and avoid doing things twice, but also helps avoid file
+     * sharing violations and inconsistencies araising from the image being updated
+     * and read independently.
+     *
+     * @returns true if the element from @a pReuseSpec an be reused, false if not.
+     * @param   pProviderReg    Pointer to the element provider registration.
+     * @param   pSpec           The chain specification.
+     * @param   pElement        The chain element specification.
+     * @param   pReuseSpec      The chain specification of the existing chain.
+     * @param   pReuseElement   The chain element specification of the existing
+     *                          element that is being considered for reuse.
+     */
+    DECLCALLBACKMEMBER(bool, pfnCanReuseElement)(PCRTVFSCHAINELEMENTREG pProviderReg,
+                                                 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
+                                                 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement);
 
     /** 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. */
@@ -1126,30 +1134,36 @@
  *
  * @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, uint32_t fFlags, RTVFSCHAINACTION enmLeadingAction,
-                                            RTVFSCHAINACTION enmTrailingAction,
-                                            PRTVFSCHAINSPEC *ppSpec, const char **ppszError);
+ * @param   pszSpec         The specification string to parse.
+ * @param   fFlags          Flags, see RTVFSCHAIN_PF_XXX.
+ * @param   enmDesiredType  The object type the caller wants to interface with.
+ * @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, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType,
+                                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)
+#define RTVFSCHAIN_PF_VALID_MASK                UINT32_C(0x00000000)
 /** @} */
+
+/**
+ * Checks and setups the chain.
+ *
+ * @returns IPRT status code.
+ * @param   pSpec       The parsed specification.
+ * @param   pReuseSpec  Spec to reuse if applicable. Optional.
+ * @param   phVfsObj    Where to return the VFS object.
+ * @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) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec,
+                                        PRTVFSOBJ phVfsObj, uint32_t *poffError);
 
 /**
@@ -1159,5 +1173,5 @@
  *                              quietly ignored.
  */
-RTDECL(void)            RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec);
+RTDECL(void) RTVfsChainSpecFree(PRTVFSCHAINSPEC pSpec);
 
 /**
Index: /trunk/src/VBox/Runtime/common/misc/message.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/message.cpp	(revision 66593)
+++ /trunk/src/VBox/Runtime/common/misc/message.cpp	(revision 66594)
@@ -138,13 +138,32 @@
     return enmExitCode;
 }
+RT_EXPORT_SYMBOL(RTMsgErrorExit);
+
+
+RTDECL(RTEXITCODE) RTMsgErrorExitV(RTEXITCODE enmExitCode, const char *pszFormat, va_list va)
+{
+    RTMsgErrorV(pszFormat, va);
+    return enmExitCode;
+}
 RT_EXPORT_SYMBOL(RTMsgErrorExitV);
 
 
-RTDECL(RTEXITCODE) RTMsgErrorExitV(RTEXITCODE enmExitCode, const char *pszFormat, va_list va)
-{
-    RTMsgErrorV(pszFormat, va);
-    return enmExitCode;
-}
-RT_EXPORT_SYMBOL(RTMsgErrorExitV);
+RTDECL(RTEXITCODE) RTMsgErrorExitFailure(const char *pszFormat, ...)
+{
+    va_list va;
+    va_start(va, pszFormat);
+    RTMsgErrorV(pszFormat, va);
+    va_end(va);
+    return RTEXITCODE_FAILURE;
+}
+RT_EXPORT_SYMBOL(RTMsgErrorExitFailure);
+
+
+RTDECL(RTEXITCODE) RTMsgErrorExitFailureV(const char *pszFormat, va_list va)
+{
+    RTMsgErrorV(pszFormat, va);
+    return RTEXITCODE_FAILURE;
+}
+RT_EXPORT_SYMBOL(RTMsgErrorExitFailureV);
 
 
Index: /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 66593)
+++ /trunk/src/VBox/Runtime/common/vfs/vfschain.cpp	(revision 66594)
@@ -53,11 +53,13 @@
 *********************************************************************************************************************************/
 /** Init the critical section once. */
-static RTONCE       g_rtVfsChainElementInitOnce;
+static RTONCE       g_rtVfsChainElementInitOnce = RTONCE_INITIALIZER;
 /** Critical section protecting g_rtVfsChainElementProviderList. */
-static RTCRITSECT   g_rtVfsChainElementCritSect;
+static RTCRITSECTRW g_rtVfsChainElementCritSect;
 /** List of VFS chain element providers (RTVFSCHAINELEMENTREG). */
 static RTLISTANCHOR g_rtVfsChainElementProviderList;
 
 
+
+
 /**
  * Initializes the globals via RTOnce.
@@ -69,5 +71,11 @@
 {
     NOREF(pvUser);
-    return RTCritSectInit(&g_rtVfsChainElementCritSect);
+    if (!g_rtVfsChainElementProviderList.pNext)
+        RTListInit(&g_rtVfsChainElementProviderList);
+    int rc = RTCritSectRwInit(&g_rtVfsChainElementCritSect);
+    if (RT_SUCCESS(rc))
+    {
+    }
+    return rc;
 }
 
@@ -84,10 +92,8 @@
     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);
+    AssertPtrReturn(pRegRec->pszName,               VERR_INVALID_POINTER);
+    AssertPtrReturn(pRegRec->pfnValidate,           VERR_INVALID_POINTER);
+    AssertPtrReturn(pRegRec->pfnInstantiate,        VERR_INVALID_POINTER);
+    AssertPtrReturn(pRegRec->pfnCanReuseElement,    VERR_INVALID_POINTER);
 
     /*
@@ -99,8 +105,10 @@
         if (RT_FAILURE(rc))
             return rc;
-        rc = RTCritSectEnter(&g_rtVfsChainElementCritSect);
+        rc = RTCritSectRwEnterExcl(&g_rtVfsChainElementCritSect);
         if (RT_FAILURE(rc))
             return rc;
     }
+    else if (!g_rtVfsChainElementProviderList.pNext)
+        RTListInit(&g_rtVfsChainElementProviderList);
 
     /*
@@ -129,5 +137,5 @@
      */
     if (!fFromCtor)
-        RTCritSectLeave(&g_rtVfsChainElementCritSect);
+        RTCritSectRwLeaveExcl(&g_rtVfsChainElementCritSect);
     return rc;
 }
@@ -144,6 +152,8 @@
     if (pSpec)
     {
-        pSpec->iActionElement = UINT32_MAX;
+        pSpec->fOpenFile      = 0;
+        pSpec->fOpenDir       = 0;
         pSpec->cElements      = 0;
+        pSpec->uProvider      = 0;
         pSpec->paElements     = NULL;
     }
@@ -213,5 +223,5 @@
  *                      code shorter. -lazy bird)
  */
-static PRTVFSCHAINELEMSPEC rtVfsChainSpecAddElement(PRTVFSCHAINSPEC pSpec, int *prc)
+static PRTVFSCHAINELEMSPEC rtVfsChainSpecAddElement(PRTVFSCHAINSPEC pSpec, uint16_t offSpec, int *prc)
 {
     AssertPtr(pSpec);
@@ -240,11 +250,14 @@
     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->enmTypeIn   = iElement ? pSpec->paElements[iElement - 1].enmType : RTVFSOBJTYPE_INVALID;
+    pElement->enmType     = RTVFSOBJTYPE_INVALID;
+    pElement->offSpec     = offSpec;
+    pElement->cchSpec     = 0;
     pElement->cArgs       = 0;
-    pElement->papszArgs   = 0;
-
-    pSpec->cElements  = iElement + 1;
+    pElement->paArgs      = NULL;
+    pElement->pProvider   = NULL;
+    pElement->hVfsObj     = NIL_RTVFSOBJ;
+
+    pSpec->cElements = iElement + 1;
     return pElement;
 }
@@ -260,20 +273,20 @@
  *                              sequences counted twice.
  */
-static int rtVfsChainSpecElementAddArg(PRTVFSCHAINELEMSPEC pElement, const char *psz, size_t cch)
+static int rtVfsChainSpecElementAddArg(PRTVFSCHAINELEMSPEC pElement, const char *psz, size_t cch, uint16_t offSpec)
 {
     uint32_t iArg = pElement->cArgs;
     if ((iArg % 32) == 0)
     {
-        char **papszNew = (char **)RTMemTmpAlloc((iArg + 32 + 1) * sizeof(papszNew[0]));
-        if (!papszNew)
+        PRTVFSCHAINELEMENTARG paNew = (PRTVFSCHAINELEMENTARG)RTMemTmpAlloc((iArg + 32) * sizeof(paNew[0]));
+        if (!paNew)
             return VERR_NO_TMP_MEMORY;
-        memcpy(papszNew, pElement->papszArgs, iArg * sizeof(papszNew[0]));
-        RTMemTmpFree(pElement->papszArgs);
-        pElement->papszArgs = papszNew;
+        memcpy(paNew, pElement->paArgs, iArg * sizeof(paNew[0]));
+        RTMemTmpFree(pElement->paArgs);
+        pElement->paArgs = paNew;
     }
 
     int rc = VINF_SUCCESS;
-    pElement->papszArgs[iArg] = rtVfsChainSpecDupStrN(psz, cch, &rc);
-    pElement->papszArgs[iArg + 1] = NULL;
+    pElement->paArgs[iArg].psz     = rtVfsChainSpecDupStrN(psz, cch, &rc);
+    pElement->paArgs[iArg].offSpec = offSpec;
     pElement->cArgs = iArg + 1;
     return rc;
@@ -291,7 +304,12 @@
         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].paArgs[iArg].psz);
+        RTMemTmpFree(pSpec->paElements[i].paArgs);
         RTMemTmpFree(pSpec->paElements[i].pszProvider);
+        if (pSpec->paElements[i].hVfsObj != NIL_RTVFSOBJ)
+        {
+            RTVfsObjRelease(pSpec->paElements[i].hVfsObj);
+            pSpec->paElements[i].hVfsObj = NIL_RTVFSOBJ;
+        }
     }
 
@@ -326,32 +344,7 @@
 }
 
-/**
- * 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)
+
+RTDECL(int) RTVfsChainSpecParse(const char *pszSpec, uint32_t fFlags, RTVFSOBJTYPE enmDesiredType,
+                                PRTVFSCHAINSPEC *ppSpec, const char **ppszError)
 {
     AssertPtrNullReturn(ppszError, VERR_INVALID_POINTER);
@@ -362,5 +355,5 @@
     AssertPtrReturn(pszSpec, VERR_INVALID_POINTER);
     AssertReturn(!(fFlags & ~RTVFSCHAIN_PF_VALID_MASK), VERR_INVALID_PARAMETER);
-    AssertReturn(enmLeadingAction > RTVFSCHAINACTION_INVALID && enmLeadingAction < RTVFSCHAINACTION_END, VERR_INVALID_PARAMETER);
+    AssertReturn(enmDesiredType > RTVFSOBJTYPE_INVALID && enmDesiredType < RTVFSOBJTYPE_END, VERR_INVALID_PARAMETER);
 
     /*
@@ -369,6 +362,6 @@
     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)
+    const char *pszSrc = RTStrStripL(pszSpec + sizeof(RTVFSCHAIN_SPEC_PREFIX) - 1);
+    if (!*pszSrc)
         return VERR_VFS_CHAIN_EMPTY;
 
@@ -376,54 +369,28 @@
     if (!pSpec)
         return VERR_NO_TMP_MEMORY;
+    pSpec->enmDesiredType = enmDesiredType;
 
     /*
      * Parse the spec one element at a time.
      */
-    int         rc     = VINF_SUCCESS;
-    const char *pszSrc = pszSpec;
+    int rc = VINF_SUCCESS;
     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.
+         * Digest element separator, except for the first element.
          */
-        size_t           cch;
-        RTVFSCHAINACTION enmAction = rtVfsChainSpecEatAction(pszSpec, &cch);
-        if (enmAction != RTVFSCHAINACTION_NONE)
-        {
-            pszSrc = RTStrStripL(pszSrc + cch);
-            if (!*pszSrc)
+        if (*pszSrc == '|' || *pszSrc == ':')
+        {
+            if (pSpec->cElements != 0)
+                pszSrc = RTStrStripL(pszSrc + 1);
+            else
             {
-                /* 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;
+                rc = VERR_VFS_CHAIN_LEADING_SEPARATOR;
                 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;
+        }
+        else if (pSpec->cElements != 0)
+        {
+            rc = VERR_VFS_CHAIN_EXPECTED_SEPARATOR;
             break;
         }
@@ -432,29 +399,33 @@
          * Ok, there should be an element here so add one to the return struct.
          */
-        PRTVFSCHAINELEMSPEC pElement = rtVfsChainSpecAddElement(pSpec, &rc);
+        PRTVFSCHAINELEMSPEC pElement = rtVfsChainSpecAddElement(pSpec, (uint16_t)(pszSrc - pszSpec), &rc);
         if (!pElement)
             break;
-        pElement->enmAction = enmAction;
 
         /*
-         * First up is the VFS object type followed by a parentheses.
+         * First up is the VFS object type followed by a parentheses,
+         * or this could be the trailing action.
          */
+        size_t cch;
         if (strncmp(pszSrc, "base", cch = 4) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_BASE;
+            pElement->enmType = RTVFSOBJTYPE_BASE;
         else if (strncmp(pszSrc, "vfs",  cch = 3) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_VFS;
+            pElement->enmType = RTVFSOBJTYPE_VFS;
         else if (strncmp(pszSrc, "fss",  cch = 3) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_FS_STREAM;
+            pElement->enmType = RTVFSOBJTYPE_FS_STREAM;
         else if (strncmp(pszSrc, "ios",  cch = 3) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_IO_STREAM;
+            pElement->enmType = RTVFSOBJTYPE_IO_STREAM;
         else if (strncmp(pszSrc, "dir",  cch = 3) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_DIR;
+            pElement->enmType = RTVFSOBJTYPE_DIR;
         else if (strncmp(pszSrc, "file", cch = 4) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_FILE;
+            pElement->enmType = RTVFSOBJTYPE_FILE;
         else if (strncmp(pszSrc, "sym",  cch = 3) == 0)
-            pElement->enmTypeOut = RTVFSOBJTYPE_SYMLINK;
+            pElement->enmType = RTVFSOBJTYPE_SYMLINK;
         else
         {
-            rc = VERR_VFS_CHAIN_UNKNOWN_TYPE;
+            if (*pszSrc == '\0')
+                rc = VERR_VFS_CHAIN_TRAILING_SEPARATOR;
+            else
+                rc = VERR_VFS_CHAIN_UNKNOWN_TYPE;
             break;
         }
@@ -490,7 +461,11 @@
             pszSrc = RTStrStripL(pszSrc + 1);
             cch = rtVfsChainSpecFindArgEnd(pszSrc);
-            rc = rtVfsChainSpecElementAddArg(pElement, pszSrc, cch);
+            rc = rtVfsChainSpecElementAddArg(pElement, pszSrc, cch, (uint16_t)(pszSrc - pszSpec));
+            if (RT_FAILURE(rc))
+                break;
             pszSrc += cch;
         }
+        if (RT_FAILURE(rc))
+            break;
 
         /* Must end with a right parentheses. */
@@ -500,6 +475,23 @@
             break;
         }
+        pElement->cchSpec = (uint16_t)(pszSrc - pszSpec) - pElement->offSpec + 1;
+
         pszSrc = RTStrStripL(pszSrc + 1);
     }
+
+#if 1
+    RTAssertMsg2("dbg: cElements=%d rc=%Rrc\n", pSpec->cElements, rc);
+    for (uint32_t i = 0; i < pSpec->cElements; i++)
+    {
+        uint32_t const cArgs = pSpec->paElements[i].cArgs;
+        RTAssertMsg2("dbg: #%u: enmTypeIn=%d enmType=%d cArgs=%d",
+                     i, pSpec->paElements[i].enmTypeIn, pSpec->paElements[i].enmType, cArgs);
+        for (uint32_t j = 0; j < cArgs; j++)
+            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(" spec: %.*s\n", pSpec->paElements[i].cchSpec, &pszSpec[pSpec->paElements[i].offSpec]);
+    }
+#endif
 
     /*
@@ -519,5 +511,183 @@
 
 
-
+/**
+ * Looks up @a pszProvider among the registered providers.
+ *
+ * @returns Pointer to registration record if found, NULL if not.
+ * @param   pszProvider         The provider.
+ */
+static PCRTVFSCHAINELEMENTREG rtVfsChainFindProviderLocked(const char *pszProvider)
+{
+    PCRTVFSCHAINELEMENTREG pIterator;
+    RTListForEach(&g_rtVfsChainElementProviderList, pIterator, RTVFSCHAINELEMENTREG, ListEntry)
+    {
+        if (strcmp(pIterator->pszName, pszProvider) == 0)
+            return pIterator;
+    }
+    return NULL;
+}
+
+
+/**
+ * Does reusable object type matching.
+ *
+ * @returns true if the types matches, false if not.
+ * @param   pElement        The target element specification.
+ * @param   pReuseElement   The source element specification.
+ */
+static bool rtVfsChainMatchReusableType(PRTVFSCHAINELEMSPEC pElement, PRTVFSCHAINELEMSPEC pReuseElement)
+{
+    if (pElement->enmType == pReuseElement->enmType)
+        return true;
+
+    /* File objects can always be cast to I/O streams.  */
+    if (   pElement->enmType == RTVFSOBJTYPE_IO_STREAM
+        && pReuseElement->enmType == RTVFSOBJTYPE_FILE)
+        return true;
+
+    /* I/O stream objects may be file objects. */
+    if (   pElement->enmType == RTVFSOBJTYPE_FILE
+        && pReuseElement->enmType == RTVFSOBJTYPE_IO_STREAM)
+    {
+        RTVFSFILE hVfsFile = RTVfsObjToFile(pReuseElement->hVfsObj);
+        if (hVfsFile != NIL_RTVFSFILE)
+        {
+            RTVfsFileRelease(hVfsFile);
+            return true;
+        }
+    }
+    return false;
+}
+
+
+RTDECL(int) RTVfsChainSpecCheckAndSetup(PRTVFSCHAINSPEC pSpec, PCRTVFSCHAINSPEC pReuseSpec,
+                                        PRTVFSOBJ phVfsObj, uint32_t *poffError)
+{
+    AssertPtrReturn(poffError, VERR_INVALID_POINTER);
+    *poffError = 0;
+    AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
+    *phVfsObj = NIL_RTVFSOBJ;
+    AssertPtrReturn(pSpec, VERR_INVALID_POINTER);
+
+    /*
+     * Enter the critical section after making sure it has been initialized.
+     */
+    int rc = RTOnce(&g_rtVfsChainElementInitOnce, rtVfsChainElementRegisterInit, NULL);
+    if (RT_SUCCESS(rc))
+        rc = RTCritSectRwEnterShared(&g_rtVfsChainElementCritSect);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Resolve and check each element first.
+         */
+        for (uint32_t i = 0; i < pSpec->cElements; i++)
+        {
+            PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i];
+            *poffError = pElement->offSpec;
+            pElement->pProvider = rtVfsChainFindProviderLocked(pElement->pszProvider);
+            if (pElement->pProvider)
+            {
+                rc = pElement->pProvider->pfnValidate(pElement->pProvider, pSpec, pElement, poffError);
+                if (RT_SUCCESS(rc))
+                    continue;
+            }
+            else
+                rc = VERR_VFS_CHAIN_PROVIDER_NOT_FOUND;
+            break;
+        }
+
+        /*
+         * Check that the desired type is compatible with the last element.
+         */
+        if (RT_SUCCESS(rc))
+        {
+            if (pSpec->cElements > 0) /* paranoia */
+            {
+                PRTVFSCHAINELEMSPEC const pLast = &pSpec->paElements[pSpec->cElements - 1];
+                if (   pLast->enmType == pSpec->enmDesiredType
+                    || (   pLast->enmType == RTVFSOBJTYPE_FILE
+                        && pSpec->enmDesiredType == RTVFSOBJTYPE_IO_STREAM) )
+                    rc = VINF_SUCCESS;
+                else
+                {
+                    *poffError = pLast->offSpec;
+                    rc = VERR_VFS_CHAIN_FINAL_TYPE_MISMATCH;
+                }
+            }
+            else
+                rc = VERR_VFS_CHAIN_EMPTY;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Try construct the chain.
+             */
+            RTVFSOBJ hPrevVfsObj = NIL_RTVFSOBJ; /* No extra reference, kept in chain structure. */
+            for (uint32_t i = 0; i < pSpec->cElements; i++)
+            {
+                PRTVFSCHAINELEMSPEC const pElement = &pSpec->paElements[i];
+
+                /*
+                 * Try reuse the VFS objects at the start of the passed in reuse chain.
+                 */
+                if (!pReuseSpec)
+                { /* likely */ }
+                else
+                {
+                    if (i < pReuseSpec->cElements)
+                    {
+                        PRTVFSCHAINELEMSPEC const pReuseElement = &pReuseSpec->paElements[i];
+                        if (pReuseElement->hVfsObj != NIL_RTVFSOBJ)
+                        {
+                            if (strcmp(pElement->pszProvider, pReuseElement->pszProvider) == 0)
+                            {
+                                if (rtVfsChainMatchReusableType(pElement, pReuseElement))
+                                {
+                                    if (pElement->pProvider->pfnCanReuseElement(pElement->pProvider, pSpec, pElement,
+                                                                                pReuseSpec, pReuseElement))
+                                    {
+                                        uint32_t cRefs = RTVfsObjRetain(pReuseElement->hVfsObj);
+                                        if (cRefs != UINT32_MAX)
+                                        {
+                                            pElement->hVfsObj = hPrevVfsObj = pReuseElement->hVfsObj;
+                                            continue;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    pReuseSpec = NULL;
+                }
+
+                /*
+                 * Instantiate a new VFS object.
+                 */
+                RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
+                rc = pElement->pProvider->pfnInstantiate(pElement->pProvider, pSpec, pElement, hPrevVfsObj, &hVfsObj, poffError);
+                if (RT_FAILURE(rc))
+                    break;
+                pElement->hVfsObj = hVfsObj;
+                hPrevVfsObj = hVfsObj;
+            }
+
+            /*
+             * Add another reference to the final object and return.
+             */
+            if (RT_SUCCESS(rc))
+            {
+                uint32_t cRefs = RTVfsObjRetain(hPrevVfsObj);
+                AssertStmt(cRefs != UINT32_MAX, rc = VERR_VFS_CHAIN_IPE);
+                *phVfsObj = hPrevVfsObj;
+            }
+        }
+
+        int rc2 = RTCritSectRwLeaveShared(&g_rtVfsChainElementCritSect);
+        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+            rc = rc2;
+    }
+    return rc;
+}
 
 
@@ -538,5 +708,7 @@
      */
     if (!fFromDtor)
-        RTCritSectEnter(&g_rtVfsChainElementCritSect);
+        RTCritSectRwEnterExcl(&g_rtVfsChainElementCritSect);
+    else if (!g_rtVfsChainElementProviderList.pNext)
+        RTListInit(&g_rtVfsChainElementProviderList);
 
     /*
@@ -559,5 +731,5 @@
      */
     if (!fFromDtor)
-        RTCritSectLeave(&g_rtVfsChainElementCritSect);
+        RTCritSectRwLeaveExcl(&g_rtVfsChainElementCritSect);
     return rc;
 }
@@ -593,15 +765,24 @@
     {
         PRTVFSCHAINSPEC pSpec;
-        rc = RTVfsChainSpecParse(pszSpec,
-                                   RTVFSCHAIN_PF_NO_REAL_ACTION
-                                 | RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL,
-                                 RTVFSCHAINACTION_PASSIVE,
-                                 RTVFSCHAINACTION_NONE,
-                                 &pSpec,
-                                 ppszError);
+        rc = RTVfsChainSpecParse(pszSpec,  0 /*fFlags*/, RTVFSOBJTYPE_FILE, &pSpec, ppszError);
         if (RT_SUCCESS(rc))
         {
-            /** @todo implement this when needed. */
-            rc = VERR_NOT_IMPLEMENTED;
+            pSpec->fOpenFile = fOpen;
+
+            uint32_t offError = 0;
+            RTVFSOBJ hVfsObj  = NIL_RTVFSOBJ;
+            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &offError);
+            if (RT_SUCCESS(rc))
+            {
+                *phVfsFile = RTVfsObjToFile(hVfsObj);
+                if (*phVfsFile)
+                    rc = VINF_SUCCESS;
+                else
+                    rc = VERR_VFS_CHAIN_CAST_FAILED;
+                RTVfsObjRelease(hVfsObj);
+            }
+            else if (ppszError)
+                *ppszError = &pszSpec[offError];
+
             RTVfsChainSpecFree(pSpec);
         }
@@ -641,19 +822,30 @@
         }
     }
+    /*
+     * Do the chain thing.
+     */
     else
     {
         PRTVFSCHAINSPEC pSpec;
-        rc = RTVfsChainSpecParse(pszSpec,
-                                   RTVFSCHAIN_PF_NO_REAL_ACTION
-                                 | RTVFSCHAIN_PF_LEADING_ACTION_OPTIONAL,
-                                 RTVFSCHAINACTION_PASSIVE,
-                                 RTVFSCHAINACTION_NONE,
-                                 &pSpec,
-                                 ppszError);
+        rc = RTVfsChainSpecParse(pszSpec, 0 /*fFlags*/, RTVFSOBJTYPE_IO_STREAM, &pSpec, ppszError);
         if (RT_SUCCESS(rc))
         {
-
-
-            rc = VERR_NOT_IMPLEMENTED;
+            pSpec->fOpenFile = fOpen;
+
+            uint32_t offError = 0;
+            RTVFSOBJ hVfsObj  = NIL_RTVFSOBJ;
+            rc = RTVfsChainSpecCheckAndSetup(pSpec, NULL /*pReuseSpec*/, &hVfsObj, &offError);
+            if (RT_SUCCESS(rc))
+            {
+                *phVfsIos = RTVfsObjToIoStream(hVfsObj);
+                if (*phVfsIos)
+                    rc = VINF_SUCCESS;
+                else
+                    rc = VERR_VFS_CHAIN_CAST_FAILED;
+                RTVfsObjRelease(hVfsObj);
+            }
+            else if (ppszError)
+                *ppszError = &pszSpec[offError];
+
             RTVfsChainSpecFree(pSpec);
         }
Index: /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 66593)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 66594)
@@ -32,7 +32,9 @@
 #include <iprt/vfslowlevel.h>
 
+#include <iprt/assert.h>
 #include <iprt/err.h>
 #include <iprt/file.h>
 #include <iprt/poll.h>
+#include <iprt/string.h>
 #include <iprt/thread.h>
 
@@ -509,2 +511,122 @@
 }
 
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
+ */
+static DECLCALLBACK(int) rtVfsChainStdFile_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
+                                                    PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg);
+
+    /*
+     * Basic checks.
+     */
+    if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
+        return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
+    if (pElement->cArgs < 1)
+        return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
+    if (pElement->cArgs > 4)
+        return VERR_VFS_CHAIN_AT_MOST_FOUR_ARGS;
+    if (!*pElement->paArgs[0].psz)
+        return VERR_VFS_CHAIN_EMPTY_ARG;
+    if (   pElement->enmType != RTVFSOBJTYPE_FILE
+        && pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
+        return VERR_VFS_CHAIN_ONLY_FILE_OR_IOS;
+
+    /*
+     * Calculate the flags, storing them in the first argument.
+     */
+    const char *pszAccess = pElement->cArgs >= 2 ? pElement->paArgs[1].psz : "";
+    if (!*pszAccess)
+        pszAccess = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READWRITE ? "rw"
+                  : (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ      ? "r"
+                  : (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE     ? "w"
+                  :                                                                   "rw";
+
+    const char *pszDisp = pElement->cArgs >= 3 ? pElement->paArgs[2].psz : "";
+    if (!*pszDisp)
+        pszDisp = strchr(pszAccess, 'w') != NULL ? "open-create" : "open";
+
+    const char *pszSharing = pElement->cArgs >= 4 ? pElement->paArgs[3].psz : "";
+
+    int rc = RTFileModeToFlagsEx(pszAccess, pszDisp, pszSharing, &pElement->paArgs[0].uProvider);
+    if (RT_SUCCESS(rc))
+        return VINF_SUCCESS;
+
+    /*
+     * Now try figure out which argument offended us.
+     */
+    AssertReturn(pElement->cArgs > 1, VERR_VFS_CHAIN_IPE);
+    if (   pElement->cArgs == 2
+        || RT_FAILURE(RTFileModeToFlagsEx(pszAccess, "open-create", "", &pElement->paArgs[0].uProvider)))
+        *poffError = pElement->paArgs[1].offSpec;
+    else if (   pElement->cArgs == 3
+             || RT_FAILURE(RTFileModeToFlagsEx(pszAccess, pszDisp, "", &pElement->paArgs[0].uProvider)))
+        *poffError = pElement->paArgs[2].offSpec;
+    else
+        *poffError = pElement->paArgs[3].offSpec;
+    return VERR_VFS_CHAIN_INVALID_ARGUMENT;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
+ */
+static DECLCALLBACK(int) rtVfsChainStdFile_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
+                                                       PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
+                                                       PRTVFSOBJ phVfsObj, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg, pSpec, poffError);
+    AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
+
+    RTVFSFILE hVfsFile;
+    int rc = RTVfsFileOpenNormal(pElement->paArgs[0].psz, pElement->paArgs[0].uProvider, &hVfsFile);
+    if (RT_SUCCESS(rc))
+    {
+        *phVfsObj = RTVfsObjFromFile(hVfsFile);
+        RTVfsFileRelease(hVfsFile);
+        if (*phVfsObj != NIL_RTVFSOBJ)
+            return VINF_SUCCESS;
+        rc = VERR_VFS_CHAIN_CAST_FAILED;
+    }
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
+ */
+static DECLCALLBACK(bool) rtVfsChainStdFile_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
+                                                            PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
+                                                            PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
+{
+    RT_NOREF(pProviderReg, pSpec, pReuseSpec);
+    if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
+        if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
+            return true;
+    return false;
+}
+
+
+/** VFS chain element 'file'. */
+static RTVFSCHAINELEMENTREG g_rtVfsChainStdFileReg =
+{
+    /* uVersion = */            RTVFSCHAINELEMENTREG_VERSION,
+    /* fReserved = */           0,
+    /* pszName = */             "stdfile",
+    /* ListEntry = */           { NULL, NULL },
+    /* pszHelp = */             "Open a real file, providing either a file or an I/O stream object. Initial element.\n"
+                                "First argument is the filename path.\n"
+                                "Second argument is access mode, optional: r, w, rw.\n"
+                                "Third argument is open disposition, optional: create, create-replace, open, open-create, open-append, open-truncate.\n"
+                                "Forth argument is file sharing, optional: nr, nw, nrw, d.",
+    /* pfnValidate = */         rtVfsChainStdFile_Validate,
+    /* pfnInstantiate = */      rtVfsChainStdFile_Instantiate,
+    /* pfnCanReuseElement = */  rtVfsChainStdFile_CanReuseElement,
+    /* uEndMarker = */          RTVFSCHAINELEMENTREG_VERSION
+};
+
+RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdFileReg, rtVfsChainStdFileReg);
+
Index: /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp	(revision 66593)
+++ /trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp	(revision 66594)
@@ -33,4 +33,5 @@
 
 #include <iprt/assert.h>
+#include <iprt/ctype.h>
 #include <iprt/file.h>
 #include <iprt/err.h>
@@ -828,2 +829,188 @@
 }
 
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
+ */
+static DECLCALLBACK(int) rtVfsChainGunzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
+                                                   PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg, poffError);
+
+    if (pElement->enmTypeIn == RTVFSOBJTYPE_INVALID)
+        return VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT;
+    if (pElement->cArgs != 0)
+        return VERR_VFS_CHAIN_NO_ARGS;
+    if (pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
+        return VERR_VFS_CHAIN_ONLY_IOS;
+    if (pSpec->fOpenFile & RTFILE_O_WRITE)
+        return VERR_VFS_CHAIN_READ_ONLY_IOS;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
+ */
+static DECLCALLBACK(int) rtVfsChainGunzip_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
+                                                      PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
+                                                      PRTVFSOBJ phVfsObj, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+    AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
+
+    RTVFSIOSTREAM hVfsIosIn = RTVfsObjToIoStream(hPrevVfsObj);
+    if (hVfsIosIn == NIL_RTVFSIOSTREAM)
+        return VERR_VFS_CHAIN_CAST_FAILED;
+
+    RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
+    int rc = RTZipGzipDecompressIoStream(hVfsIosIn, 0 /*fFlags*/, &hVfsIos);
+    if (RT_SUCCESS(rc))
+    {
+        *phVfsObj = RTVfsObjFromIoStream(hVfsIos);
+        RTVfsIoStrmRelease(hVfsIos);
+        if (*phVfsObj != NIL_RTVFSOBJ)
+            return VINF_SUCCESS;
+        rc = VERR_VFS_CHAIN_CAST_FAILED;
+    }
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
+ */
+static DECLCALLBACK(bool) rtVfsChainGunzip_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
+                                                           PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
+                                                           PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, pReuseSpec, pReuseElement);
+    return false;
+}
+
+
+/** VFS chain element 'gunzip'. */
+static RTVFSCHAINELEMENTREG g_rtVfsChainGunzipReg =
+{
+    /* uVersion = */            RTVFSCHAINELEMENTREG_VERSION,
+    /* fReserved = */           0,
+    /* pszName = */             "gunzip",
+    /* ListEntry = */           { NULL, NULL },
+    /* pszHelp = */             "Takes an I/O stream and gunzips it. No arguments.",
+    /* pfnValidate = */         rtVfsChainGunzip_Validate,
+    /* pfnInstantiate = */      rtVfsChainGunzip_Instantiate,
+    /* pfnCanReuseElement = */  rtVfsChainGunzip_CanReuseElement,
+    /* uEndMarker = */          RTVFSCHAINELEMENTREG_VERSION
+};
+
+RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainGunzipReg, rtVfsChainGunzipReg);
+
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
+ */
+static DECLCALLBACK(int) rtVfsChainGzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
+                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg);
+
+    /*
+     * Basics.
+     */
+    if (pElement->enmTypeIn == RTVFSOBJTYPE_INVALID)
+        return VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT;
+    if (pElement->cArgs > 1)
+        return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
+    if (pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
+        return VERR_VFS_CHAIN_ONLY_IOS;
+    if (pSpec->fOpenFile & RTFILE_O_READ)
+        return VERR_VFS_CHAIN_WRITE_ONLY_IOS;
+
+    /*
+     * Optional argument 1..9 indicating the compression level.
+     * We store it in pSpec->uProvider.
+     */
+    if (pElement->cArgs > 0)
+    {
+        const char *psz = pElement->paArgs[0].psz;
+        if (!*psz || !strcmp(psz, "default"))
+            pSpec->uProvider = 6;
+        else if (!strcmp(psz, "fast"))
+            pSpec->uProvider = 3;
+        else if (   RT_C_IS_DIGIT(*psz)
+                 && *psz != '0'
+                 && *RTStrStripL(psz + 1) == '\0')
+            pSpec->uProvider = *psz - '0';
+        else
+        {
+            *poffError = pElement->paArgs[0].offSpec;
+            return VERR_VFS_CHAIN_INVALID_ARGUMENT;
+        }
+    }
+    else
+        pSpec->uProvider = 6;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
+ */
+static DECLCALLBACK(int) rtVfsChainGzip_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
+                                                    PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
+                                                    PRTVFSOBJ phVfsObj, uint32_t *poffError)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, poffError);
+    AssertReturn(hPrevVfsObj != NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
+
+    RTVFSIOSTREAM hVfsIosOut = RTVfsObjToIoStream(hPrevVfsObj);
+    if (hVfsIosOut == NIL_RTVFSIOSTREAM)
+        return VERR_VFS_CHAIN_CAST_FAILED;
+
+    RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
+    int rc = RTZipGzipCompressIoStream(hVfsIosOut, 0 /*fFlags*/, pSpec->uProvider, &hVfsIos);
+    if (RT_SUCCESS(rc))
+    {
+        *phVfsObj = RTVfsObjFromIoStream(hVfsIos);
+        RTVfsIoStrmRelease(hVfsIos);
+        if (*phVfsObj != NIL_RTVFSOBJ)
+            return VINF_SUCCESS;
+        rc = VERR_VFS_CHAIN_CAST_FAILED;
+    }
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
+ */
+static DECLCALLBACK(bool) rtVfsChainGzip_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
+                                                         PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
+                                                         PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
+{
+    RT_NOREF(pProviderReg, pSpec, pElement, pReuseSpec, pReuseElement);
+    return false;
+}
+
+
+/** VFS chain element 'gzip'. */
+static RTVFSCHAINELEMENTREG g_rtVfsChainGzipReg =
+{
+    /* uVersion = */            RTVFSCHAINELEMENTREG_VERSION,
+    /* fReserved = */           0,
+    /* pszName = */             "gzip",
+    /* ListEntry = */           { NULL, NULL },
+    /* pszHelp = */             "Takes an I/O stream and gzips it.\n"
+                                "Optional argument specifying compression level: 1-9, default, fast",
+    /* pfnValidate = */         rtVfsChainGzip_Validate,
+    /* pfnInstantiate = */      rtVfsChainGzip_Instantiate,
+    /* pfnCanReuseElement = */  rtVfsChainGzip_CanReuseElement,
+    /* uEndMarker = */          RTVFSCHAINELEMENTREG_VERSION
+};
+
+RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainGzipReg, rtVfsChainGzipReg);
+
