VirtualBox

Changeset 76271 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 18, 2018 5:29:30 AM (6 years ago)
Author:
vboxsync
Message:

Overhauled around Klaus's snapshot/locking design.. Stubbed out attempted encryption code for now, generates appropriate message for encrypted disks for now. Unit tested, w/close attention to locking, against running VMs (btw: the wide listing shows media state for helpful w.r.t. to determining lock state)

Location:
trunk/src/VBox/ImageMounter/vboximg-mount
Files:
5 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ImageMounter/vboximg-mount/Makefile.kmk

    r76033 r76271  
    2020
    2121ifeq ($(KBUILD_TARGET),darwin)
    22  VBOX_PATH_FUSE ?= $(lastword $(sort $(wildcard $(KBUILD_DEVTOOLS_TRG)/osxfuse/v*)))
     22 VBOX_PATH_FUSE := $(lastword $(sort $(wildcard $(KBUILD_DEVTOOLS_TRG)/osxfuse/v*)))
    2323 ifneq ($(VBOX_PATH_FUSE),)
    2424  LIB_FUSE     := $(VBOX_PATH_FUSE)/lib/libosxfuse.dylib
     
    4848    vboximg-mount.cpp \
    4949    vboximg-mount.h \
     50    vboximgCrypto.cpp \
     51    vboximgCrypto.h \
     52    vboximgMedia.cpp \
     53    vboximgMedia.h \
     54    vboximgOpts.h \
    5055    SelfSizingTable.h
    5156
  • trunk/src/VBox/ImageMounter/vboximg-mount/vboximg-mount.cpp

    r76130 r76271  
    3636#include <unistd.h>
    3737#include <math.h>
    38 //#include <stdarg.h>
    3938#include <cstdarg>
    4039#include <sys/stat.h>
     
    6160#include <VBox/com/array.h>
    6261#include <VBox/com/errorprint.h>
    63 
     62#include <VBox/vd-plugin.h>
    6463#include <iprt/initterm.h>
    6564#include <iprt/assert.h>
     
    7473#include <iprt/path.h>
    7574#include <iprt/utf16.h>
     75#include <iprt/base64.h>
    7676
    7777#include "vboximg-mount.h"
     78#include "vboximgCrypto.h"
     79#include "vboximgMedia.h"
    7880#include "SelfSizingTable.h"
     81#include "vboximgOpts.h"
    7982
    8083using namespace com;
     
    8487};
    8588
    86 /* For getting the basename of the image path */
    87 union
    88 {
    89     RTPATHSPLIT split;
    90     uint8_t     abPad[RTPATH_MAX + 1024];
    91 } g_u;
    92 
    93 #if 0 /* unused */
    94 const uint64_t KB = 1024;
    95 const uint64_t MB = KB * KB;
    96 const uint64_t GB = MB * KB;
    97 const uint64_t TB = GB * KB;
    98 const uint64_t PB = TB * KB;
    99 #endif
    100 
    10189enum { PARTITION_TABLE_MBR = 1, PARTITION_TABLE_GPT = 2 };
    10290
     91#define VBOX_EXTPACK                "Oracle VM VirtualBox Extension Pack"
    10392#define GPT_PTABLE_SIZE             32 * BLOCKSIZE   /** Max size we to read for GPT partition table */
    10493#define MBR_PARTITIONS_MAX          4                /** Fixed number of partitions in Master Boot Record */
     
    114103#define VD_SECTOR_MASK              (VD_SECTOR_SIZE - 1)    /** Masks off a blocks worth of data */
    115104#define VD_SECTOR_OUT_OF_BOUNDS_MASK  (~UINT64_C(VD_SECTOR_MASK))         /** Masks the overflow of a blocks worth of data */
    116 
     105#define VERBOSE                     g_vboximgOpts.fVerbose
    117106#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
    118107
     
    131120
    132121static PVDISK                g_pVDisk;              /** Handle for Virtual Disk in contet */
    133 static char                 *g_pvDiskUuid;          /** UUID of image (if known, otherwise NULL) */
     122static char                 *g_pszDiskUuid;          /** UUID of image (if known, otherwise NULL) */
    134123static off_t                 g_vDiskOffset;         /** Biases r/w from start of VD */
    135124static off_t                 g_vDiskSize;           /** Limits r/w length for VD */
     
    137126static int32_t               g_cWriters;            /** Number of writers for VD */
    138127static RTFOFF                g_cbEntireVDisk;       /** Size of VD */
    139 static char                 *g_pszBaseImageName;    /** Base filename for current VD image */
    140 static char                 *g_pszBaseImagePath;    /** Full path to current VD image */
    141128static PVDINTERFACE          g_pVdIfs;              /** @todo Remove when VD I/O becomes threadsafe */
    142129static VDINTERFACETHREADSYNC g_VDIfThreadSync;      /** @todo Remove when VD I/O becomes threadsafe */
     
    144131static uint16_t              g_lastPartNbr;         /** Last partition number found in MBR + EBR chain */
    145132static bool                  g_fGPT;                /** True if GPT type partition table was found */
     133static char                 *g_pszImageName;        /** Base filename for current VD image */
     134static char                 *g_pszImagePath;        /** Full path to current VD image */
     135static char                 *g_pszBaseImagePath;    /** Base image known after parsing */
     136static char                 *g_pszBaseImageName;    /** Base image known after parsing */
     137static uint32_t              g_cImages;             /** Number of images in diff chain */
    146138
    147139/* Table entry containing partition info parsed out of GPT or MBR and EBR chain of specified VD */
     
    168160PARTITIONINFO g_aParsedPartitionInfo[VBOXIMG_PARTITION_MAX + 1]; /* Note: Element 0 reserved for EntireDisk partitionEntry */
    169161
    170 static struct vboximgOpts {
    171      char         *pszVm;                   /** optional VM UUID */
    172      char         *pszImage;                /** Virtual Disk image UUID or path */
    173      int32_t       idxPartition;            /** Number of partition to constrain FUSE based FS to (optional) 0 - whole disk*/
    174      int32_t       offset;                  /** Offset to base virtual disk reads and writes from (altnerative to partition) */
    175      int32_t       size;                    /** Size of accessible disk region, starting at offset, default = offset 0 */
    176      uint32_t      cHddImageDiffMax;        /** Max number of differencing images (snapshots) to apply to image */
    177      uint32_t      fListMediaLong;          /** Flag to list virtual disks of all known VMs */
    178      uint32_t      fList;                   /** Flag to list virtual disks of all known VMs */
    179      uint32_t      fListParts;              /** Flag to summarily list partitions associated with pszImage */
    180      uint32_t      fAllowRoot;              /** Flag to allow root to access this FUSE FS */
    181      uint32_t      fRW;                     /** Flag to allow changes to FUSE-mounted Virtual Disk image */
    182      uint32_t      fBriefUsage;             /** Flag to display only FS-specific program usage options */
    183      uint32_t      fVerbose;                /** Add more info to lists and operations */
    184 } g_vboximgOpts;
     162VBOXIMGOPTS g_vboximgOpts;
    185163
    186164#define OPTION(fmt, pos, val) { fmt, offsetof(struct vboximgOpts, pos), val }
    187165
    188166static struct fuse_opt vboximgOptDefs[] = {
    189     OPTION("-l",              fList,             1),
    190     OPTION("--list",          fList,             1),
    191     OPTION("--root",          fAllowRoot,        1),
    192     OPTION("--vm=%s",         pszVm,             0),
    193     OPTION("--maxdiff=%d",    cHddImageDiffMax,  1),
    194     OPTION("--diff=%d",       cHddImageDiffMax,  1),
    195     OPTION("--partition=%d",  idxPartition,      1),
    196     OPTION("-p %d",           idxPartition,      1),
    197     OPTION("--offset=%d",     offset,            1),
    198     OPTION("-o %d",           offset,            1),
    199     OPTION("--size=%d",       size,              1),
    200     OPTION("-s %d",           size,              1),
    201     OPTION("--image=%s",      pszImage,          0),
    202     OPTION("-i %s",           pszImage,          0),
    203     OPTION("--rw",            fRW,               1),
    204     OPTION("--verbose",       fVerbose,          1),
    205     OPTION("-v",              fVerbose,          1),
    206     OPTION("-h",              fBriefUsage,       1),
     167    OPTION("--image=%s",      pszImageUuidOrPath,   0),
     168    OPTION("-i %s",           pszImageUuidOrPath,   0),
     169    OPTION("--rw",            fRW,                  1),
     170    OPTION("--root",          fAllowRoot,           0),
     171    OPTION("--vm=%s",         pszVm,                0),
     172    OPTION("--partition=%d",  idxPartition,         1),
     173    OPTION("-p %d",           idxPartition,         1),
     174    OPTION("--offset=%d",     offset,               1),
     175    OPTION("-o %d",           offset,               1),
     176    OPTION("--size=%d",       size,                 1),
     177    OPTION("-s %d",           size,                 1),
     178    OPTION("-l",              fList,                1),
     179    OPTION("--list",          fList,                1),
     180    OPTION("--verbose",       fVerbose,             1),
     181    OPTION("-v",              fVerbose,             1),
     182    OPTION("--wide",          fWide,                1),
     183    OPTION("-w",              fWide,                1),
     184    OPTION("-lv",             fVerboseList,         1),
     185    OPTION("-vl",             fVerboseList,         1),
     186    OPTION("-lw",             fWideList,            1),
     187    OPTION("-wl",             fWideList,            1),
     188    OPTION("-h",              fBriefUsage,          1),
    207189    FUSE_OPT_KEY("--help",    USAGE_FLAG),
    208190    FUSE_OPT_KEY("-vm",       FUSE_OPT_KEY_NONOPT),
     
    210192};
    211193
     194typedef struct IMAGELIST
     195{
     196    struct IMAGELIST *next;
     197    struct IMAGELIST *prev;
     198    ComPtr<IToken> pLockToken;
     199    bool   fWriteable;
     200    ComPtr<IMedium> pImage;
     201    Bstr   pImageName;
     202    Bstr   pImagePath;
     203} IMAGELIST;
     204
     205IMAGELIST listHeadLockList;  /* flink & blink intentionally left NULL */
     206
    212207static void
    213208briefUsage()
    214209{
    215     RTPrintf("usage: vboximg-mount [options] <mountpoint>\n\n"
     210    RTPrintf("usage: vboximg-mount [options] <mount point directory path>\n\n"
    216211        "vboximg-mount options:\n\n"
    217         "  [ { -i | --image= } <specifier> ]  VirtualBox disk image (UUID, name or path)\n"
     212        "  [ { -i | --image= } <specifier> ]  VirtualBox disk base or snapshot image,\n"
     213        "                                     specified by UUID, or fully-qualified path\n"
    218214        "\n"
    219         "  [ { -l | --list } ]                If image specified, list its partitions, \n"
    220         "                                     otherwise, list registered VMs and\n"
    221         "                                     associated disks. In verbose mode,\n"
    222         "                                     VM/media list will be long format, i.e.\n"
    223         "                                     including snapshot images and file paths.\n"
     215        "  [ { -l | --list } ]                If --image specified, list its partitions,\n"
     216        "                                     otherwise, list registered VMs and their\n"
     217        "                                     attached virtual HDD disk media. In verbose\n"
     218        "                                     mode, VM/media list will be long format,\n"
     219        "                                     i.e. including snapshot images and paths.\n"
     220        "\n"
     221        " [ { -w | --wide } ]                 List media in wide / tabular format\n"
     222        "                                     (reduces vertical scrolling but requires\n"
     223        "                                     wider than standard 80 column window\n)"
    224224        "\n"
    225225        "  [ --vm=UUID ]                      Restrict media list to specified vm.\n"
     
    233233        "                                     (incompatible with -p, --partition)\n"
    234234        "\n"
    235         "  [ { --diff=<diff #> } ]            Limits default operation (of applying all\n"
    236         "                                     snapshots of virtual disk) to specified\n"
    237         "                                     disk differencing image #. Diffs will\n"
    238         "                                     be merged-in up to and including diff #.\n"
    239         "                                     (default: All diffs, 0 = No diffs)\n"
     235        "  [ --rw ]                           Make image writeable (default = readonly)\n"
    240236        "\n"
    241         "  [ --rw ]                           Make image writeable (default = readonly)\n"
    242237        "  [ --root ]                         Same as -o allow_root.\n"
    243238        "\n"
    244         "  [ { -v | --verbose }]              Log extra information.\n"
     239        "  [ { -v | --verbose } ]              Log extra information.\n"
    245240        "\n"
    246241        "  [ -o opt[,opt...]]                 FUSE mount options.\n"
     
    249244        "  [ --help ]                         Display long usage info (incl. FUSE opts).\n\n"
    250245    );
    251     RTPrintf("\n");
    252     RTPrintf("When successful, the --image option instantiates a one-directory-deep FUSE\n");
    253     RTPrintf("filesystem rooted at the specified mountpoint.  Its contents are a\n");
    254     RTPrintf("symbolic link named as basename of the image path, pointing to full path of\n");
    255     RTPrintf("the virtual disk image. Also a regular file named 'vhdd', which is a device\n");
    256     RTPrintf("node through which a raw byte stream of the disk image (as synthesized by\n");
    257     RTPrintf("the VirtualBox runtime engine) can be accessed. It is the vhdd file that the\n");
    258     RTPrintf("user or a utility can subsequently mount on the host OS.\n");
     246    RTPrintf("\n"
     247      "vboximg-mount is a utility to make VirtualBox disk images available to the host\n"
     248      "operating system in a root or non-root accessible way. The user determines the\n"
     249      "historical representation of the disk by choosing either the base image or a\n"
     250      "snapshot, to establish the desired level of currency of the mounted disk.\n"
     251      "\n"
     252      "The disk image is mounted through this utility inside a FUSE-based filesystem\n"
     253      "that overlays the user-provided mount point. The FUSE filesystem presents a\n"
     254      "a directory that contains two files: an HDD pseudo device node and a symbolic\n"
     255      "link. The device node is named 'vhdd' and is the access point to the synthesized\n"
     256      "state of the virtual disk. It is the entity that can be mounted or otherwise\n"
     257      "accessed through the host OS. The symbolic link is given the same name as the\n"
     258      "base image, as determined from '--image' option argument. The link equates\n"
     259      "to the specified image's location (path).\n"
     260      "\n"
     261      "If the user provides a base image UUID/path with the --image option, only\n"
     262      "the base image will be exposed via vhdd, disregarding any snapshots.\n"
     263      "Alternatively, if a snapshot (e.g. disk differencing image) is provided,\n"
     264      "the chain of snapshots is calculated from that \"leaf\" snapshot\n"
     265      "to the base image and the whole chain of images is merged to form the exposed\n"
     266      "state of the FUSE-mounted disk.\n"
     267      "\n"
     268
     269    );
    259270}
    260271
     
    262273vboximgOptHandler(void *data, const char *arg, int optKey, struct fuse_args *outargs)
    263274{
    264     (void) data;
    265     (void) arg;
    266     (void) optKey;
    267     (void) outargs;
     275    NOREF(data);
     276    NOREF(arg);
     277    NOREF(optKey);
     278    NOREF(outargs);
     279
    268280    /*
    269281     * Apparently this handler is only called for arguments FUSE can't parse,
     
    280292static int vboximgOp_open(const char *pszPath, struct fuse_file_info *pInfo)
    281293{
    282     RT_NOREF(pszPath, pInfo);
     294    RT_NOREF(pszPath, pInfo);;
    283295    LogFlowFunc(("pszPath=%s\n", pszPath));
    284296    uint32_t notsup = 0;
     
    339351}
    340352
     353
    341354/** @todo Remove when VD I/O becomes threadsafe */
    342355static DECLCALLBACK(int) vboximgThreadStartRead(void *pvUser)
     
    368381static int vboximgOp_release(const char *pszPath, struct fuse_file_info *pInfo)
    369382{
    370     (void) pszPath;
     383    NOREF(pszPath);
    371384
    372385    LogFlowFunc(("pszPath=%s\n", pszPath));
     
    578591                           off_t offset, struct fuse_file_info *pInfo)
    579592{
    580     (void) pszPath;
    581     (void) pInfo;
     593    NOREF(pszPath);
     594    NOREF(pInfo);
    582595
    583596    LogFlowFunc(("my offset=%#llx size=%#zx path=\"%s\"\n", (uint64_t)offset, cbBuf, pszPath));
     
    609622                           off_t offset, struct fuse_file_info *pInfo)
    610623{
    611     (void) pszPath;
    612     (void) pInfo;
     624    NOREF(pszPath);
     625    NOREF(pInfo);
    613626
    614627    LogFlowFunc(("offset=%#llx size=%#zx path=\"%s\"\n", (uint64_t)offset, cbBuf, pszPath));
     
    646659    int rc = 0;
    647660
    648     LogFlowFunc(("pszPath=%s, stat(\"%s\")\n", pszPath, g_pszBaseImagePath));
     661    LogFlowFunc(("pszPath=%s, stat(\"%s\")\n", pszPath, g_pszImagePath));
    649662
    650663    memset(stbuf, 0, sizeof(struct stat));
     
    657670    else if (RTStrCmp(pszPath + 1, "vhdd") == 0)
    658671    {
    659         rc = stat(g_pszBaseImagePath, stbuf);
     672        rc = stat(g_pszImagePath, stbuf);
    660673        if (rc < 0)
    661674            return rc;
     
    668681        stbuf->st_nlink = 1;
    669682    }
    670     else if (RTStrNCmp(pszPath + 1, g_pszBaseImageName, strlen(g_pszBaseImageName)) == 0)
     683    else if (RTStrNCmp(pszPath + 1, g_pszImageName, strlen(g_pszImageName)) == 0)
    671684    {
    672685        /* When the disk is partitioned, the symbolic link named from `basename` of
     
    678691         *  simple_fixed_disk.vdi[20480:2013244928]    vhdd
    679692         */
    680         rc = stat(g_pszBaseImagePath, stbuf);
     693        rc = stat(g_pszImagePath, stbuf);
    681694        if (rc < 0)
    682695            return rc;
     
    698711
    699712{
    700     (void) offset;
    701     (void) pInfo;
     713    NOREF(offset);
     714    NOREF(pInfo);
    702715
    703716    if (RTStrCmp(pszPath, "/") != 0)
     
    719732
    720733    if (g_vDiskOffset == 0 && (g_vDiskSize == 0 || g_vDiskSize == g_cbEntireVDisk))
    721         pfnFiller(pvBuf, g_pszBaseImageName, NULL, 0);
     734        pfnFiller(pvBuf, g_pszImageName, NULL, 0);
    722735    else
    723736    {
    724737        char tmp[BASENAME_MAX];
    725         RTStrPrintf(tmp, sizeof (tmp), "%s[%d:%d]", g_pszBaseImageName, g_vDiskOffset, g_vDiskSize);
     738        RTStrPrintf(tmp, sizeof (tmp), "%s[%jd:%jd]", g_pszImageName, g_vDiskOffset, g_vDiskSize);
    726739        pfnFiller(pvBuf, tmp, NULL, 0);
    727740    }
     
    739752vboximgOp_readlink(const char *pszPath, char *buf, size_t size)
    740753{
    741     (void) pszPath;
    742     RTStrCopy(buf, size, g_pszBaseImagePath);
     754    NOREF(pszPath);
     755    RTStrCopy(buf, size, g_pszImagePath);
    743756    return 0;
    744 }
    745 
    746 static void
    747 listMedia(IMachine *pMachine, char *vmName, char *vmUuid)
    748 {
    749     int rc = 0;
    750     com::SafeIfaceArray<IMediumAttachment> pMediumAttachments;
    751 
    752     CHECK_ERROR(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(pMediumAttachments)));
    753     int firstIteration = 1;
    754     for (size_t i = 0; i < pMediumAttachments.size(); i++)
    755     {
    756 
    757         ComPtr<IMedium> pMedium;
    758         DeviceType_T deviceType;
    759         Bstr pMediumUuid;
    760         Bstr pMediumName;
    761         Bstr pMediumPath;
    762 
    763         CHECK_ERROR(pMediumAttachments[i], COMGETTER(Type)(&deviceType));
    764 
    765         if (deviceType == DeviceType_HardDisk)
    766         {
    767             CHECK_ERROR(pMediumAttachments[i], COMGETTER(Medium)(pMedium.asOutParam()));
    768             if (pMedium.isNull())
    769                 return;
    770 
    771             MediumState_T state;
    772             CHECK_ERROR(pMedium, COMGETTER(State)(&state));
    773             if (FAILED(rc))
    774                 return;
    775             if (state == MediumState_Inaccessible)
    776             {
    777                 CHECK_ERROR(pMedium, RefreshState(&state));
    778                 if (FAILED(rc))
    779                 return;
    780             }
    781 
    782             ComPtr<IMedium> pEarliestAncestor;
    783             CHECK_ERROR(pMedium, COMGETTER(Base)(pEarliestAncestor.asOutParam()));
    784             ComPtr<IMedium> pChild = pEarliestAncestor;
    785             uint32_t ancestorNumber = 0;
    786             if (pEarliestAncestor.isNull())
    787                 return;
    788             do
    789             {
    790                 com::SafeIfaceArray<IMedium> aMediumChildren;
    791                 CHECK_ERROR(pChild, COMGETTER(Name)(pMediumName.asOutParam()));
    792                 CHECK_ERROR(pChild, COMGETTER(Id)(pMediumUuid.asOutParam()));
    793                 CHECK_ERROR(pChild, COMGETTER(Location)(pMediumPath.asOutParam()));
    794 
    795                 if (ancestorNumber == 0)
    796                 {
    797                     if (g_vboximgOpts.fVerbose)
    798                     {
    799                         RTPrintf("   -----------------------\n");
    800                         RTPrintf("   HDD base:   \"%s\"\n",   CSTR(pMediumName));
    801                         RTPrintf("   UUID:       %s\n",       CSTR(pMediumUuid));
    802                         RTPrintf("   Location:   %s\n\n",     CSTR(pMediumPath));
    803                     }
    804                     else
    805                     {
    806                         if (firstIteration)
    807                             RTPrintf("\nVM:    %s " ANSI_BOLD "%-20s" ANSI_RESET "\n",
    808                                 vmUuid, vmName);
    809                         RTPrintf("  img: %s " ANSI_BOLD "  %s" ANSI_RESET "\n",
    810                             CSTR(pMediumUuid), CSTR(pMediumName));
    811                     }
    812                 }
    813                 else
    814                 {
    815                     if (g_vboximgOpts.fVerbose)
    816                     {
    817                         RTPrintf("     Diff %d:\n", ancestorNumber);
    818                         RTPrintf("          UUID:       %s\n",    CSTR(pMediumUuid));
    819                         RTPrintf("          Location:   %s\n",  CSTR(pMediumPath));
    820                     }
    821                 }
    822                 CHECK_ERROR_BREAK(pChild, COMGETTER(Children)(ComSafeArrayAsOutParam(aMediumChildren)));
    823                 pChild = (aMediumChildren.size()) ? aMediumChildren[0] : NULL;
    824                 ++ancestorNumber;
    825                 firstIteration = 0;
    826             } while(pChild);
    827         }
    828     }
    829 }
    830 /**
    831  * Display all registered VMs on the screen with some information about each
    832  *
    833  * @param virtualBox VirtualBox instance object.
    834  */
    835 static void
    836 listVMs(IVirtualBox *pVirtualBox)
    837 {
    838     HRESULT rc = 0;
    839     com::SafeIfaceArray<IMachine> pMachines;
    840     CHECK_ERROR(pVirtualBox, COMGETTER(Machines)(ComSafeArrayAsOutParam(pMachines)));
    841     for (size_t i = 0; i < pMachines.size(); ++i)
    842     {
    843         ComPtr<IMachine> pMachine = pMachines[i];
    844         if (pMachine)
    845         {
    846             BOOL fAccessible;
    847             CHECK_ERROR(pMachines[i], COMGETTER(Accessible)(&fAccessible));
    848             if (fAccessible)
    849             {
    850                 Bstr pMachineName;
    851                 Bstr pMachineUuid;
    852                 Bstr pDescription;
    853                 Bstr pMachineLocation;
    854 
    855                 CHECK_ERROR(pMachine, COMGETTER(Name)(pMachineName.asOutParam()));
    856                 CHECK_ERROR(pMachine, COMGETTER(Id)(pMachineUuid.asOutParam()));
    857                 CHECK_ERROR(pMachine, COMGETTER(Description)(pDescription.asOutParam()));
    858                 CHECK_ERROR(pMachine, COMGETTER(SettingsFilePath)(pMachineLocation.asOutParam()));
    859 
    860 
    861                 if (   g_vboximgOpts.pszVm == NULL
    862                     || RTStrNCmp(CSTR(pMachineUuid), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0
    863                     || RTStrNCmp((const char *)pMachineName.raw(), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0)
    864                 {
    865                     if (g_vboximgOpts.fVerbose)
    866                     {
    867                         RTPrintf("------------------------------------------------------\n");
    868                         RTPrintf("VM Name:   \"%s\"\n", CSTR(pMachineName));
    869                         RTPrintf("UUID:      %s\n",     CSTR(pMachineUuid));
    870                         if (*pDescription.raw() != '\0')
    871                             RTPrintf("Description:  %s\n",      CSTR(pDescription));
    872                         RTPrintf("Location:  %s\n",      CSTR(pMachineLocation));
    873                     }
    874                     listMedia(pMachine, RTStrDup(CSTR(pMachineName)), RTStrDup(CSTR(pMachineUuid)));
    875                 }
    876             }
    877         }
    878     }
    879 }
    880 
    881 static void
    882 searchForBaseImage(IVirtualBox *pVirtualBox, char *pszImageString, ComPtr<IMedium> *pBaseImage)
    883 {
    884     int rc = 0;
    885     com::SafeIfaceArray<IMedium> aDisks;
    886 
    887     CHECK_ERROR(pVirtualBox, COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aDisks)));
    888     for (size_t i = 0; i < aDisks.size() && aDisks[i]; i++)
    889     {
    890         if (aDisks[i])
    891         {
    892             Bstr pMediumUuid;
    893             Bstr pMediumName;
    894 
    895             CHECK_ERROR(aDisks[i], COMGETTER(Name)(pMediumName.asOutParam()));
    896             CHECK_ERROR(aDisks[i], COMGETTER(Id)(pMediumUuid.asOutParam()));
    897 
    898             if (   RTStrCmp(pszImageString, CSTR(pMediumUuid)) == 0
    899                 || RTStrCmp(pszImageString, CSTR(pMediumName)) == 0)
    900             {
    901                 *pBaseImage = aDisks[i];
    902                 return;
    903             }
    904         }
    905     }
    906757}
    907758
     
    984835
    985836        uint8_t *pTblBuf = (uint8_t *)RTMemAlloc(GPT_PTABLE_SIZE);
    986 
    987         RTPrintf( "Virtual disk image:\n\n");
    988         RTPrintf("   Path: %s\n", g_pszBaseImagePath);
    989         if (g_pvDiskUuid)
    990             RTPrintf("   UUID: %s\n\n", g_pvDiskUuid);
    991 
    992         if (g_vboximgOpts.fVerbose)
    993         {
    994             RTPrintf("   GPT Partition Table Header:\n\n");
    995             if (RTStrCmp((const char *)&parTblHdr.signature, "EFI PART") == 0)
    996                 RTPrintf(
    997                      "      Signature               \"EFI PART\" (0x%llx)\n", parTblHdr.signature);
    998             else
    999                 RTPrintf(
    1000                      "      Signature:              0x%llx\n",  parTblHdr.signature);
    1001             RTPrintf("      Revision:               %-8.8x\n",  parTblHdr.revision);
    1002             RTPrintf("      Current LBA:            %lld\n",    parTblHdr.headerLba);
    1003             RTPrintf("      Backup LBA:             %lld\n",    parTblHdr.backupLba);
    1004             RTPrintf("      Partition entries LBA:  %lld\n",    parTblHdr.partitionEntriesLba);
    1005             RTPrintf("      # of partitions:        %d\n",      parTblHdr.cPartitionEntries);
    1006             RTPrintf("      size of entry:          %d\n\n",    parTblHdr.cbPartitionEntry);
    1007         }
    1008837
    1009838        if (!pTblBuf)
     
    1112941{
    1113942
     943    RTPrintf( "Virtual disk image:\n\n");
     944    RTPrintf("   Base: %s\n", g_pszBaseImagePath);
     945    if (g_cImages > 1)
     946        RTPrintf("   Diff: %s\n", g_pszImagePath);
     947    if (g_pszDiskUuid)
     948            RTPrintf("   UUID: %s\n\n", g_pszDiskUuid);
     949
    1114950    void *colBoot = NULL;
    1115951
     
    1119955    void *colPartNbr   = tbl.addCol("#",                 "%3d",       1);
    1120956
    1121     /* If none of the partitions supports legacy BIOS boot, don't show column */
     957    /* If none of the partitions supports legacy BIOS boot, don't show that column */
    1122958    for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++)
    1123959        if (g_aParsedPartitionInfo[idxPartition].fBootable) {
     
    1128964    void *colStart     = tbl.addCol("Start",             "%lld",      1);
    1129965    void *colSectors   = tbl.addCol("Sectors",           "%lld",     -1, 2);
    1130     void *colSize      = tbl.addCol("Size",              "%d.%d%c",   1);
     966    void *colSize      = tbl.addCol("Size",              "%s",        1);
    1131967    void *colOffset    = tbl.addCol("Offset",            "%lld",      1);
    1132     /* Need to see how other OSes with GPT schemes use this field. Seems like type covers it
     968    void *colType      = tbl.addCol("Type",              "%s",       -1, 2);
     969
     970#if 0 /* need to see how other OSes w/GPT use 'Name' field, right now 'Type' seems to suffice */
    1133971    void *colName      = tbl.addCol("Name",              "%s",       -1); */
    1134     void *colType      = tbl.addCol("Type",              "%s",       -1, 2);
     972#endif
    1135973
    1136974    for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++)
     
    1139977        if (ppi->idxPartition)
    1140978        {
    1141             uint8_t exp = log2((double)ppi->cbPartition);
    1142             char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10];
    1143 
    1144              /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */
    1145             double cbPartitionScaled = (double)ppi->cbPartition / pow(2, (double)(((uint8_t)(exp / 10)) * 10));
    1146             uint8_t cbPartitionIntPart = cbPartitionScaled;
    1147             uint8_t cbPartitionFracPart = (cbPartitionScaled - (double)cbPartitionIntPart) * 10;
    1148 
    1149979            char abGuid[GUID_STRING_LENGTH * 2];
    1150980            RTStrPrintf(abGuid, sizeof(abGuid), "%RTuuid",  &ppi->partitionType.gptGuidTypeSpecifier);
     
    1167997            tbl.setCell(row, colStart,      ppi->offPartition / BLOCKSIZE);
    1168998            tbl.setCell(row, colSectors,    ppi->cbPartition / BLOCKSIZE);
    1169             tbl.setCell(row, colSize,       cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude);
     999            tbl.setCell(row, colSize,       vboximgScaledSize(ppi->cbPartition));
    11701000            tbl.setCell(row, colOffset,     ppi->offPartition);
    1171 /*          tbl.setCell(row, colName,       ppi->pszName);    ... see comment for column definition */
    11721001            tbl.setCell(row, colType,       SAFENULL(pszPartitionTypeDesc));
     1002
     1003#if 0 /* see comment for stubbed-out 'Name' column definition above */
     1004            tbl.setCell(row, colName,       ppi->pszName);
     1005#endif
     1006
    11731007        }
    11741008    }
     
    11841018     * are adapted to the actual data, to avoid insufficient or excessive whitespace.
    11851019     */
     1020
    11861021    RTPrintf( "Virtual disk image:\n\n");
    1187     RTPrintf("   Path: %s\n", g_pszBaseImagePath);
    1188     if (g_pvDiskUuid)
    1189         RTPrintf("   UUID: %s\n\n", g_pvDiskUuid);
     1022    RTPrintf("   Base: %s\n", g_pszBaseImagePath);
     1023    if (g_cImages > 1)
     1024        RTPrintf("   Diff: %s\n", g_pszImagePath);
     1025    if (g_pszDiskUuid)
     1026            RTPrintf("   UUID: %s\n\n", g_pszDiskUuid);
    11901027
    11911028    SELFSIZINGTABLE tbl(2);
    11921029
    1193     void *colPartition = tbl.addCol("Partition",    "%s%d",     -1);
     1030    void *colPartition = tbl.addCol("Partition",    "%s(%d)",     -1);
    11941031    void *colBoot      = tbl.addCol("Boot",         "%c   ",     1);
    11951032    void *colStart     = tbl.addCol("Start",        "%lld",      1);
    11961033    void *colSectors   = tbl.addCol("Sectors",      "%lld",     -1, 2);
    1197     void *colSize      = tbl.addCol("Size",         "%d.%d%c",   1);
     1034    void *colSize      = tbl.addCol("Size",         "%s",        1);
    11981035    void *colOffset    = tbl.addCol("Offset",       "%lld",      1);
    11991036    void *colId        = tbl.addCol("Id",           "%2x",       1);
     
    12051042        if (p->idxPartition)
    12061043        {
    1207             uint8_t exp = log2((double)p->cbPartition);
    1208             char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10];
    1209 
    1210              /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */
    1211             double  cbPartitionScaled = (double)p->cbPartition / pow(2, (double)(((uint8_t)(exp / 10)) * 10));
    1212             uint8_t cbPartitionIntPart = cbPartitionScaled;
    1213             uint8_t cbPartitionFracPart = (cbPartitionScaled - (double)cbPartitionIntPart) * 10;
    1214 
    12151044            void *row = tbl.addRow();
    1216 
    12171045            tbl.setCell(row, colPartition,  g_pszBaseImageName, idxPartition);
    12181046            tbl.setCell(row, colBoot,       p->fBootable ? '*' : ' ');
    12191047            tbl.setCell(row, colStart,      p->offPartition / BLOCKSIZE);
    12201048            tbl.setCell(row, colSectors,    p->cbPartition / BLOCKSIZE);
    1221             tbl.setCell(row, colSize,       cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude);
     1049            tbl.setCell(row, colSize,       vboximgScaledSize(p->cbPartition));
    12221050            tbl.setCell(row, colOffset,     p->offPartition);
    12231051            tbl.setCell(row, colId,         p->partitionType.legacy);
     
    12531081    memset(&g_vboximgOpts, 0, sizeof(g_vboximgOpts));
    12541082
     1083    g_vboximgOpts.idxPartition = -1;
     1084
    12551085    rc = fuse_opt_parse(&args, &g_vboximgOpts, vboximgOptDefs, vboximgOptHandler);
    12561086    if (rc < 0 || argc < 2 || RTStrCmp(argv[1], "-?" ) == 0 || g_vboximgOpts.fBriefUsage)
     
    12601090    }
    12611091
     1092    if (g_vboximgOpts.fAllowRoot)
     1093        fuse_opt_add_arg(&args, "-oallow_root");
     1094
     1095    /*
     1096     * FUSE doesn't seem to like combining options with one hyphen, as traditional UNIX
     1097     * command line utilities allow. The following flags, fWideList and fVerboseList,
     1098     * and their respective option definitions give the appearance of combined opts,
     1099     * so that -vl, -lv, -wl, -lw options are allowed, since those in particular would
     1100     * tend to conveniently facilitate some of the most common use cases.
     1101     */
     1102    if (g_vboximgOpts.fWideList)
     1103    {
     1104        g_vboximgOpts.fWide = true;
     1105        g_vboximgOpts.fList = true;
     1106    }
     1107    if (g_vboximgOpts.fVerboseList)
     1108    {
     1109        g_vboximgOpts.fVerbose = true;
     1110        g_vboximgOpts.fList    = true;
     1111    }
    12621112    if (g_vboximgOpts.fAllowRoot)
    12631113        fuse_opt_add_arg(&args, "-oallow_root");
     
    12911141    if (SUCCEEDED(hrc))
    12921142        hrc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam());
     1143
    12931144    if (FAILED(hrc))
    12941145        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get IVirtualBox object! (hrc=%Rhrc)", hrc);
    12951146
    1296     if (g_vboximgOpts.fVerbose)
    1297         RTPrintf("vboximg: VirtualBox XPCOM object created\n");
    1298 
    1299     if (g_vboximgOpts.fList && g_vboximgOpts.pszImage == NULL)
    1300     {
    1301         listVMs(pVirtualBox);
    1302         return 0;
    1303     }
    1304 
    1305     ComPtr<IMedium> pBaseImageMedium = NULL;
    1306     char    *pszFormat;
     1147    if (g_vboximgOpts.fList && g_vboximgOpts.pszImageUuidOrPath == NULL)
     1148    {
     1149        vboximgListVMs(pVirtualBox);
     1150        return VINF_SUCCESS;
     1151    }
     1152
     1153    Bstr    pMediumUuid;
     1154    ComPtr<IMedium> pVDiskMedium = NULL;
     1155    char   *pszFormat;
    13071156    VDTYPE  enmType;
    1308     searchForBaseImage(pVirtualBox, g_vboximgOpts.pszImage, &pBaseImageMedium);
    1309     if (pBaseImageMedium == NULL)
    1310     {
     1157
     1158    /*
     1159     * Open chain of images from what is provided on command line, to base image
     1160     */
     1161    if (g_vboximgOpts.pszImageUuidOrPath)
     1162    {
     1163        /* compiler was too fussy about access mode's data type in conditional expr, so... */
     1164        if (g_vboximgOpts.fRW)
     1165            CHECK_ERROR(pVirtualBox, OpenMedium(Bstr(g_vboximgOpts.pszImageUuidOrPath).raw(), DeviceType_HardDisk,
     1166                AccessMode_ReadWrite, false /* forceNewUuid */, pVDiskMedium.asOutParam()));
     1167
     1168        else
     1169            CHECK_ERROR(pVirtualBox, OpenMedium(Bstr(g_vboximgOpts.pszImageUuidOrPath).raw(), DeviceType_HardDisk,
     1170                AccessMode_ReadOnly, false /* forceNewUuid */, pVDiskMedium.asOutParam()));
     1171
     1172        if (FAILED(rc))
     1173            return RTMsgErrorExitFailure("\nCould't find specified VirtualBox base or snapshot disk image:\n%s",
     1174                 g_vboximgOpts.pszImageUuidOrPath);
     1175
     1176
     1177        CHECK_ERROR(pVDiskMedium, COMGETTER(Id)(pMediumUuid.asOutParam()));
     1178        g_pszDiskUuid = RTStrDup((char *)CSTR(pMediumUuid));
     1179
    13111180        /*
    1312          * Try to locate base image pMedium via the VirtualBox API, given the user-provided path
    1313          * resolving symlinks back to hard path.
     1181         * Lock & cache the disk image media chain (from leaf to base).
     1182         * Only leaf can be rw (and only if media is being mounted in non-default writable (rw) mode)
     1183         *
     1184         * Note: Failure to acquire lock is intentionally fatal (e.g. program termination)
    13141185         */
    1315         int cbNameMax = pathconf(g_vboximgOpts.pszImage, _PC_PATH_MAX);
    1316         if (cbNameMax < 0)
    1317             return cbNameMax;
    1318 
    1319         g_pszBaseImagePath = RTStrDup(g_vboximgOpts.pszImage);
    1320         if (g_pszBaseImagePath == NULL)
    1321             return RTMsgErrorExitFailure("out of memory\n");
    1322 
    1323         if (access(g_pszBaseImagePath, F_OK) < 0)
    1324             return RTMsgErrorExitFailure("Virtual disk image not found: \"%s\"\n", g_pszBaseImagePath);
    1325 
    1326         if (access(g_pszBaseImagePath, R_OK) < 0)
    1327              return RTMsgErrorExitFailure(
    1328                     "Virtual disk image not readable: \"%s\"\n", g_pszBaseImagePath);
    1329 
    1330         if (g_vboximgOpts.fRW && access(g_vboximgOpts.pszImage, W_OK) < 0)
    1331              return RTMsgErrorExitFailure(
    1332                     "Virtual disk image not writeable: \"%s\"\n", g_pszBaseImagePath);
    1333         rc = RTPathSplit(g_pszBaseImagePath, &g_u.split, sizeof(g_u), 0);
    1334 
    1335         if (RT_FAILURE(rc))
    1336              return RTMsgErrorExitFailure(
    1337                     "RTPathSplit failed on '%s': %Rrc",  g_pszBaseImagePath);
    1338 
    1339         if (!(g_u.split.fProps & RTPATH_PROP_FILENAME))
    1340              return RTMsgErrorExitFailure(
    1341                     "RTPATH_PROP_FILENAME not set for: '%s'",  g_pszBaseImagePath);
    1342 
    1343         g_pszBaseImageName = g_u.split.apszComps[g_u.split.cComps - 1];
    1344         searchForBaseImage(pVirtualBox, g_pszBaseImageName, &pBaseImageMedium);
    1345 
    1346         if (pBaseImageMedium == NULL)
    1347         {
    1348             /*
    1349              *  Can't find the user specified image Medium via the VirtualBox API
    1350              *  Try to 'mount' the image via the user-provided path (without differencing images)
    1351              *  Create VirtualBox disk container and open main image
    1352              */
    1353             rc = VDGetFormat(NULL /* pVDIIfsDisk */, NULL /* pVDIIfsImage*/,
    1354                 g_pszBaseImagePath, &pszFormat, &enmType);
     1186
     1187        if (VERBOSE)
     1188            RTPrintf("\nAttempting to lock medium chain from leaf image to base image\n");
     1189
     1190        bool fLeaf = true;
     1191        g_cImages = 0;
     1192
     1193        do
     1194        {
     1195            ++g_cImages;
     1196            IMAGELIST *pNewEntry= new IMAGELIST();
     1197            pNewEntry->pImage = pVDiskMedium;
     1198            CHECK_ERROR(pVDiskMedium, COMGETTER(Name)((pNewEntry->pImageName).asOutParam()));
     1199            CHECK_ERROR(pVDiskMedium, COMGETTER(Location)((pNewEntry->pImagePath).asOutParam()));
     1200
     1201            if (VERBOSE)
     1202                RTPrintf("  %s", CSTR(pNewEntry->pImageName));
     1203
     1204            if (fLeaf && g_vboximgOpts.fRW)
     1205            {
     1206                if (VERBOSE)
     1207                    RTPrintf(" ... Locking for write\n");
     1208                CHECK_ERROR_RET(pVDiskMedium, LockWrite((pNewEntry->pLockToken).asOutParam()), rc);
     1209                pNewEntry->fWriteable = true;
     1210            }
     1211            else
     1212            {
     1213                if (VERBOSE)
     1214                    RTPrintf(" ... Locking for read\n");
     1215                CHECK_ERROR_RET(pVDiskMedium, LockRead((pNewEntry->pLockToken).asOutParam()), rc);
     1216            }
     1217
     1218            IMAGELIST *pCurImageEntry = &listHeadLockList;
     1219            while (pCurImageEntry->next)
     1220                pCurImageEntry = pCurImageEntry->next;
     1221            pCurImageEntry->next = pNewEntry;
     1222            pNewEntry->prev = pCurImageEntry;
     1223            listHeadLockList.prev = pNewEntry;
     1224
     1225            CHECK_ERROR(pVDiskMedium, COMGETTER(Parent)(pVDiskMedium.asOutParam()));
     1226            fLeaf = false;
     1227        }
     1228        while(pVDiskMedium);
     1229    }
     1230
     1231    ComPtr<IMedium> pVDiskBaseMedium = listHeadLockList.prev->pImage;
     1232    Bstr pVDiskBaseImagePath = listHeadLockList.prev->pImagePath;
     1233    Bstr pVDiskBaseImageName = listHeadLockList.prev->pImageName;
     1234
     1235    g_pszBaseImagePath = RTStrDup((char *)CSTR(pVDiskBaseImagePath));
     1236    g_pszBaseImageName = RTStrDup((char *)CSTR(pVDiskBaseImageName));
     1237
     1238    g_pszImagePath = RTStrDup((char *)CSTR(listHeadLockList.next->pImagePath));
     1239    g_pszImageName = RTStrDup((char *)CSTR(listHeadLockList.next->pImageName));
     1240
     1241    /*
     1242     * Attempt to VDOpen media (base and any snapshots), handling encryption,
     1243     * if that property is set for base media
     1244     */
     1245    Bstr pBase64EncodedKeyStore;
     1246
     1247    rc = pVDiskBaseMedium->GetProperty(Bstr("CRYPT/KeyStore").raw(), pBase64EncodedKeyStore.asOutParam());
     1248    if (SUCCEEDED(rc) && strlen(CSTR(pBase64EncodedKeyStore)) != 0)
     1249    {
     1250        RTPrintf("\nvboximgMount: Encrypted disks not supported in this version\n\n");
     1251        return -1;
     1252    }
     1253
     1254
     1255/* ***************** BEGIN IFDEF'D (STUBBED-OUT) CODE ************** */
     1256/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
     1257
     1258#if 0 /* The following encrypted disk related code is stubbed out until it can be finished.
     1259       * What is here is an attempt to port the VBoxSVC specific code in i_openForIO to
     1260       * a client's proximity. It is supplemented by code in vboximgCrypto.cpp and
     1261       * vboximageCrypt.h that was lifed from SecretKeyStore.cpp along with the setup
     1262       * task function.
     1263       *
     1264       * The ultimate solution may be to use a simpler but less efficient COM interface,
     1265       * or to use VD encryption interfaces and key containers entirely. The keystore
     1266       * handling/filter approach that is here may be a bumbling hybrid approach
     1267       * that is broken (trying to bridge incompatible disk encryption mechanisms) or otherwise
     1268       * doesn't make sense. */
     1269
     1270    Bstr pKeyId;
     1271    ComPtr<IExtPackManager> pExtPackManager;
     1272    ComPtr<IExtPack> pExtPack;
     1273    com::SafeIfaceArray<IExtPackPlugIn> pExtPackPlugIns;
     1274
     1275    if (SUCCEEDED(rc))
     1276    {
     1277        RTPrintf("Got GetProperty(\"CRYPT/KeyStore\") = %s\n", CSTR(pBase64EncodedKeyStore));
     1278        if (strlen(CSTR(pBase64EncodedKeyStore)) == 0)
     1279            return RTMsgErrorExitFailure("Image '%s' is configured for encryption but "
     1280                    "there is no key store to retrieve the password from", CSTR(pVDiskBaseImageName));
     1281
     1282        SecretKeyStore keyStore(false);
     1283        RTBase64Decode(CSTR(pBase64EncodedKeyStore), &keyStore, sizeof (SecretKeyStore), NULL, NULL);
     1284
     1285        rc = pVDiskBaseMedium->GetProperty(Bstr("CRYPT/KeyId").raw(), pKeyId.asOutParam());
     1286        if (SUCCEEDED(rc) && strlen(CSTR(pKeyId)) == 0)
     1287            return RTMsgErrorExitFailure("Image '%s' is configured for encryption but "
     1288                "doesn't have a key identifier set", CSTR(pVDiskBaseImageName));
     1289
     1290        RTPrintf("        key id: %s\n", CSTR(pKeyId));
     1291
     1292#ifndef VBOX_WITH_EXTPACK
     1293        return RTMsgErrorExitFailure(
     1294            "Encryption is not supported because extension pack support is not built in");
     1295#endif
     1296
     1297        CHECK_ERROR(pVirtualBox, COMGETTER(ExtensionPackManager)(pExtPackManager.asOutParam()));
     1298        BOOL fExtPackUsable;
     1299        CHECK_ERROR(pExtPackManager, IsExtPackUsable((PRUnichar *)VBOX_EXTPACK, &fExtPackUsable));
     1300        if (fExtPackUsable)
     1301        {
     1302            /* Load the PlugIn */
     1303
     1304            CHECK_ERROR(pExtPackManager, Find((PRUnichar *)VBOX_EXTPACK, pExtPack.asOutParam()));
    13551305            if (RT_FAILURE(rc))
    1356                 return RTMsgErrorExitFailure("VDGetFormat(%s,) "
    1357                     "failed, rc=%Rrc\n", g_pszBaseImagePath, rc);
    1358 
    1359             g_pVDisk = NULL;
    1360             rc = VDCreate(NULL /* pVDIIfsDisk */, enmType, &g_pVDisk);
    1361             if (RT_SUCCESS(rc))
     1306                return RTMsgErrorExitFailure(
     1307                    "Encryption is not supported because the extension pack '%s' is missing",
     1308                    VBOX_EXTPACK);
     1309
     1310            CHECK_ERROR(pExtPack, COMGETTER(PlugIns)(ComSafeArrayAsOutParam(pExtPackPlugIns)));
     1311
     1312            Bstr pPlugInPath;
     1313            size_t iPlugIn;
     1314            for (iPlugIn = 0; iPlugIn < pExtPackPlugIns.size(); iPlugIn++)
    13621315            {
    1363                 rc = VDOpen(g_pVDisk, pszFormat, g_pszBaseImagePath, 0, NULL /* pVDIfsImage */);
    1364                 if (RT_FAILURE(rc))
     1316                Bstr pPlugInName;
     1317                CHECK_ERROR(pExtPackPlugIns[iPlugIn], COMGETTER(Name)(pPlugInName.asOutParam()));
     1318                if (RTStrCmp(CSTR(pPlugInName), "VDPlugInCrypt") == 0)
    13651319                {
    1366                     VDClose(g_pVDisk, false /* fDeletes */);
    1367                     return RTMsgErrorExitFailure("VDCreate(,%s,%s,,,) failed,"
    1368                         " rc=%Rrc\n", pszFormat, g_pszBaseImagePath, rc);
     1320                    CHECK_ERROR(pExtPackPlugIns[iPlugIn], COMGETTER(ModulePath)(pPlugInPath.asOutParam()));
     1321                    break;
    13691322                }
    13701323            }
    1371             else
    1372                 return RTMsgErrorExitFailure("VDCreate failed, rc=%Rrc\n", rc);
    1373         }
    1374     } else {
    1375         Bstr pMediumUuid;
    1376         CHECK_ERROR(pBaseImageMedium, COMGETTER(Id)(pMediumUuid.asOutParam()));
    1377         g_pvDiskUuid = RTStrDup((char *)CSTR(pMediumUuid));
    1378     }
    1379 
    1380     if (g_pVDisk == NULL)
    1381     {
    1382 
    1383         com::SafeIfaceArray<IMedium> aMediumChildren;
    1384         ComPtr<IMedium> pChild = pBaseImageMedium;
    1385         uint32_t diffNumber = 0; /* diff # 0 = base image */
    1386         do
    1387         {
    1388             Bstr pMediumName;
    1389             Bstr pMediumPath;
    1390 
    1391             CHECK_ERROR(pChild, COMGETTER(Name)(pMediumName.asOutParam()));
    1392             CHECK_ERROR(pChild, COMGETTER(Location)(pMediumPath.asOutParam()));
    1393 
    1394             if (pChild == pBaseImageMedium)
    1395             {
    1396                 free((void *)g_pszBaseImageName);
    1397                 g_pszBaseImageName = RTStrDup(CSTR(pMediumName));
    1398 
    1399                 free((void *)g_pszBaseImagePath);
    1400                 g_pszBaseImagePath = RTStrDup(CSTR(pMediumPath));
    1401                 if (g_pszBaseImageName == NULL)
    1402                     return RTMsgErrorExitFailure("out of memory\n");
    1403 
    1404                 if (g_pszBaseImagePath == NULL)
    1405                     return RTMsgErrorExitFailure("out of memory\n");
    1406                 /*
    1407                  * Create HDD container to open base image and differencing images into
    1408                  */
    1409                 rc = VDGetFormat(NULL /* pVDIIfsDisk */, NULL /* pVDIIfsImage*/,
    1410                         g_pszBaseImagePath, &pszFormat, &enmType);
    1411                 if (RT_FAILURE(rc))
    1412                     return RTMsgErrorExitFailure("VDGetFormat(,,%s,,) "
    1413                         "failed (during HDD container creation), rc=%Rrc\n", g_pszBaseImagePath, rc);
    1414                 if (g_vboximgOpts.fVerbose)
    1415                     RTPrintf("Creating container for base image of format %s\n", pszFormat);
    1416                 /** @todo Remove I/O CB's and crit sect. when VDRead()/VDWrite() are made threadsafe */
    1417                 rc = RTCritSectInit(&g_vdioLock);
    1418                 if (RT_SUCCESS(rc))
    1419                 {
    1420                     g_VDIfThreadSync.pfnStartRead   = vboximgThreadStartRead;
    1421                     g_VDIfThreadSync.pfnFinishRead  = vboximgThreadFinishRead;
    1422                     g_VDIfThreadSync.pfnStartWrite  = vboximgThreadStartWrite;
    1423                     g_VDIfThreadSync.pfnFinishWrite = vboximgThreadFinishWrite;
    1424                     rc = VDInterfaceAdd(&g_VDIfThreadSync.Core, "vboximg_ThreadSync", VDINTERFACETYPE_THREADSYNC,
    1425                                         &g_vdioLock, sizeof(VDINTERFACETHREADSYNC), &g_pVdIfs);
    1426                 }
    1427                 else
    1428                     return RTMsgErrorExitFailure("ERROR: Failed to create critsects "
    1429                                                  "for virtual disk I/O, rc=%Rrc\n", rc);
    1430 
    1431                 g_pVDisk = NULL;
    1432                 rc = VDCreate(g_pVdIfs, enmType, &g_pVDisk);
    1433                 if (NS_FAILED(rc))
    1434                     return RTMsgErrorExitFailure("ERROR: Couldn't create virtual disk container\n");
    1435             }
    1436             /** @todo (end of to do section) */
    1437 
    1438             if ( g_vboximgOpts.cHddImageDiffMax != 0 && diffNumber > g_vboximgOpts.cHddImageDiffMax)
    1439                 break;
    1440 
    1441             if (g_vboximgOpts.fVerbose)
    1442             {
    1443                 if (diffNumber == 0)
    1444                     RTPrintf("\nvboximg-mount: Opening base image into container:\n       %s\n",
    1445                         g_pszBaseImagePath);
    1446                 else
    1447                     RTPrintf("\nvboximg-mount: Opening difference image #%d into container:\n       %s\n",
    1448                         diffNumber, g_pszBaseImagePath);
    1449             }
    1450 
    1451             rc = VDOpen(g_pVDisk, pszFormat, g_pszBaseImagePath, 0, NULL /* pVDIfsImage */);
     1324            if (iPlugIn == pExtPackPlugIns.size())
     1325                return RTMsgErrorExitFailure("Encryption is not supported because the extension pack '%s' "
     1326                    "is missing the encryption PlugIn (old extension pack installed?)", VBOX_EXTPACK);
     1327
     1328            rc = VDPluginLoadFromFilename(CSTR(pPlugInPath));
    14521329            if (RT_FAILURE(rc))
    1453             {
    1454                 VDClose(g_pVDisk, false /* fDeletes */);
    1455                 return RTMsgErrorExitFailure("VDOpen(,,%s,,) failed, rc=%Rrc\n",
    1456                    g_pszBaseImagePath, rc);
    1457             }
    1458 
    1459             CHECK_ERROR(pChild, COMGETTER(Children)(ComSafeArrayAsOutParam(aMediumChildren)));
    1460 
    1461             if (aMediumChildren.size() != 0) {
    1462                 pChild = aMediumChildren[0];
    1463             }
    1464 
    1465             aMediumChildren.setNull();
    1466 
    1467             ++diffNumber;
    1468 
    1469 
    1470         } while(NS_SUCCEEDED(rc) && aMediumChildren.size());
    1471     }
    1472 
    1473     g_cReaders    = VDIsReadOnly(g_pVDisk) ? INT32_MAX / 2 : 0;
    1474     g_cWriters   = 0;
     1330                return RTMsgErrorExitFailure("Retrieving encryption settings of the image failed "
     1331                    "because the encryption PlugIn could not be loaded\n");
     1332        }
     1333
     1334        SecretKey *pKey = NULL;
     1335        rc = keyStore.retainSecretKey(Utf8Str(pKeyId), &pKey);
     1336        if (RT_FAILURE(rc))
     1337                return RTMsgErrorExitFailure(
     1338                    "Failed to retrieve the secret key with ID \"%s\" from the store (%Rrc)",
     1339                    CSTR(pKeyId), rc);
     1340
     1341        VDISKCRYPTOSETTINGS vdiskCryptoSettings, *pVDiskCryptoSettings = &vdiskCryptoSettings;
     1342
     1343        vboxImageCryptoSetup(pVDiskCryptoSettings, NULL,
     1344            (const char *)CSTR(pBase64EncodedKeyStore), (const char *)pKey->getKeyBuffer(), false);
     1345
     1346        rc = VDFilterAdd(g_pVDisk, "CRYPT", VD_FILTER_FLAGS_DEFAULT, pVDiskCryptoSettings->vdFilterIfaces);
     1347        keyStore.releaseSecretKey(Utf8Str(pKeyId));
     1348
     1349        if (rc == VERR_VD_PASSWORD_INCORRECT)
     1350            return RTMsgErrorExitFailure("The password to decrypt the image is incorrect");
     1351
     1352        if (RT_FAILURE(rc))
     1353            return RTMsgErrorExitFailure("Failed to load the decryption filter: %Rrc", rc);
     1354    }
     1355#endif
     1356
     1357/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
     1358/* **************** END IFDEF'D (STUBBED-OUT) CODE ***************** */
     1359
     1360     rc = RTCritSectInit(&g_vdioLock);
     1361    if (RT_SUCCESS(rc))
     1362    {
     1363        g_VDIfThreadSync.pfnStartRead   = vboximgThreadStartRead;
     1364        g_VDIfThreadSync.pfnFinishRead  = vboximgThreadFinishRead;
     1365        g_VDIfThreadSync.pfnStartWrite  = vboximgThreadStartWrite;
     1366        g_VDIfThreadSync.pfnFinishWrite = vboximgThreadFinishWrite;
     1367        rc = VDInterfaceAdd(&g_VDIfThreadSync.Core, "vboximg_ThreadSync", VDINTERFACETYPE_THREADSYNC,
     1368                            &g_vdioLock, sizeof(VDINTERFACETHREADSYNC), &g_pVdIfs);
     1369    }
     1370    else
     1371        return RTMsgErrorExitFailure("ERROR: Failed to create critsects "
     1372                                     "for virtual disk I/O, rc=%Rrc\n", rc);
     1373
     1374   /*
     1375     * Create HDD container to open base image and differencing images into
     1376     */
     1377    rc = VDGetFormat(NULL /* pVDIIfsDisk */, NULL /* pVDIIfsImage*/,
     1378            CSTR(pVDiskBaseImagePath), &pszFormat, &enmType);
     1379
     1380    if (RT_FAILURE(rc))
     1381        return RTMsgErrorExitFailure("VDGetFormat(,,%s,,) "
     1382            "failed (during HDD container creation), rc=%Rrc\n", g_pszImagePath, rc);
     1383
     1384    if (VERBOSE)
     1385        RTPrintf("\nCreating container for base image of format %s\n", pszFormat);
     1386
     1387    g_pVDisk = NULL;
     1388    rc = VDCreate(g_pVdIfs, enmType, &g_pVDisk);
     1389    if ((rc))
     1390        return RTMsgErrorExitFailure("ERROR: Couldn't create virtual disk container\n");
     1391
     1392    /* Open all virtual disk media from leaf snapshot (if any) to base image*/
     1393
     1394    if (VERBOSE)
     1395        RTPrintf("\nOpening medium chain\n");
     1396
     1397    IMAGELIST *pCurMedium = listHeadLockList.prev;  /* point to base image */
     1398    while (pCurMedium != &listHeadLockList)
     1399    {
     1400        if (VERBOSE)
     1401            RTPrintf("  Open: %s\n", CSTR(pCurMedium->pImagePath));
     1402
     1403        rc = VDOpen(g_pVDisk,
     1404                    CSTR(pszFormat),
     1405                    CSTR(pCurMedium->pImagePath),
     1406                    pCurMedium->fWriteable,
     1407                    g_pVdIfs);
     1408
     1409        if (RT_FAILURE(rc))
     1410            return RTMsgErrorExitFailure("Could not open the medium storage unit '%s' %Rrc",
     1411                CSTR(pCurMedium->pImagePath), rc);
     1412
     1413        pCurMedium = pCurMedium->prev;
     1414    }
     1415
     1416    g_cReaders  = VDIsReadOnly(g_pVDisk) ? INT32_MAX / 2 : 0;
     1417    g_cWriters  = 0;
    14751418    g_cbEntireVDisk  = VDGetSize(g_pVDisk, 0 /* base */);
    14761419
     
    14811424
    14821425        RTPrintf("\n");
    1483 
    14841426        rc = parsePartitionTable();
    14851427        switch(rc)
     
    14961438        return 0;
    14971439    }
     1440
    14981441    if (g_vboximgOpts.idxPartition >= 0)
    14991442    {
     
    15161459        if (partNbr < 0 || partNbr > g_lastPartNbr)
    15171460            return RTMsgErrorExitFailure("Non-valid partition number specified\n");
    1518 
    15191461        if (partNbr == 0)
    15201462        {
    15211463            g_vDiskOffset = 0;
    15221464            g_vDiskSize = VDGetSize(g_pVDisk, 0);
    1523             if (g_vboximgOpts.fVerbose)
    1524                 RTPrintf("Partition 0 specified - Whole disk will be accessible\n");
     1465            if (VERBOSE)
     1466                RTPrintf("\nPartition 0 specified - Whole disk will be accessible\n");
    15251467        } else {
    1526             for (int i = 0; i < g_lastPartNbr; i++)
     1468            int fFoundPartition = false;
     1469            for (int i = 1; i < g_lastPartNbr + 1; i++)
    15271470            {
    15281471                /* If GPT, display vboximg's representation of partition table starts at partition 2
    15291472                 * but the table is displayed calling it partition 1, because the protective MBR
    15301473                 * record is relatively pointless to display or reference in this context */
    1531 
    1532                 if (g_aParsedPartitionInfo[i].idxPartition == partNbr + g_fGPT ? 1 : 0)
     1474                if (g_aParsedPartitionInfo[i].idxPartition == partNbr + (g_fGPT ? 1 : 0))
    15331475                {
     1476                     fFoundPartition = true;
    15341477                     g_vDiskOffset = g_aParsedPartitionInfo[i].offPartition;
    15351478                     g_vDiskSize = g_vDiskOffset + g_aParsedPartitionInfo[i].cbPartition;
    1536                      if (g_vboximgOpts.fVerbose)
    1537                         RTPrintf("Partition %d specified. Only sectors %llu to %llu of disk will be accessible\n",
     1479                     if (VERBOSE)
     1480                        RTPrintf("\nPartition %d specified. Only sectors %llu to %llu of disk will be accessible\n",
    15381481                            g_vboximgOpts.idxPartition, g_vDiskOffset / BLOCKSIZE, g_vDiskSize / BLOCKSIZE);
    15391482                }
    15401483            }
     1484            if (!fFoundPartition)
     1485                return RTMsgErrorExitFailure("Couldn't find partition %d in partition table\n", partNbr);
    15411486        }
    15421487    } else {
     
    15451490                return RTMsgErrorExitFailure("User specified offset out of range of virtual disk\n");
    15461491
    1547             if (g_vboximgOpts.fVerbose)
     1492            if (VERBOSE)
    15481493                RTPrintf("Setting r/w bias (offset) to user requested value for sector %llu\n", g_vDiskOffset / BLOCKSIZE);
    15491494
     
    15541499                return RTMsgErrorExitFailure("User specified size out of range of virtual disk\n");
    15551500
    1556             if (g_vboximgOpts.fVerbose)
     1501            if (VERBOSE)
    15571502                RTPrintf("Setting r/w size limit to user requested value %llu\n", g_vDiskSize / BLOCKSIZE);
    15581503
     
    15661511     * Hand control over to libfuse.
    15671512     */
    1568     if (g_vboximgOpts.fVerbose)
     1513    if (VERBOSE)
    15691514        RTPrintf("\nvboximg-mount: Going into background...\n");
    15701515
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette