ExtPackUtil.cpp revision 441579693f771e49eb05f2bd20c316232155675b
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/* $Id$ */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/** @file
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2010-2012 Oracle Corporation
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * available from http://www.virtualbox.org. This file is free software;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * you can redistribute it and/or modify it under the terms of the GNU
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * General Public License (GPL) as published by the Free Software
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/*******************************************************************************
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync* Header Files *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync*******************************************************************************/
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include "../include/ExtPackUtil.h"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/ctype.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/dir.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/file.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/manifest.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/param.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/path.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/sha.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/string.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/vfs.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/tar.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/zip.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <iprt/cpp/xml.h>
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#include <VBox/log.h>
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Worker for VBoxExtPackLoadDesc that loads the plug-in descriptors.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @returns Same as VBoxExtPackLoadDesc.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param pVBoxExtPackElm
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pcPlugIns Where to return the number of plug-ins in the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * array.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param paPlugIns Where to return the plug-in descriptor array.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * (RTMemFree it even on failure)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsyncstatic RTCString *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvboxExtPackLoadPlugInDescs(const xml::ElementNode *pVBoxExtPackElm,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync uint32_t *pcPlugIns, PVBOXEXTPACKPLUGINDESC *paPlugIns)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *pcPlugIns = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *paPlugIns = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /** @todo plug-ins */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync NOREF(pVBoxExtPackElm);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Clears the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The descriptor to clear.
376b92d26cc4fad78e813cf33afcc0784adc9b19vboxsync */
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncstatic void vboxExtPackClearDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync{
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strName.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strDescription.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strVersion.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strEdition.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->uRevision = 0;
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strMainModule.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->strVrdeModule.setNull();
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->cPlugIns = 0;
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync a_pExtPackDesc->paPlugIns = NULL;
376b92d26cc4fad78e813cf33afcc0784adc9b19vboxsync a_pExtPackDesc->fShowLicense = false;
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync}
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync/**
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * Initializes an extension pack descriptor so that it's safe to call free on
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * it whatever happens later on.
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The descirptor to initialize.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid VBoxExtPackInitDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackClearDesc(a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Load the extension pack descriptor from an XML document.
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync *
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync * @returns NULL on success, pointer to an error message on failure (caller
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync * deletes it).
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pDoc Pointer to the the XML document.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsyncstatic RTCString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Get the main element and check its version.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if ( !pVBoxExtPackElm
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString("No VirtualBoxExtensionPack element");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString strFormatVersion;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString("Missing format version");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!strFormatVersion.equals("1.0"))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString("Unsupported format version: "))->append(strFormatVersion);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Read and validate mandatory bits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pNameElm)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString("The 'Name' element is missing");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *pszName = pNameElm->getValue();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!VBoxExtPackIsValidName(pszName))
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return &(new RTCString("Invalid name: "))->append(pszName);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pDescElm)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' element is missing");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const char *pszDesc = pDescElm->getValue();
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pszDesc || *pszDesc == '\0')
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' element is empty");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' must not contain control characters");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pVersionElm)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Version' element is missing");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const char *pszVersion = pVersionElm->getValue();
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pszVersion || *pszVersion == '\0')
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Version' element is empty");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!VBoxExtPackIsValidVersionString(pszVersion))
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return &(new RTCString("Invalid version string: "))->append(pszVersion);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync uint32_t uRevision;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pVersionElm->getAttributeValue("revision", uRevision))
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync uRevision = 0;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const char *pszEdition;
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pVersionElm->getAttributeValue("edition", pszEdition))
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync pszEdition = "";
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync if (!VBoxExtPackIsValidEditionString(pszEdition))
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return &(new RTCString("Invalid edition string: "))->append(pszEdition);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync if (!pMainModuleElm)
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return new RTCString("The 'MainModule' element is missing");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync const char *pszMainModule = pMainModuleElm->getValue();
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync if (!pszMainModule || *pszMainModule == '\0')
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return new RTCString("The 'MainModule' element is empty");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync if (!VBoxExtPackIsValidModuleString(pszMainModule))
9cb702c3a5fd2287c57c7c1e98a61ba9e357b4devboxsync return &(new RTCString("Invalid main module string: "))->append(pszMainModule);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync
6fe1329154975472e055284198df7fa8e64dee3avboxsync /*
6fe1329154975472e055284198df7fa8e64dee3avboxsync * The VRDE module, optional.
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Accept both none and empty as tokens of no VRDE module.
6fe1329154975472e055284198df7fa8e64dee3avboxsync */
6fe1329154975472e055284198df7fa8e64dee3avboxsync const char *pszVrdeModule = NULL;
6fe1329154975472e055284198df7fa8e64dee3avboxsync const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule");
6fe1329154975472e055284198df7fa8e64dee3avboxsync if (pVrdeModuleElm)
6fe1329154975472e055284198df7fa8e64dee3avboxsync {
6fe1329154975472e055284198df7fa8e64dee3avboxsync pszVrdeModule = pVrdeModuleElm->getValue();
6fe1329154975472e055284198df7fa8e64dee3avboxsync if (!pszVrdeModule || *pszVrdeModule == '\0')
6fe1329154975472e055284198df7fa8e64dee3avboxsync pszVrdeModule = NULL;
6fe1329154975472e055284198df7fa8e64dee3avboxsync else if (!VBoxExtPackIsValidModuleString(pszVrdeModule))
6fe1329154975472e055284198df7fa8e64dee3avboxsync return &(new RTCString("Invalid VRDE module string: "))->append(pszVrdeModule);
6fe1329154975472e055284198df7fa8e64dee3avboxsync }
6fe1329154975472e055284198df7fa8e64dee3avboxsync
6fe1329154975472e055284198df7fa8e64dee3avboxsync /*
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Whether to show the license, optional. (presense is enough here)
6fe1329154975472e055284198df7fa8e64dee3avboxsync */
6fe1329154975472e055284198df7fa8e64dee3avboxsync const xml::ElementNode *pShowLicenseElm = pVBoxExtPackElm->findChildElement("ShowLicense");
6fe1329154975472e055284198df7fa8e64dee3avboxsync bool fShowLicense = pShowLicenseElm != NULL;
6fe1329154975472e055284198df7fa8e64dee3avboxsync
6fe1329154975472e055284198df7fa8e64dee3avboxsync /*
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Parse plug-in descriptions (last because of the manual memory management).
6fe1329154975472e055284198df7fa8e64dee3avboxsync */
6fe1329154975472e055284198df7fa8e64dee3avboxsync uint32_t cPlugIns = 0;
6fe1329154975472e055284198df7fa8e64dee3avboxsync PVBOXEXTPACKPLUGINDESC paPlugIns = NULL;
6fe1329154975472e055284198df7fa8e64dee3avboxsync RTCString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns);
6fe1329154975472e055284198df7fa8e64dee3avboxsync if (pstrRet)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync RTMemFree(paPlugIns);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync return pstrRet;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync }
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /*
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Everything seems fine, fill in the return values and return successfully.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strName = pszName;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strDescription = pszDesc;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strVersion = pszVersion;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strEdition = pszEdition;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->uRevision = uRevision;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strMainModule = pszMainModule;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->strVrdeModule = pszVrdeModule;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->cPlugIns = cPlugIns;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->paPlugIns = paPlugIns;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync a_pExtPackDesc->fShowLicense = fShowLicense;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync return NULL;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync}
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/**
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Reads the extension pack descriptor.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync *
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * @returns NULL on success, pointer to an error message on failure (caller
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * deletes it).
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * @param a_pszDir The directory containing the description file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pObjInfo Where to store the object info for the file (unix
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * attribs). Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
ae16af2d7d3c99d359094a7f19f5937efc2e66bdvboxsync vboxExtPackClearDesc(a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validate, open and parse the XML file.
ae017640afff8b6cc50453182a4edf2eb0903a12vboxsync */
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync char szFilePath[RTPATH_MAX];
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (RT_FAILURE(vrc))
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return new RTCString("RTPathJoin failed with %Rrc", vrc);
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync RTFSOBJINFO ObjInfo;
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (RT_FAILURE(vrc))
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return &(new RTCString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (a_pObjInfo)
8b7ee9f7ebabcdbf40fececa0d6321d97d5143d8vboxsync *a_pObjInfo = ObjInfo;
8b7ee9f7ebabcdbf40fececa0d6321d97d5143d8vboxsync if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync {
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return new RTCString("The XML file is symlinked, that is not allowed");
31a693ce9a8a9ebbecdcea9f24ce7f912aef4cd1vboxsync return &(new RTCString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync }
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync xml::Document Doc;
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync {
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync xml::XmlFileParser Parser;
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync try
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync {
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync Parser.read(szFilePath, Doc);
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync }
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync catch (xml::XmlError Err)
ae017640afff8b6cc50453182a4edf2eb0903a12vboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString(Err.what());
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync }
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync }
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync /*
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * Hand the xml doc over to the common code.
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync */
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync return vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
ae16af2d7d3c99d359094a7f19f5937efc2e66bdvboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Reads the extension pack descriptor.
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync *
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * @returns NULL on success, pointer to an error message on failure (caller
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * deletes it).
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * @param a_pszDir The directory containing the description file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pObjInfo Where to store the object info for the file (unix
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * attribs). Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackClearDesc(a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Query the object info.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTFSOBJINFO ObjInfo;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (a_pObjInfo)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *a_pObjInfo = ObjInfo;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * The simple approach, read the whole thing into memory and pass this to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * the XML parser.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Check the file size. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync return &(new RTCString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync size_t const cbFile = (size_t)ObjInfo.cbObject;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Rewind to the start of the file. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc);
42aef05f4b27fb393967e581be04be455064c80avboxsync
42aef05f4b27fb393967e581be04be455064c80avboxsync /* Allocate memory and read the file content into it. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync void *pvFile = RTMemTmpAlloc(cbFile);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync if (!pvFile)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTMemTmpAlloc(%zu) failed", cbFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString *pstrErr = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrErr = &(new RTCString)->printf("RTVfsFileRead failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Parse the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync xml::Document Doc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync xml::XmlMemParser Parser;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync try
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync Parser.read(pvFile, cbFile, strFileName, Doc);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync }
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync catch (xml::XmlError Err)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync {
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync pstrErr = new RTCString(Err.what());
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync rc = VERR_PARSE_ERROR;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMemTmpFree(pvFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Hand the xml doc over to the common code.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return pstrErr;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Frees all resources associated with a extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The extension pack descriptor which members
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * should be freed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strName.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strDescription.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strVersion.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strEdition.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->uRevision = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strMainModule.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->strVrdeModule.setNull();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->cPlugIns = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMemFree(a_pExtPackDesc->paPlugIns);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->paPlugIns = NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync a_pExtPackDesc->fShowLicense = false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync * Extract the extension pack name from the tarball path.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns String containing the name on success, the caller must delete it.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * NULL if no valid name was found or if we ran out of memory.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarball The path to the tarball.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Skip ahead to the filename part and count the number of characters
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * that matches the criteria for a mangled extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *pszSrc = RTPathFilename(pszTarball);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pszSrc)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync return NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync size_t off = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == '_')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync off++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if ( off > VBOX_EXTPACK_NAME_MAX_LEN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || off < VBOX_EXTPACK_NAME_MIN_LEN)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return NULL;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Return the unmangled name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return VBoxExtPackUnmangleName(pszSrc, off);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates the extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns true if valid, false if not.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @sa VBoxExtPackExtractNameFromTarballPath
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncbool VBoxExtPackIsValidName(const char *pszName)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pszName)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the characters making up the name, only english alphabet
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * characters, decimal digits and spaces are allowed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync size_t off = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (pszName[off])
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!RT_C_IS_ALNUM(pszName[off]) && pszName[off] != ' ')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync off++;
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if ( off > VBOX_EXTPACK_NAME_MAX_LEN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || off < VBOX_EXTPACK_NAME_MIN_LEN)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return true;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Checks if an alledged manged extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns true if valid, false if not.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszMangledName The mangled name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cchMax The max number of chars to test.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @sa VBoxExtPackMangleName
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncbool VBoxExtPackIsValidMangledName(const char *pszMangledName, size_t cchMax /*= RTSTR_MAX*/)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pszMangledName)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the characters making up the name, only english alphabet
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * characters, decimal digits and underscores (=space) are allowed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync size_t off = 0;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (off < cchMax && pszMangledName[off])
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!RT_C_IS_ALNUM(pszMangledName[off]) && pszMangledName[off] != '_')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync off++;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if ( off > VBOX_EXTPACK_NAME_MAX_LEN
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || off < VBOX_EXTPACK_NAME_MIN_LEN)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4f3d37f3c8ea851c3d57304fac430764b77a84dcvboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return true;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync/**
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Mangle an extension pack name so it can be used by a directory or file name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync *
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns String containing the mangled name on success, the caller must
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * delete it. NULL on failure.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszName The unmangled name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @sa VBoxExtPackUnmangleName, VBoxExtPackIsValidMangledName
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync */
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncRTCString *VBoxExtPackMangleName(const char *pszName)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidName(pszName), NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync size_t off = 0;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync char ch;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync while ((ch = pszName[off]) != '\0')
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync {
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (ch == ' ')
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ch = '_';
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync szTmp[off++] = ch;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync }
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync szTmp[off] = '\0';
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync Assert(VBoxExtPackIsValidMangledName(szTmp));
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return new RTCString(szTmp, off);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync/**
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Unmangle an extension pack name (reverses VBoxExtPackMangleName).
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync *
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns String containing the mangled name on success, the caller must
4f3d37f3c8ea851c3d57304fac430764b77a84dcvboxsync * delete it. NULL on failure.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszMangledName The mangled name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param cchMax The max name length. RTSTR_MAX is fine.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @sa VBoxExtPackMangleName, VBoxExtPackIsValidMangledName
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync */
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncRTCString *VBoxExtPackUnmangleName(const char *pszMangledName, size_t cchMax)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidMangledName(pszMangledName, cchMax), NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1];
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync size_t off = 0;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync char ch;
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync while ( off < cchMax
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync && (ch = pszMangledName[off]) != '\0')
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync {
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (ch == '_')
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync ch = ' ';
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync else
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(RT_C_IS_ALNUM(ch) || ch == ' ', NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync szTmp[off++] = ch;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync }
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync szTmp[off] = '\0';
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidName(szTmp), NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return new RTCString(szTmp, off);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync}
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync/**
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Constructs the extension pack directory path.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync *
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * A combination of RTPathJoin and VBoxExtPackMangleName.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync *
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns IPRT status code like RTPathJoin.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszExtPackDir Where to return the directory path.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param cbExtPackDir The size of the return buffer.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszParentDir The parent directory (".../Extensions").
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszName The extension pack name, unmangled.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync */
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncint VBoxExtPackCalcDir(char *pszExtPackDir, size_t cbExtPackDir, const char *pszParentDir, const char *pszName)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync{
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidName(pszName), VERR_INTERNAL_ERROR_5);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync RTCString *pstrMangledName = VBoxExtPackMangleName(pszName);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync if (!pstrMangledName)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return VERR_INTERNAL_ERROR_4;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync int vrc = RTPathJoin(pszExtPackDir, cbExtPackDir, pszParentDir, pstrMangledName->c_str());
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync delete pstrMangledName;
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync return vrc;
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync}
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync/**
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Validates the extension pack version string.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync *
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns true if valid, false if not.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszVersion The version string to validate.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync */
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncbool VBoxExtPackIsValidVersionString(const char *pszVersion)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync{
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (!pszVersion || *pszVersion == '\0')
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /* 1.x.y.z... */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync for (;;)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (!RT_C_IS_DIGIT(*pszVersion))
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync do
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pszVersion++;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync while (RT_C_IS_DIGIT(*pszVersion));
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (*pszVersion != '.')
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync break;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pszVersion++;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /* upper case string + numbers indicating the build type */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (*pszVersion == '-' || *pszVersion == '_')
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /** @todo Should probably restrict this to known build types (alpha,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * beta, rc, ++). */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync do
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pszVersion++;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync while ( RT_C_IS_DIGIT(*pszVersion)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || RT_C_IS_UPPER(*pszVersion)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || *pszVersion == '-'
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || *pszVersion == '_');
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return *pszVersion == '\0';
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync}
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync/**
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validates the extension pack edition string.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync *
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns true if valid, false if not.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param pszEdition The edition string to validate.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsyncbool VBoxExtPackIsValidEditionString(const char *pszEdition)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync{
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (*pszEdition)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (!RT_C_IS_UPPER(*pszEdition))
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync do
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pszEdition++;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync while ( RT_C_IS_UPPER(*pszEdition)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || RT_C_IS_DIGIT(*pszEdition)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || *pszEdition == '-'
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync || *pszEdition == '_');
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return *pszEdition == '\0';
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync}
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync/**
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validates an extension pack module string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync *
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @returns true if valid, false if not.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszModule The module string to validate.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync */
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncbool VBoxExtPackIsValidModuleString(const char *pszModule)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync{
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync if (!pszModule || *pszModule == '\0')
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync return false;
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync /* Restricted charset, no extensions (dots). */
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync while ( RT_C_IS_ALNUM(*pszModule)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync || *pszModule == '-'
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync || *pszModule == '_')
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync pszModule++;
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync return *pszModule == '\0';
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync}
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync/**
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * RTStrPrintfv wrapper.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync *
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @returns @a rc
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param rc The status code to return.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszError The error buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param cbError The size of the buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszFormat The error message format string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param ... Format arguments.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync */
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncstatic int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync{
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync va_list va;
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync va_start(va, pszFormat);
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync RTStrPrintfV(pszError, cbError, pszFormat, va);
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync va_end(va);
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync return rc;
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync}
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync/**
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * RTStrPrintfv wrapper.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync *
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszError The error buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param cbError The size of the buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszFormat The error message format string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param ... Format arguments.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync */
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncstatic void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync va_list va;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync va_start(va, pszFormat);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTStrPrintfV(pszError, cbError, pszFormat, va);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync va_end(va);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the manifest and its signature.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hManifestFile The xml from the extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszExtPackName The expected extension pack name. This can be
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * NULL, in which we don't have any expectations.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Load the XML.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync VBOXEXTPACKDESC ExtPackDesc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString *pstrErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &ExtPackDesc, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (pstrErr)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTStrCopy(pszError, cbError, pstrErr->c_str());
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync delete pstrErr;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return VERR_PARSE_ERROR;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /** @todo drop this restriction after the old install interface is
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * dropped. */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int rc = VINF_SUCCESS;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if ( pszExtPackName
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync && !ExtPackDesc.strName.equalsIgnoreCase(pszExtPackName))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_NOT_EQUAL, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "The name of the downloaded file and the name stored inside the extension pack does not match"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync " (xml='%s' file='%s')", ExtPackDesc.strName.c_str(), pszExtPackName);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the manifest and its signature.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param hOurManifest The manifest we compiled.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param hManifestFile The manifest file in the extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hSignatureFile The manifest signature file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Read the manifest from the extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMANIFEST hTheirManifest;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestReadStandard(hTheirManifest, hVfsIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hVfsIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Compare the manifests.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync static const char *s_apszIgnoreEntries[] =
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync VBOX_EXTPACK_MANIFEST_NAME,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync VBOX_EXTPACK_SIGNATURE_NAME,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync "./" VBOX_EXTPACK_MANIFEST_NAME,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync "./" VBOX_EXTPACK_SIGNATURE_NAME,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync NULL
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync };
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync char szError[RTPATH_MAX];
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync szError, sizeof(szError));
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (RT_SUCCESS(rc))
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync {
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /*
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validate the manifest file signature.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /** @todo implement signature stuff */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync NOREF(hSignatureFile);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync else if (rc == VERR_NOT_EQUAL && szError[0])
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError);
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync else
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#if 0
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM;
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestWriteStandard(hOurManifest, hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync#endif
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync RTManifestRelease(hTheirManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync}
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the file digest (if specified) and returns the SHA-256 of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hFileManifest Manifest containing a SHA-256 digest of the file
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * that was calculated as the file was processed.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszFileDigest SHA-256 digest of the file.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pStrDigest Where to return the SHA-256 digest. Optional.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszError Where to write an error message on failure.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param cbError The size of the @a pszError buffer.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyFileDigest(RTMANIFEST hFileManifest, const char *pszFileDigest,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString *pStrDigest, char *pszError, size_t cbError)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Extract the SHA-256 entry for the extpack file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync char szCalculatedDigest[RTSHA256_DIGEST_LEN + 1];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTManifestEntryQueryAttr(hFileManifest, "extpack", NULL /*no name*/, RTMANIFEST_ATTR_SHA256,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync szCalculatedDigest, sizeof(szCalculatedDigest), NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Convert the two strings to binary form before comparing.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * We convert the calculated hash even if we don't have anything to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * compare with, just to validate it.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync uint8_t abCalculatedHash[RTSHA256_HASH_SIZE];
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync rc = RTSha256FromString(szCalculatedDigest, abCalculatedHash);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync {
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync if ( pszFileDigest
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync && *pszFileDigest != '\0')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync uint8_t abFileHash[RTSHA256_HASH_SIZE];
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTSha256FromString(pszFileDigest, abFileHash);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (memcmp(abFileHash, abCalculatedHash, sizeof(abFileHash)))
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "The extension pack file has changed (SHA-256 mismatch)");
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = VERR_NOT_EQUAL;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Set the output hash on success.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (pStrDigest && RT_SUCCESS(rc))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync try
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync *pStrDigest = szCalculatedDigest;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync catch (std::bad_alloc)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = VERR_NO_MEMORY;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync }
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryGetAttr: %Rrc", rc);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync return rc;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync}
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync * Validates a standard file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Generally all files are
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync *
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @returns VBox status code, failure message in @a pszError.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param pszAdjName The adjusted member name.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param enmType The VFS object type.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param phVfsObj The pointer to the VFS object handle variable.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * This is both input and output.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param phVfsFile Where to store the handle to the memorized
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * file. This is NULL for license files.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszError Where to write an error message on failure.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param cbError The size of the @a pszError buffer.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncstatic int VBoxExtPackValidateStandardFile(const char *pszAdjName, RTVFSOBJTYPE enmType,
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync PRTVFSOBJ phVfsObj, PRTVFSFILE phVfsFile, char *pszError, size_t cbError)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync{
3933885bc0c2c93436d858a14564c6179ec72872vboxsync int rc;
3933885bc0c2c93436d858a14564c6179ec72872vboxsync
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /*
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Make sure it's a file and that it isn't too large.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (phVfsFile && *phVfsFile != NIL_RTVFSFILE)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_DUPLICATE, pszError, cbError,
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync "There can only be one '%s'", pszAdjName);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync "Standard member '%s' is not a file", pszAdjName);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync RTFSOBJINFO ObjInfo;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync rc = RTVfsObjQueryInfo(*phVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (RT_SUCCESS(rc))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync "Standard member '%s' is not a file", pszAdjName);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else if (ObjInfo.cbObject >= _1M)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)",
3933885bc0c2c93436d858a14564c6179ec72872vboxsync pszAdjName, (uint64_t)ObjInfo.cbObject);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else
3933885bc0c2c93436d858a14564c6179ec72872vboxsync {
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /*
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Make an in memory copy of the stream and check that the file
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * is UTF-8 clean.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(*phVfsObj);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSFILE hVfsFile;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, &hVfsFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsIoStrmValidateUtf8Encoding(hVfsIos,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFS_VALIDATE_UTF8_BY_RTC_3629 | RTVFS_VALIDATE_UTF8_NO_NULL,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Replace *phVfsObj with the memorized file.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync */
501181107e73684ab109521ba371063734cd1d76vboxsync rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
501181107e73684ab109521ba371063734cd1d76vboxsync if (RT_SUCCESS(rc))
501181107e73684ab109521ba371063734cd1d76vboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsObjRelease(*phVfsObj);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *phVfsObj = RTVfsObjFromFile(hVfsFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsFileSeek failed on '%s': %Rrc", pszAdjName, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (phVfsFile && RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *phVfsFile = hVfsFile;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync else
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync RTVfsFileRelease(hVfsFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszAdjName, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hVfsIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszAdjName, rc);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
501181107e73684ab109521ba371063734cd1d76vboxsync
501181107e73684ab109521ba371063734cd1d76vboxsync/**
501181107e73684ab109521ba371063734cd1d76vboxsync * Validates a name in an extension pack.
501181107e73684ab109521ba371063734cd1d76vboxsync *
501181107e73684ab109521ba371063734cd1d76vboxsync * We restrict the charset to try make sure the extension pack can be unpacked
501181107e73684ab109521ba371063734cd1d76vboxsync * on all file systems.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pszName The name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsyncstatic int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RTPathStartsWithRoot(pszName))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *pszErr = NULL;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync const char *psz = pszName;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int ch;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while ((ch = *psz) != '\0')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Character set restrictions. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ch < 0 || ch >= 128)
28ae9ced88db55943497a8bb98682bc2be513476vboxsync {
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "Only 7-bit ASCII allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync break;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync }
28ae9ced88db55943497a8bb98682bc2be513476vboxsync if (ch <= 31 || ch == 127)
28ae9ced88db55943497a8bb98682bc2be513476vboxsync {
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "No control characters are not allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync break;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync }
28ae9ced88db55943497a8bb98682bc2be513476vboxsync if (ch == '\\')
28ae9ced88db55943497a8bb98682bc2be513476vboxsync {
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "Only backward slashes are not allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync break;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync }
28ae9ced88db55943497a8bb98682bc2be513476vboxsync if (strchr("'\":;*?|[]<>(){}", ch))
28ae9ced88db55943497a8bb98682bc2be513476vboxsync {
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync break;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync }
28ae9ced88db55943497a8bb98682bc2be513476vboxsync
28ae9ced88db55943497a8bb98682bc2be513476vboxsync /* Take the simple way out and ban all ".." sequences. */
28ae9ced88db55943497a8bb98682bc2be513476vboxsync if ( ch == '.'
28ae9ced88db55943497a8bb98682bc2be513476vboxsync && psz[1] == '.')
28ae9ced88db55943497a8bb98682bc2be513476vboxsync {
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "Double dot sequence are not allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync break;
28ae9ced88db55943497a8bb98682bc2be513476vboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
03a954338932c2b34361f1d27ae2029828db0958vboxsync /* Keep the tree shallow or the hardening checks will fail. */
03a954338932c2b34361f1d27ae2029828db0958vboxsync if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH)
03a954338932c2b34361f1d27ae2029828db0958vboxsync {
03a954338932c2b34361f1d27ae2029828db0958vboxsync pszErr = "Too long";
03a954338932c2b34361f1d27ae2029828db0958vboxsync break;
03a954338932c2b34361f1d27ae2029828db0958vboxsync }
03a954338932c2b34361f1d27ae2029828db0958vboxsync
03a954338932c2b34361f1d27ae2029828db0958vboxsync /* advance */
03a954338932c2b34361f1d27ae2029828db0958vboxsync psz++;
03a954338932c2b34361f1d27ae2029828db0958vboxsync }
03a954338932c2b34361f1d27ae2029828db0958vboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (pszErr)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return RTEXITCODE_SUCCESS;
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync}
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates a file in an extension pack.
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync *
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hVfsObj The VFS object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsyncstatic int vboxExtPackValidateMemberFile(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync if (RT_SUCCESS(rc))
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync {
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync RTFSOBJINFO ObjInfo;
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ObjInfo.cbObject >= 9*_1G64)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "'%s': too large (%'RU64 bytes)",
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync pszName, (uint64_t)ObjInfo.cbObject);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync "The alleged file '%s' has a mode mask stating otherwise (%RTfmode)",
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync pszName, ObjInfo.Attr.fMode);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync }
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync else
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync }
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync return rc;
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync}
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync/**
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync * Validates a directory in an extension pack.
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param pszName The name of the directory.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param hVfsObj The VFS object.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param pszError Where to store an error message on failure.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param cbError The size of the buffer @a pszError points to.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync */
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsyncstatic int vboxExtPackValidateMemberDir(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync{
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync if (RT_SUCCESS(rc))
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync {
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync RTFSOBJINFO ObjInfo;
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
c9e3f6ad81ea9a279ffb537720699e552882c40avboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_NOT_A_DIRECTORY, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "The alleged directory '%s' has a mode mask saying differently (%RTfmode)",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pszName, ObjInfo.Attr.fMode);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates a member of an extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name of the directory.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param enmType The object type.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hVfsObj The VFS object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync Assert(cbError > 0);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *pszError = '\0';
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if ( enmType == RTVFSOBJTYPE_FILE
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || enmType == RTVFSOBJTYPE_IO_STREAM)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackValidateMemberFile(pszName, hVfsObj, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else if ( enmType == RTVFSOBJTYPE_DIR
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || enmType == RTVFSOBJTYPE_BASE)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackValidateMemberDir(pszName, hVfsObj, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_UNEXPECTED_FS_OBJ_TYPE, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "'%s' is not a file or directory (enmType=%d)", pszName, enmType);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Rewinds the tarball file handle and creates a gunzip | tar chain that
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * results in a filesystem stream.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hTarballFile The handle to the tarball file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param phTarFss Where to return the filesystem stream handle.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param phFileManifest Where to return a manifest where the tarball is
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * gettting hashed. The entry will be called
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * "extpack" and be ready when the file system
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * stream is at an end. Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync Assert(cbError > 0);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *pszError = '\0';
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *phTarFss = NIL_RTVFSFSSTREAM;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Rewind the file and set up a VFS chain for it.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hTarballIos;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync &hTarballIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMANIFEST hFileManifest = NIL_RTMANIFEST;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hPtIos;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestEntryAddPassthruIoStream(hFileManifest, hTarballIos, "extpack", RTMANIFEST_ATTR_SHA256, true /*read*/, &hPtIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hGunzipIos;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTZipGzipDecompressIoStream(hPtIos, 0 /*fFlags*/, &hGunzipIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSFSSTREAM hTarFss;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hPtIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hGunzipIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hTarballIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *phTarFss = hTarFss;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (phFileManifest)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *phFileManifest = hFileManifest;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestRelease(hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return VINF_SUCCESS;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hGunzipIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hPtIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddPassthruIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestRelease(hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync }
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync else
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmRelease(hTarballIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync}
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/**
c9e3f6ad81ea9a279ffb537720699e552882c40avboxsync * Validates the extension pack tarball prior to unpacking.
21ed14a0d745501ffc9a68be81c0abadc777b628vboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Operations performed:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Mandatory files.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Manifest check.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Manifest seal check.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - XML check, match name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hTarballFile The handle to open the @a pszTarball file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszExtPackName The name of the extension pack name. NULL if
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * the name is not fixed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarball The name of the tarball in case we have to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * complain about something.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarballDigest The SHA-256 digest of the tarball. Empty string
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * if no digest available.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
629169500a4e1696f37dd3118a791d68278f71davboxsync * @param phValidManifest Where to optionally return the handle to fully
629169500a4e1696f37dd3118a791d68278f71davboxsync * validated the manifest for the extension pack.
629169500a4e1696f37dd3118a791d68278f71davboxsync * This includes all files.
629169500a4e1696f37dd3118a791d68278f71davboxsync * @param phXmlFile Where to optionally return the memorized XML
629169500a4e1696f37dd3118a791d68278f71davboxsync * file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pStrDigest Where to return the digest of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *pszTarball, const char *pszTarballDigest,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync char *pszError, size_t cbError,
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile, RTCString *pStrDigest)
94c4b844625733fedcd2b473c207981b31316bd9vboxsync{
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Clear return values.
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync */
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync if (phValidManifest)
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync *phValidManifest = NIL_RTMANIFEST;
94c4b844625733fedcd2b473c207981b31316bd9vboxsync if (phXmlFile)
94c4b844625733fedcd2b473c207981b31316bd9vboxsync *phXmlFile = NIL_RTVFSFILE;
94c4b844625733fedcd2b473c207981b31316bd9vboxsync Assert(cbError > 1);
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync *pszError = '\0';
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync NOREF(pszTarball);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /*
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync * Open the tar.gz filesystem stream and set up an manifest in-memory file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMANIFEST hFileManifest;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSFSSTREAM hTarFss;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss, &hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return rc;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTMANIFEST hOurManifest;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest);
4c13f0d619c9707412b40eae8e3beafae5cf1858vboxsync if (RT_SUCCESS(rc))
94c4b844625733fedcd2b473c207981b31316bd9vboxsync {
94c4b844625733fedcd2b473c207981b31316bd9vboxsync /*
94c4b844625733fedcd2b473c207981b31316bd9vboxsync * Process the tarball (would be nice to move this to a function).
94c4b844625733fedcd2b473c207981b31316bd9vboxsync */
94c4b844625733fedcd2b473c207981b31316bd9vboxsync RTVFSFILE hXmlFile = NIL_RTVFSFILE;
94c4b844625733fedcd2b473c207981b31316bd9vboxsync RTVFSFILE hManifestFile = NIL_RTVFSFILE;
94c4b844625733fedcd2b473c207981b31316bd9vboxsync RTVFSFILE hSignatureFile = NIL_RTVFSFILE;
94c4b844625733fedcd2b473c207981b31316bd9vboxsync for (;;)
94c4b844625733fedcd2b473c207981b31316bd9vboxsync {
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Get the next stream object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync char *pszName;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSOBJ hVfsObj;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSOBJTYPE enmType;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_FAILURE(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (rc != VERR_EOF)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync else
94c4b844625733fedcd2b473c207981b31316bd9vboxsync rc = VINF_SUCCESS;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync break;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync }
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync /*
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * Check the type & name validity, performing special tests on
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * standard extension pack member files.
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync *
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * N.B. We will always reach the end of the loop before breaking on
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * failure - cleanup reasons.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync */
ae16af2d7d3c99d359094a7f19f5937efc2e66bdvboxsync rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync {
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync PRTVFSFILE phVfsFile = NULL;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync phVfsFile = &hXmlFile;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync phVfsFile = &hManifestFile;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync phVfsFile = &hSignatureFile;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strncmp(pszAdjName, VBOX_EXTPACK_LICENSE_NAME_PREFIX, sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX) - 1))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, NULL, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync if (phVfsFile)
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, phVfsFile, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync }
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync /*
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Add any I/O stream to the manifest
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync */
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync if ( RT_SUCCESS(rc)
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync && ( enmType == RTVFSOBJTYPE_FILE
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync || enmType == RTVFSOBJTYPE_IO_STREAM))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync {
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync if (RT_FAILURE(rc))
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync RTVfsIoStrmRelease(hVfsIos);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync }
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync /*
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Clean up and break out on failure.
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync */
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync RTVfsObjRelease(hVfsObj);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync RTStrFree(pszName);
844af57b369279e0d79e59b433ab16aa83b47df2vboxsync if (RT_FAILURE(rc))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync break;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync }
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync /*
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Check the integrity of the tarball file.
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync */
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync if (RT_SUCCESS(rc))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync {
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync RTVfsFsStrmRelease(hTarFss);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync hTarFss = NIL_RTVFSFSSTREAM;
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = vboxExtPackVerifyFileDigest(hFileManifest, pszTarballDigest, pStrDigest, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync }
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync /*
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * If we've successfully processed the tarball, verify that the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * mandatory files are present.
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (RT_SUCCESS(rc))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync {
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (hXmlFile == NIL_RTVFSFILE)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME);
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync if (hManifestFile == NIL_RTVFSFILE)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (hSignatureFile == NIL_RTVFSFILE)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME);
}
/*
* Check the manifest and it's signature.
*/
if (RT_SUCCESS(rc))
rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError);
/*
* Check the XML.
*/
if (RT_SUCCESS(rc))
rc = vboxExtPackVerifyXml(hXmlFile, pszExtPackName, pszError, cbError);
/*
* Returns objects.
*/
if (RT_SUCCESS(rc))
{
if (phValidManifest)
{
RTManifestRetain(hOurManifest);
*phValidManifest = hOurManifest;
}
if (phXmlFile)
{
RTVfsFileRetain(hXmlFile);
*phXmlFile = hXmlFile;
}
}
/*
* Release our object references.
*/
RTManifestRelease(hOurManifest);
RTVfsFileRelease(hXmlFile);
RTVfsFileRelease(hManifestFile);
RTVfsFileRelease(hSignatureFile);
}
else
vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
RTVfsFsStrmRelease(hTarFss);
RTManifestRelease(hFileManifest);
return rc;
}