Changeset 76271 in vbox for trunk/src/VBox
- Timestamp:
- Dec 18, 2018 5:29:30 AM (6 years ago)
- 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 20 20 21 21 ifeq ($(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*))) 23 23 ifneq ($(VBOX_PATH_FUSE),) 24 24 LIB_FUSE := $(VBOX_PATH_FUSE)/lib/libosxfuse.dylib … … 48 48 vboximg-mount.cpp \ 49 49 vboximg-mount.h \ 50 vboximgCrypto.cpp \ 51 vboximgCrypto.h \ 52 vboximgMedia.cpp \ 53 vboximgMedia.h \ 54 vboximgOpts.h \ 50 55 SelfSizingTable.h 51 56 -
trunk/src/VBox/ImageMounter/vboximg-mount/vboximg-mount.cpp
r76130 r76271 36 36 #include <unistd.h> 37 37 #include <math.h> 38 //#include <stdarg.h>39 38 #include <cstdarg> 40 39 #include <sys/stat.h> … … 61 60 #include <VBox/com/array.h> 62 61 #include <VBox/com/errorprint.h> 63 62 #include <VBox/vd-plugin.h> 64 63 #include <iprt/initterm.h> 65 64 #include <iprt/assert.h> … … 74 73 #include <iprt/path.h> 75 74 #include <iprt/utf16.h> 75 #include <iprt/base64.h> 76 76 77 77 #include "vboximg-mount.h" 78 #include "vboximgCrypto.h" 79 #include "vboximgMedia.h" 78 80 #include "SelfSizingTable.h" 81 #include "vboximgOpts.h" 79 82 80 83 using namespace com; … … 84 87 }; 85 88 86 /* For getting the basename of the image path */87 union88 {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 #endif100 101 89 enum { PARTITION_TABLE_MBR = 1, PARTITION_TABLE_GPT = 2 }; 102 90 91 #define VBOX_EXTPACK "Oracle VM VirtualBox Extension Pack" 103 92 #define GPT_PTABLE_SIZE 32 * BLOCKSIZE /** Max size we to read for GPT partition table */ 104 93 #define MBR_PARTITIONS_MAX 4 /** Fixed number of partitions in Master Boot Record */ … … 114 103 #define VD_SECTOR_MASK (VD_SECTOR_SIZE - 1) /** Masks off a blocks worth of data */ 115 104 #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 117 106 #define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 118 107 … … 131 120 132 121 static PVDISK g_pVDisk; /** Handle for Virtual Disk in contet */ 133 static char *g_p vDiskUuid; /** UUID of image (if known, otherwise NULL) */122 static char *g_pszDiskUuid; /** UUID of image (if known, otherwise NULL) */ 134 123 static off_t g_vDiskOffset; /** Biases r/w from start of VD */ 135 124 static off_t g_vDiskSize; /** Limits r/w length for VD */ … … 137 126 static int32_t g_cWriters; /** Number of writers for VD */ 138 127 static 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 */141 128 static PVDINTERFACE g_pVdIfs; /** @todo Remove when VD I/O becomes threadsafe */ 142 129 static VDINTERFACETHREADSYNC g_VDIfThreadSync; /** @todo Remove when VD I/O becomes threadsafe */ … … 144 131 static uint16_t g_lastPartNbr; /** Last partition number found in MBR + EBR chain */ 145 132 static bool g_fGPT; /** True if GPT type partition table was found */ 133 static char *g_pszImageName; /** Base filename for current VD image */ 134 static char *g_pszImagePath; /** Full path to current VD image */ 135 static char *g_pszBaseImagePath; /** Base image known after parsing */ 136 static char *g_pszBaseImageName; /** Base image known after parsing */ 137 static uint32_t g_cImages; /** Number of images in diff chain */ 146 138 147 139 /* Table entry containing partition info parsed out of GPT or MBR and EBR chain of specified VD */ … … 168 160 PARTITIONINFO g_aParsedPartitionInfo[VBOXIMG_PARTITION_MAX + 1]; /* Note: Element 0 reserved for EntireDisk partitionEntry */ 169 161 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; 162 VBOXIMGOPTS g_vboximgOpts; 185 163 186 164 #define OPTION(fmt, pos, val) { fmt, offsetof(struct vboximgOpts, pos), val } 187 165 188 166 static 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), 207 189 FUSE_OPT_KEY("--help", USAGE_FLAG), 208 190 FUSE_OPT_KEY("-vm", FUSE_OPT_KEY_NONOPT), … … 210 192 }; 211 193 194 typedef 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 205 IMAGELIST listHeadLockList; /* flink & blink intentionally left NULL */ 206 212 207 static void 213 208 briefUsage() 214 209 { 215 RTPrintf("usage: vboximg-mount [options] <mount point>\n\n"210 RTPrintf("usage: vboximg-mount [options] <mount point directory path>\n\n" 216 211 "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" 218 214 "\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)" 224 224 "\n" 225 225 " [ --vm=UUID ] Restrict media list to specified vm.\n" … … 233 233 " (incompatible with -p, --partition)\n" 234 234 "\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" 240 236 "\n" 241 " [ --rw ] Make image writeable (default = readonly)\n"242 237 " [ --root ] Same as -o allow_root.\n" 243 238 "\n" 244 " [ { -v | --verbose } ] Log extra information.\n"239 " [ { -v | --verbose } ] Log extra information.\n" 245 240 "\n" 246 241 " [ -o opt[,opt...]] FUSE mount options.\n" … … 249 244 " [ --help ] Display long usage info (incl. FUSE opts).\n\n" 250 245 ); 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 ); 259 270 } 260 271 … … 262 273 vboximgOptHandler(void *data, const char *arg, int optKey, struct fuse_args *outargs) 263 274 { 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 268 280 /* 269 281 * Apparently this handler is only called for arguments FUSE can't parse, … … 280 292 static int vboximgOp_open(const char *pszPath, struct fuse_file_info *pInfo) 281 293 { 282 RT_NOREF(pszPath, pInfo); 294 RT_NOREF(pszPath, pInfo);; 283 295 LogFlowFunc(("pszPath=%s\n", pszPath)); 284 296 uint32_t notsup = 0; … … 339 351 } 340 352 353 341 354 /** @todo Remove when VD I/O becomes threadsafe */ 342 355 static DECLCALLBACK(int) vboximgThreadStartRead(void *pvUser) … … 368 381 static int vboximgOp_release(const char *pszPath, struct fuse_file_info *pInfo) 369 382 { 370 (void) pszPath;383 NOREF(pszPath); 371 384 372 385 LogFlowFunc(("pszPath=%s\n", pszPath)); … … 578 591 off_t offset, struct fuse_file_info *pInfo) 579 592 { 580 (void) pszPath;581 (void) pInfo;593 NOREF(pszPath); 594 NOREF(pInfo); 582 595 583 596 LogFlowFunc(("my offset=%#llx size=%#zx path=\"%s\"\n", (uint64_t)offset, cbBuf, pszPath)); … … 609 622 off_t offset, struct fuse_file_info *pInfo) 610 623 { 611 (void) pszPath;612 (void) pInfo;624 NOREF(pszPath); 625 NOREF(pInfo); 613 626 614 627 LogFlowFunc(("offset=%#llx size=%#zx path=\"%s\"\n", (uint64_t)offset, cbBuf, pszPath)); … … 646 659 int rc = 0; 647 660 648 LogFlowFunc(("pszPath=%s, stat(\"%s\")\n", pszPath, g_psz BaseImagePath));661 LogFlowFunc(("pszPath=%s, stat(\"%s\")\n", pszPath, g_pszImagePath)); 649 662 650 663 memset(stbuf, 0, sizeof(struct stat)); … … 657 670 else if (RTStrCmp(pszPath + 1, "vhdd") == 0) 658 671 { 659 rc = stat(g_psz BaseImagePath, stbuf);672 rc = stat(g_pszImagePath, stbuf); 660 673 if (rc < 0) 661 674 return rc; … … 668 681 stbuf->st_nlink = 1; 669 682 } 670 else if (RTStrNCmp(pszPath + 1, g_psz BaseImageName, strlen(g_pszBaseImageName)) == 0)683 else if (RTStrNCmp(pszPath + 1, g_pszImageName, strlen(g_pszImageName)) == 0) 671 684 { 672 685 /* When the disk is partitioned, the symbolic link named from `basename` of … … 678 691 * simple_fixed_disk.vdi[20480:2013244928] vhdd 679 692 */ 680 rc = stat(g_psz BaseImagePath, stbuf);693 rc = stat(g_pszImagePath, stbuf); 681 694 if (rc < 0) 682 695 return rc; … … 698 711 699 712 { 700 (void) offset;701 (void) pInfo;713 NOREF(offset); 714 NOREF(pInfo); 702 715 703 716 if (RTStrCmp(pszPath, "/") != 0) … … 719 732 720 733 if (g_vDiskOffset == 0 && (g_vDiskSize == 0 || g_vDiskSize == g_cbEntireVDisk)) 721 pfnFiller(pvBuf, g_psz BaseImageName, NULL, 0);734 pfnFiller(pvBuf, g_pszImageName, NULL, 0); 722 735 else 723 736 { 724 737 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); 726 739 pfnFiller(pvBuf, tmp, NULL, 0); 727 740 } … … 739 752 vboximgOp_readlink(const char *pszPath, char *buf, size_t size) 740 753 { 741 (void) pszPath;742 RTStrCopy(buf, size, g_psz BaseImagePath);754 NOREF(pszPath); 755 RTStrCopy(buf, size, g_pszImagePath); 743 756 return 0; 744 }745 746 static void747 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 do789 {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 else805 {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 else814 {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 each832 *833 * @param virtualBox VirtualBox instance object.834 */835 static void836 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 == NULL862 || RTStrNCmp(CSTR(pMachineUuid), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0863 || 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 void882 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)) == 0899 || RTStrCmp(pszImageString, CSTR(pMediumName)) == 0)900 {901 *pBaseImage = aDisks[i];902 return;903 }904 }905 }906 757 } 907 758 … … 984 835 985 836 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 else999 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 }1008 837 1009 838 if (!pTblBuf) … … 1112 941 { 1113 942 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 1114 950 void *colBoot = NULL; 1115 951 … … 1119 955 void *colPartNbr = tbl.addCol("#", "%3d", 1); 1120 956 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 */ 1122 958 for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++) 1123 959 if (g_aParsedPartitionInfo[idxPartition].fBootable) { … … 1128 964 void *colStart = tbl.addCol("Start", "%lld", 1); 1129 965 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); 1131 967 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 */ 1133 971 void *colName = tbl.addCol("Name", "%s", -1); */ 1134 void *colType = tbl.addCol("Type", "%s", -1, 2); 972 #endif 1135 973 1136 974 for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++) … … 1139 977 if (ppi->idxPartition) 1140 978 { 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 1149 979 char abGuid[GUID_STRING_LENGTH * 2]; 1150 980 RTStrPrintf(abGuid, sizeof(abGuid), "%RTuuid", &ppi->partitionType.gptGuidTypeSpecifier); … … 1167 997 tbl.setCell(row, colStart, ppi->offPartition / BLOCKSIZE); 1168 998 tbl.setCell(row, colSectors, ppi->cbPartition / BLOCKSIZE); 1169 tbl.setCell(row, colSize, cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude);999 tbl.setCell(row, colSize, vboximgScaledSize(ppi->cbPartition)); 1170 1000 tbl.setCell(row, colOffset, ppi->offPartition); 1171 /* tbl.setCell(row, colName, ppi->pszName); ... see comment for column definition */1172 1001 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 1173 1007 } 1174 1008 } … … 1184 1018 * are adapted to the actual data, to avoid insufficient or excessive whitespace. 1185 1019 */ 1020 1186 1021 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); 1190 1027 1191 1028 SELFSIZINGTABLE tbl(2); 1192 1029 1193 void *colPartition = tbl.addCol("Partition", "%s %d", -1);1030 void *colPartition = tbl.addCol("Partition", "%s(%d)", -1); 1194 1031 void *colBoot = tbl.addCol("Boot", "%c ", 1); 1195 1032 void *colStart = tbl.addCol("Start", "%lld", 1); 1196 1033 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); 1198 1035 void *colOffset = tbl.addCol("Offset", "%lld", 1); 1199 1036 void *colId = tbl.addCol("Id", "%2x", 1); … … 1205 1042 if (p->idxPartition) 1206 1043 { 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 1215 1044 void *row = tbl.addRow(); 1216 1217 1045 tbl.setCell(row, colPartition, g_pszBaseImageName, idxPartition); 1218 1046 tbl.setCell(row, colBoot, p->fBootable ? '*' : ' '); 1219 1047 tbl.setCell(row, colStart, p->offPartition / BLOCKSIZE); 1220 1048 tbl.setCell(row, colSectors, p->cbPartition / BLOCKSIZE); 1221 tbl.setCell(row, colSize, cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude);1049 tbl.setCell(row, colSize, vboximgScaledSize(p->cbPartition)); 1222 1050 tbl.setCell(row, colOffset, p->offPartition); 1223 1051 tbl.setCell(row, colId, p->partitionType.legacy); … … 1253 1081 memset(&g_vboximgOpts, 0, sizeof(g_vboximgOpts)); 1254 1082 1083 g_vboximgOpts.idxPartition = -1; 1084 1255 1085 rc = fuse_opt_parse(&args, &g_vboximgOpts, vboximgOptDefs, vboximgOptHandler); 1256 1086 if (rc < 0 || argc < 2 || RTStrCmp(argv[1], "-?" ) == 0 || g_vboximgOpts.fBriefUsage) … … 1260 1090 } 1261 1091 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 } 1262 1112 if (g_vboximgOpts.fAllowRoot) 1263 1113 fuse_opt_add_arg(&args, "-oallow_root"); … … 1291 1141 if (SUCCEEDED(hrc)) 1292 1142 hrc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam()); 1143 1293 1144 if (FAILED(hrc)) 1294 1145 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get IVirtualBox object! (hrc=%Rhrc)", hrc); 1295 1146 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; 1307 1156 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 1311 1180 /* 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) 1314 1185 */ 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())); 1355 1305 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++) 1362 1315 { 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) 1365 1319 { 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; 1369 1322 } 1370 1323 } 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)); 1452 1329 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; 1475 1418 g_cbEntireVDisk = VDGetSize(g_pVDisk, 0 /* base */); 1476 1419 … … 1481 1424 1482 1425 RTPrintf("\n"); 1483 1484 1426 rc = parsePartitionTable(); 1485 1427 switch(rc) … … 1496 1438 return 0; 1497 1439 } 1440 1498 1441 if (g_vboximgOpts.idxPartition >= 0) 1499 1442 { … … 1516 1459 if (partNbr < 0 || partNbr > g_lastPartNbr) 1517 1460 return RTMsgErrorExitFailure("Non-valid partition number specified\n"); 1518 1519 1461 if (partNbr == 0) 1520 1462 { 1521 1463 g_vDiskOffset = 0; 1522 1464 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"); 1525 1467 } else { 1526 for (int i = 0; i < g_lastPartNbr; i++) 1468 int fFoundPartition = false; 1469 for (int i = 1; i < g_lastPartNbr + 1; i++) 1527 1470 { 1528 1471 /* If GPT, display vboximg's representation of partition table starts at partition 2 1529 1472 * but the table is displayed calling it partition 1, because the protective MBR 1530 1473 * 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)) 1533 1475 { 1476 fFoundPartition = true; 1534 1477 g_vDiskOffset = g_aParsedPartitionInfo[i].offPartition; 1535 1478 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", 1538 1481 g_vboximgOpts.idxPartition, g_vDiskOffset / BLOCKSIZE, g_vDiskSize / BLOCKSIZE); 1539 1482 } 1540 1483 } 1484 if (!fFoundPartition) 1485 return RTMsgErrorExitFailure("Couldn't find partition %d in partition table\n", partNbr); 1541 1486 } 1542 1487 } else { … … 1545 1490 return RTMsgErrorExitFailure("User specified offset out of range of virtual disk\n"); 1546 1491 1547 if ( g_vboximgOpts.fVerbose)1492 if (VERBOSE) 1548 1493 RTPrintf("Setting r/w bias (offset) to user requested value for sector %llu\n", g_vDiskOffset / BLOCKSIZE); 1549 1494 … … 1554 1499 return RTMsgErrorExitFailure("User specified size out of range of virtual disk\n"); 1555 1500 1556 if ( g_vboximgOpts.fVerbose)1501 if (VERBOSE) 1557 1502 RTPrintf("Setting r/w size limit to user requested value %llu\n", g_vDiskSize / BLOCKSIZE); 1558 1503 … … 1566 1511 * Hand control over to libfuse. 1567 1512 */ 1568 if ( g_vboximgOpts.fVerbose)1513 if (VERBOSE) 1569 1514 RTPrintf("\nvboximg-mount: Going into background...\n"); 1570 1515
Note:
See TracChangeset
for help on using the changeset viewer.