Index: /trunk/include/iprt/manifest.h
===================================================================
--- /trunk/include/iprt/manifest.h	(revision 34390)
+++ /trunk/include/iprt/manifest.h	(revision 34391)
@@ -212,5 +212,6 @@
  *                              the expected results.)
  * @param   pszEntry            The entry name.
- * @param   fAttrs              The attributes to create for this stream.
+ * @param   fAttrs              The attributes to create for this stream.  See
+ *                              RTMANIFEST_ATTR_XXX.
  */
 RTDECL(int) RTManifestEntryAddIoStream(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, const char *pszEntry, uint32_t fAttrs);
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 34390)
+++ /trunk/include/iprt/vfs.h	(revision 34391)
@@ -711,4 +711,25 @@
 
 
+/** @defgroup grp_vfs_file          VFS Miscellaneous
+ * @{
+ */
+
+/**
+ * Memorizes the I/O stream as a file backed by memory.
+ *
+ * @returns VBox status code.
+ *
+ * @param   hVfsIos         The VFS I/O stream to memorize.  This will be read
+ *                          to the end on success, on failure its position is
+ *                          undefined.
+ * @param   fFlags          A combination of RTFILE_O_READ and RTFILE_O_WRITE.
+ * @param   phVfsFile       Where to return the handle to the memory file on
+ *                          success.
+ */
+RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile);
+
+/** @}  */
+
+
 /** @defgroup grp_rt_vfs_chain  VFS Chains
  *
Index: /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp
===================================================================
--- /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp	(revision 34390)
+++ /trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp	(revision 34391)
@@ -234,4 +234,142 @@
 }
 
+
+/**
+ * Validates a name in an extension pack.
+ *
+ * We restrict the charset to try make sure the extension pack can be unpacked
+ * on all file systems.
+ *
+ * @returns Program exit code, failure with message.
+ * @param   pszName             The name to validate.
+ */
+static RTEXITCODE ValidateNameInExtPack(const char *pszName)
+{
+    if (RTPathStartsWithRoot(pszName))
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': starts with root spec", pszName);
+
+    const char *pszErr = NULL;
+    const char *psz = pszName;
+    int ch;
+    while ((ch = *psz) != '\0')
+    {
+        /* Character set restrictions. */
+        if (ch < 0 || ch >= 128)
+        {
+            pszErr = "Only 7-bit ASCII allowed";
+            break;
+        }
+        if (ch <= 31 || ch == 127)
+        {
+            pszErr = "No control characters are not allowed";
+            break;
+        }
+        if (ch == '\\')
+        {
+            pszErr = "Only backward slashes are not allowed";
+            break;
+        }
+        if (strchr("'\":;*?|[]<>(){}", ch))
+        {
+            pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed";
+            break;
+        }
+
+        /* Take the simple way out and ban all ".." sequences. */
+        if (   ch     == '.'
+            && psz[1] == '.')
+        {
+            pszErr = "Double dot sequence are not allowed";
+            break;
+        }
+    }
+
+    if (pszErr)
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr);
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Validates a file in an extension pack.
+ *
+ * @returns Program exit code, failure with message.
+ * @param   pszName             The name of the file.
+ * @param   hVfsObj             The VFS object.
+ */
+static RTEXITCODE ValidateFileInExtPack(const char *pszName, RTVFSOBJ hVfsObj)
+{
+    RTEXITCODE rcExit = ValidateNameInExtPack(pszName);
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        RTFSOBJINFO ObjInfo;
+        int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
+        if (RT_SUCCESS(rc))
+        {
+            if (ObjInfo.cbObject >= 9*_1G64)
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': too large (%'RU64 bytes)",
+                                        pszName, (uint64_t)ObjInfo.cbObject);
+            if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                        "The alleged file '%s' has a mode mask saying differently (%RTfmode)",
+                                        pszName, ObjInfo.Attr.fMode);
+        }
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
+    }
+    return rcExit;
+}
+
+
+/**
+ * Validates a directory in an extension pack.
+ *
+ * @returns Program exit code, failure with message.
+ * @param   pszName             The name of the directory.
+ * @param   hVfsObj             The VFS object.
+ */
+static RTEXITCODE ValidateDirInExtPack(const char *pszName, RTVFSOBJ hVfsObj)
+{
+    RTEXITCODE rcExit = ValidateNameInExtPack(pszName);
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        RTFSOBJINFO ObjInfo;
+        int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
+        if (RT_SUCCESS(rc))
+        {
+            if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                        "The alleged directory '%s' has a mode mask saying differently (%RTfmode)",
+                                        pszName, ObjInfo.Attr.fMode);
+        }
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
+    }
+    return rcExit;
+}
+
+/**
+ * Validates a member of an extension pack.
+ *
+ * @returns Program exit code, failure with message.
+ * @param   pszName             The name of the directory.
+ * @param   enmType             The object type.
+ * @param   hVfsObj             The VFS object.
+ */
+static RTEXITCODE ValidateMemberOfExtPack(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj)
+{
+    RTEXITCODE rcExit;
+    if (   enmType == RTVFSOBJTYPE_FILE
+        || enmType == RTVFSOBJTYPE_IO_STREAM)
+        rcExit = ValidateFileInExtPack(pszName, hVfsObj);
+    else if (   enmType == RTVFSOBJTYPE_DIR
+             || enmType == RTVFSOBJTYPE_BASE)
+        rcExit = ValidateDirInExtPack(pszName, hVfsObj);
+    else
+        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s' is not a file or directory (enmType=%d)", pszName, enmType);
+    return rcExit;
+}
+
+
 /**
  * Validates the extension pack tarball prior to unpacking.
@@ -304,9 +442,140 @@
     RTMANIFEST hManifest;
     int rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
-
-    /** @todo continue coding here! */
-    AssertRC(rc);
-
-    return RTEXITCODE_FAILURE;
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Process the tarball.
+         */
+        RTVFSFILE hXmlFile      = NIL_RTVFSFILE;
+        RTVFSFILE hManifestFile = NIL_RTVFSFILE;
+        RTVFSFILE hSignFile     = NIL_RTVFSFILE;
+        for (;;)
+        {
+            /*
+             * Get the next stream object.
+             */
+            char           *pszName;
+            RTVFSOBJ        hVfsObj;
+            RTVFSOBJTYPE    enmType;
+            rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
+            if (RT_FAILURE(rc))
+            {
+                if (rc != VERR_EOF)
+                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext failed: %Rrc", rc);
+                break;
+            }
+
+            /*
+             * Check the type & name validity.
+             */
+            rcExit = ValidateMemberOfExtPack(pszName, enmType, hVfsObj);
+            if (rcExit == RTEXITCODE_SUCCESS)
+            {
+                /*
+                 * Check if this is one of the standard files.
+                 */
+                const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
+                PRTVFSFILE  phVfsFile;
+                if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME))
+                    phVfsFile = &hXmlFile;
+                else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME))
+                    phVfsFile = &hManifestFile;
+                else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME))
+                    phVfsFile = &hSignFile;
+                else
+                    phVfsFile = NULL;
+                if (phVfsFile)
+                {
+                    /*
+                     * Make sure it's a file and that it isn't too large.
+                     */
+                    if (*phVfsFile != NIL_RTVFSFILE)
+                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "There can only be one '%s'", pszAdjName);
+                    else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE)
+                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName);
+                    else
+                    {
+                        RTFSOBJINFO ObjInfo;
+                        rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
+                        if (RT_SUCCESS(rc))
+                        {
+                            if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
+                                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName);
+                            else if (ObjInfo.cbObject >= _1M)
+                                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                                        "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)",
+                                                        pszAdjName, (uint64_t)ObjInfo.cbObject);
+                            else
+                            {
+                                /*
+                                 * Make an in memory copy of the stream.
+                                 */
+                                RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
+                                rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsFile);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    /*
+                                     * To simplify the code below, replace
+                                     * hVfsObj with the memorized file.
+                                     */
+                                    RTVfsObjRelease(hVfsObj);
+                                    hVfsObj = RTVfsObjFromFile(*phVfsFile);
+                                }
+                                else
+                                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+                                                            "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszName, rc);
+                                RTVfsIoStrmRelease(hVfsIos);
+                            }
+                        }
+                        else
+                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
+                    }
+                }
+            }
+
+            /*
+             * Add any I/O stream to the manifest
+             */
+            if (   rcExit == RTEXITCODE_SUCCESS
+                && (   enmType == RTVFSOBJTYPE_FILE
+                    || enmType == RTVFSOBJTYPE_IO_STREAM))
+            {
+                RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
+                rc = RTManifestEntryAddIoStream(hManifest, hVfsIos, pszName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256);
+                if (RT_FAILURE(rc))
+                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszName, rc);
+                RTVfsIoStrmRelease(hVfsIos);
+            }
+
+            /*
+             * Clean up and break out on failure.
+             */
+            RTVfsObjRelease(hVfsObj);
+            RTStrFree(pszName);
+            if (rcExit != RTEXITCODE_SUCCESS)
+                break;
+        }
+
+        /*
+         * If we've successfully processed the tarball, verify that the
+         * mandatory files are present.
+         */
+        if (rcExit == RTEXITCODE_SUCCESS)
+        {
+            if (hXmlFile == NIL_RTVFSFILE)
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME);
+            if (hManifestFile == NIL_RTVFSFILE)
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME);
+            if (hSignFile == NIL_RTVFSFILE)
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME);
+        }
+
+
+
+        RTManifestRelease(hManifest);   /** @todo return this and use it during unpacking */
+    }
+    RTVfsFsStrmRelease(hTarFss);
+
+    return rcExit;
 }
 
Index: /trunk/src/VBox/Main/include/ExtPackUtil.h
===================================================================
--- /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 34390)
+++ /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 34391)
@@ -26,4 +26,10 @@
  * The name of the description file in an extension pack.  */
 #define VBOX_EXTPACK_DESCRIPTION_NAME   "ExtPack.xml"
+/** @name VBOX_EXTPACK_DESCRIPTION_NAME
+ * The name of the manifest file in an extension pack.  */
+#define VBOX_EXTPACK_MANIFEST_NAME      "ExtPack.manifest"
+/** @name VBOX_EXTPACK_SIGNATURE_NAME
+ * The name of the signature file in an extension pack.  */
+#define VBOX_EXTPACK_SIGNATURE_NAME     "ExtPack.signature"
 /** @name VBOX_EXTPACK_SUFFIX
  * The suffix of a extension pack tarball. */
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 34390)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 34391)
@@ -372,4 +372,5 @@
 	common/vfs/vfsbase.cpp \
 	common/vfs/vfschain.cpp \
+	common/vfs/vfsmemory.cpp \
 	common/vfs/vfsmisc.cpp \
 	common/vfs/vfsstdfile.cpp \
Index: /trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp	(revision 34391)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsmemory.cpp	(revision 34391)
@@ -0,0 +1,56 @@
+/* $Id$ */
+/** @file
+ * IPRT - Virtual File System, Memory Files.
+ */
+
+/*
+ * 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 "internal/iprt.h"
+#include <iprt/vfs.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/handle.h>
+
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/vfs.h>
+
+#include <iprt/err.h>
+#include <iprt/mem.h>
+
+
+
+
+RTDECL(int) RTVfsMemorizeIoStreamAsFile(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTVFSFILE phVfsFile)
+{
+    return VERR_NOT_IMPLEMENTED;
+}
