Changeset 75815 in vbox for trunk/src/VBox/ImageMounter/vboxraw/vboxraw.cpp
- Timestamp:
- Nov 29, 2018 2:03:50 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ImageMounter/vboxraw/vboxraw.cpp
r75476 r75815 5 5 6 6 /* 7 * Copyright (C) 2009-201 7Oracle Corporation7 * Copyright (C) 2009-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 20 20 * Header Files * 21 21 *********************************************************************************************************************************/ 22 23 /*** PKK TEMPORARY FOR DEBUGGING DON'T PUT INTO PRODUCTION CODE */ 24 #include <stdio.h> 25 /*** END OF ADMONITION */ 26 27 22 28 #define LOG_GROUP LOG_GROUP_DEFAULT /** @todo log group */ 23 29 … … 27 33 #endif 28 34 #define MAX_READERS (INT32_MAX / 32) 29 30 35 #include <fuse.h> 31 36 #ifdef UNIX_DERIVATIVE … … 35 40 #include <libgen.h> 36 41 #include <unistd.h> 42 #include <math.h> 43 //#include <stdarg.h> 44 #include <cstdarg> 37 45 #include <sys/stat.h> 38 46 #endif … … 70 78 #include <iprt/types.h> 71 79 #include <iprt/path.h> 72 80 #include <iprt/utf16.h> 81 82 #include "vboxraw.h" 83 #include "SelfSizingTable.h" 84 85 /* 86 * PKK: REMOVE AFTER DEBUGGING 87 */ 73 88 #pragma GCC diagnostic ignored "-Wunused-variable" 74 89 #pragma GCC diagnostic ignored "-Wunused-parameter" … … 88 103 } g_u; 89 104 90 91 #define VD_SECTOR_SIZE 0x200 /* 0t512 */ 92 #define VD_SECTOR_MASK (VD_SECTOR_SIZE - 1) 93 #define VD_SECTOR_OUT_OF_BOUNDS_MASK (~UINT64_C(VD_SECTOR_MASK)) 94 95 #define PADMAX 50 96 #define MAX_ID_LEN 256 97 #define CSTR(arg) Utf8Str(arg).c_str() 98 99 static struct fuse_operations g_vboxrawOps; 100 PVDISK g_pVDisk; 101 int32_t g_cReaders; 102 int32_t g_cWriters; 103 RTFOFF g_cbPrimary; 104 char *g_pszBaseImageName; 105 char *g_pszBaseImagePath; 106 PVDINTERFACE g_pVdIfs; /** @todo Remove when VD I/O becomes threadsafe */ 107 VDINTERFACETHREADSYNC g_VDIfThreadSync; /** @todo Remove when VD I/O becomes threadsafe */ 108 RTCRITSECT g_vdioLock; /** @todo Remove when VD I/O becomes threadsafe */ 109 110 char *nsIDToString(nsID *guid); 111 void printErrorInfo(); 112 /** XPCOM stuff */ 105 const uint64_t KB = 1024; 106 const uint64_t MB = KB * KB; 107 const uint64_t GB = MB * KB; 108 const uint64_t TB = GB * KB; 109 const uint64_t PB = TB * KB; 110 111 112 113 enum { PARTITION_TABLE_MBR = 1, PARTITION_TABLE_GPT = 2 }; 114 115 #define GPT_PTABLE_SIZE 32 * BLOCKSIZE /** Max size we to read for GPT partition table */ 116 #define MBR_PARTITIONS_MAX 4 /** Fixed number of partitions in Master Boot Record */ 117 #define BASENAME_MAX 256 /** Maximum name for the basename of a path (for RTStrNLen()*/ 118 #define VBOXRAW_PARTITION_MAX 256 /** How much storage to allocate to store partition info */ 119 #define PARTITION_NAME_MAX 72 /** Maximum partition name size (accomodates GPT partition name) */ 120 #define BLOCKSIZE 512 /** Commonly used disk block size */ 121 #define DOS_BOOT_RECORD_SIGNATURE 0xaa55 /** MBR and EBR (partition table) signature [EOT boundary] */ 122 #define NULL_BOOT_RECORD_SIGNATURE 0x0000 /** MBR or EBR null signature value */ 123 #define MAX_UUID_LEN 256 /** Max length of a UUID */ 124 #define LBA(n) (n * BLOCKSIZE) 125 #define VD_SECTOR_SIZE 512 /** Virtual disk sector/blocksize */ 126 #define VD_SECTOR_MASK (VD_SECTOR_SIZE - 1) /** Masks off a blocks worth of data */ 127 #define VD_SECTOR_OUT_OF_BOUNDS_MASK (~UINT64_C(VD_SECTOR_MASK)) /** Masks the overflow of a blocks worth of data */ 128 129 #define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 130 131 #define PARTTYPE_IS_NULL(parType) ((uint8_t)parType == 0x00) 132 #define PARTTYPE_IS_GPT(parType) ((uint8_t)parType == 0xee) 133 #define PARTTYPE_IS_EXT(parType) (( (uint8_t)parType) == 0x05 /* Extended */ \ 134 || ((uint8_t)parType) == 0x0f /* W95 Extended (LBA) */ \ 135 || ((uint8_t)parType) == 0x85) /* Linux Extended */ 136 137 #define SAFENULL(strPtr) (strPtr ? strPtr : "") 138 139 #define CSTR(arg) Utf8Str(arg).c_str() /* Converts XPCOM string type to C string type */ 140 141 142 static struct fuse_operations g_vboxrawOps; /** FUSE structure that defines allowed ops for this FS */ 143 144 /* Global variables */ 145 146 static PVDISK g_pVDisk; /** Handle for Virtual Disk in contet */ 147 static char *g_pvDiskUuid; /** UUID of image (if known, otherwise NULL) */ 148 static off_t g_vDiskOffset; /** Biases r/w from start of VD */ 149 static off_t g_vDiskSize; /** Limits r/w length for VD */ 150 static int32_t g_cReaders; /** Number of readers for VD */ 151 static int32_t g_cWriters; /** Number of writers for VD */ 152 static RTFOFF g_cbEntireVDisk; /** Size of VD */ 153 static char *g_pszBaseImageName; /** Base filename for current VD image */ 154 static char *g_pszBaseImagePath; /** Full path to current VD image */ 155 static PVDINTERFACE g_pVdIfs; /** @todo Remove when VD I/O becomes threadsafe */ 156 static VDINTERFACETHREADSYNC g_VDIfThreadSync; /** @todo Remove when VD I/O becomes threadsafe */ 157 static RTCRITSECT g_vdioLock; /** @todo Remove when VD I/O becomes threadsafe */ 158 static uint16_t g_lastPartNbr; /** Last partition number found in MBR + EBR chain */ 159 static bool g_fGPT; /** True if GPT type partition table was found */ 160 161 /* Table entry containing partition info parsed out of GPT or MBR and EBR chain of specified VD */ 162 163 typedef struct 164 { 165 int idxPartition; /** partition number */ 166 char *pszName; 167 off_t offPartition; /** partition offset from start of disk, in bytes */ 168 uint64_t cbPartition; /** partition size in bytes */ 169 uint8_t fBootable; /** partition bootable */ 170 union 171 { 172 uint8_t legacy; /** partition type MBR/EBR */ 173 uint128_t gptGuidTypeSpecifier; /** partition type GPT */ 174 } partitionType; /** uint8_t for MBR/EBR (legacy) and GUID for GPT */ 175 176 union 177 { 178 MBRPARTITIONENTRY mbrEntry; /** MBR (also EBR partition entry) */ 179 GPTPARTITIONENTRY gptEntry; /** GPT partition entry */ 180 } partitionEntry; 181 } PARTITIONINFO; 182 183 PARTITIONINFO g_aParsedPartitionInfo[VBOXRAW_PARTITION_MAX + 1]; /* Note: Element 0 reserved for EntireDisk partitionEntry */ 113 184 114 185 static struct vboxrawOpts { 115 char *pszVm; 116 char *pszImage; 117 char *pszImageUuid; 118 uint32_t cHddImageDiffMax; 119 uint32_t fList; 120 uint32_t fAllowRoot; 121 uint32_t fRW; 122 uint32_t fVerbose; 186 char *pszVm; /** optional VM UUID */ 187 char *pszImage; /** Virtual Disk image UUID or path */ 188 int32_t idxPartition; /** Number of partition to constrain FUSE based FS to (optional) 0 - whole disk*/ 189 int32_t offset; /** Offset to base virtual disk reads and writes from (altnerative to partition) */ 190 int32_t size; /** Size of accessible disk region, starting at offset, default = offset 0 */ 191 uint32_t cHddImageDiffMax; /** Max number of differencing images (snapshots) to apply to image */ 192 uint32_t fListMedia; /** Flag to list virtual disks of all known VMs */ 193 uint32_t fListMediaBrief; /** Flag to list virtual disks of all known VMs */ 194 uint32_t fListParts; /** Flag to summarily list partitions associated with pszImage */ 195 uint32_t fAllowRoot; /** Flag to allow root to access this FUSE FS */ 196 uint32_t fRW; /** Flag to allow changes to FUSE-mounted Virtual Disk image */ 197 uint32_t fBriefUsage; /** Flag to display only FS-specific program usage options */ 198 uint32_t fVerbose; /** Make some noise */ 123 199 } g_vboxrawOpts; 124 200 … … 126 202 127 203 static struct fuse_opt vboxrawOptDefs[] = { 128 OPTION("--list", fList, 1), 129 OPTION("--root", fAllowRoot, 1), 130 OPTION("--vm=%s", pszVm, 0), 131 OPTION("--maxdiff=%d", cHddImageDiffMax, 1), 132 OPTION("--diff=%d", cHddImageDiffMax, 1), 133 OPTION("--image=%s", pszImage, 0), 134 OPTION("--rw", fRW, 1), 135 OPTION("--verbose", fVerbose, 1), 136 FUSE_OPT_KEY("-h", USAGE_FLAG), 204 OPTION("-l", fListMediaBrief, 1), 205 OPTION("-L", fListMedia, 1), 206 OPTION("-t", fListParts, 1), 207 OPTION("--root", fAllowRoot, 1), 208 OPTION("--vm=%s", pszVm, 0), 209 OPTION("--maxdiff=%d", cHddImageDiffMax, 1), 210 OPTION("--diff=%d", cHddImageDiffMax, 1), 211 OPTION("--partition=%d", idxPartition, 1), 212 OPTION("-p %d", idxPartition, 1), 213 OPTION("--offset=%d", offset, 1), 214 OPTION("-o %d", offset, 1), 215 OPTION("--size=%d", size, 1), 216 OPTION("-s %d", size, 1), 217 OPTION("--image=%s", pszImage, 0), 218 OPTION("-i %s", pszImage, 0), 219 OPTION("--rw", fRW, 1), 220 OPTION("--verbose", fVerbose, 1), 221 OPTION("-v", fVerbose, 1), 222 OPTION("-h", fBriefUsage, 1), 137 223 FUSE_OPT_KEY("--help", USAGE_FLAG), 138 224 FUSE_OPT_END 139 225 }; 140 226 141 static int vboxrawOptHandler(void *data, const char *arg, int optKey, struct fuse_args *outargs) 227 static void 228 briefUsage() 229 { 230 RTPrintf("usage: vboxraw [options] <mountpoint>\n\n" 231 "vboxraw options:\n\n" 232 " [ -l ] List virtual disk media (brief version)\n" 233 " [ -L ] List virtual disk media (long version)\n" 234 " [ -t ] List partition table (requires -i or --image option)\n" 235 "\n" 236 " [ { -i | --image= } <UUID | name | path> ] Virtual Box disk image to use\n" 237 "\n" 238 " [ { -p | --partition= } <partition #> ] Mount specified partition number via FUSE\n" 239 "\n" 240 " [ { -o | --offset= } <byte #> ] Disk I/O will be based on offset from disk start\n" 241 " (Can't use with -p or --partition options)\n" 242 "\n" 243 " [ -s | --size=<bytes>] Sets size of mounted disk from disk start or from\n" 244 " offset, if specified. (Can't use with\n" 245 " -p or --partition options)\n" 246 "\n" 247 " [ --diff=<diff #> ] Apply diffs (snapshot differencing disk images)\n" 248 " to specified base disk image up to and including\n" 249 " specified diff number.\n" 250 " (0 = Apply no diffs, default = Apply all diffs)\n" 251 "\n" 252 " [ --rw] Make image writeable (default = readonly)\n" 253 " [ --root] Same as -o allow_root\n" 254 "\n" 255 " [ --vm < Path | UUID >] VM UUID (limit media list to specific VM)\n" 256 "\n" 257 " [ --verbose] Log extra information\n" 258 " -o opt[,opt...] FUSE mount options\n" 259 " -h Display short usage info showing only the above\n" 260 " --help Display long usage info (including FUSE opts)\n\n" 261 ); 262 RTPrintf("\n"); 263 RTPrintf("When successful, the --image option creates a one-directory-deep filesystem \n"); 264 RTPrintf("rooted at the specified mountpoint. The contents of the directory will be \n"); 265 RTPrintf("a symbolic link with the base name of the image file pointing to the path of\n"); 266 RTPrintf("the virtual disk image, and a regular file named 'vhdd', which represents\n"); 267 RTPrintf("the byte stream of the disk image as interpreted by VirtualBox.\n"); 268 RTPrintf("It is the vhdd file that the user or a utility will subsequently mount on\n"); 269 RTPrintf("the host OS to gain access to the virtual disk contents.\n\n"); 270 RTPrintf("If any of the partition, size or offset related options are used the\n"); 271 RTPrintf("The constraining start offset (in bytes) and size (in bytes) will be\n"); 272 RTPrintf("appended in brackets to the symbolic link basename to indicate\n"); 273 RTPrintf("what part of the image is exposed by the FUSE filesystem implementation.\n\n"); 274 } 275 276 static int 277 vboxrawOptHandler(void *data, const char *arg, int optKey, struct fuse_args *outargs) 142 278 { 143 279 (void) data; 144 280 (void) arg; 145 146 char *progname = basename(outargs->argv[0]);147 281 switch(optKey) 148 282 { 149 283 case USAGE_FLAG: 150 RTPrintf("usage: %s [options] <mountpoint>\n\n" 151 "%s options:\n" 152 " [--list] List media\n" 153 " [--root] Same as -o allow_root\n" 154 " [--rw] writeable (default = readonly)\n" 155 " [--vm <name | UUID >] vm UUID (limit media list to specific VM)\n\n" 156 " [--diff=<diff #> ] Apply diffs to base image up " 157 "to and including specified diff #\n" 158 " (0 = no diffs, default: all diffs)\n\n" 159 " [--image=<UUID, name or path>] Image UUID or path\n" 160 " [--verbose] Log extra information\n" 161 " -o opt[,opt...] mount options\n" 162 " -h --help print usage\n\n", 163 progname, progname); 164 RTPrintf("\n"); 165 RTPrintf("When successful, the --image option creates a one-directory-deep filesystem \n"); 166 RTPrintf("rooted at the specified mountpoint. The contents of the directory will be \n"); 167 RTPrintf("a symbolic link with the base name of the image file pointing to the path of\n"); 168 RTPrintf("the virtual disk image, and a regular file named 'vhdd', which represents\n"); 169 RTPrintf("the byte stream of the disk image as interpreted by VirtualBox.\n"); 170 RTPrintf("It is the vhdd file that the user or a utility will subsequently mount on\n"); 171 RTPrintf("the host OS to gain access to the virtual disk contents.\n\n"); 284 briefUsage(); 172 285 fuse_opt_add_arg(outargs, "-ho"); 173 286 fuse_main(outargs->argc, outargs->argv, &g_vboxrawOps, NULL); 174 exit(1);287 break; 175 288 } 176 289 return 1; … … 207 320 rc = -EINVAL; 208 321 # ifdef O_DIRECTORY 209 210 322 if (pInfo->flags & O_DIRECTORY) 323 rc = -ENOTDIR; 211 324 # endif 212 325 #endif … … 263 376 return RTCritSectLeave(vdioLock); 264 377 } 265 266 378 /** @todo (end of to do section) */ 267 379 … … 290 402 return 0; 291 403 } 292 293 404 294 405 /** 295 406 * VD read Sanitizer taking care of unaligned accesses. 296 407 * 297 * @return VBox statuscode.408 * @return VBox bootIndicator code. 298 409 * @param pDisk VD disk container. 299 410 * @param off Offset to start reading from. … … 305 416 int rc; 306 417 307 uint64_t const cbMisalign Head= off & VD_SECTOR_MASK;308 uint64_t const cbMisalign Tail= (off + cbRead) & VD_SECTOR_MASK;309 310 if (cbMisalign Head + cbMisalignTail== 0) /* perfectly aligned request; just read it and done */418 uint64_t const cbMisalignmentOfStart = off & VD_SECTOR_MASK; 419 uint64_t const cbMisalignmentOfEnd = (off + cbRead) & VD_SECTOR_MASK; 420 421 if (cbMisalignmentOfStart + cbMisalignmentOfEnd == 0) /* perfectly aligned request; just read it and done */ 311 422 rc = VDRead(pDisk, off, pvBuf, cbRead); 312 423 else … … 318 429 * bytes (requested by user), only up to sector boundary, into user's buffer 319 430 */ 320 if (cbMisalign Head)321 { 322 rc = VDRead(pDisk, off - cbMisalign Head, abBuf, VD_SECTOR_SIZE);431 if (cbMisalignmentOfStart) 432 { 433 rc = VDRead(pDisk, off - cbMisalignmentOfStart, abBuf, VD_SECTOR_SIZE); 323 434 if (RT_SUCCESS(rc)) 324 435 { 325 size_t const cbPart = RT_MIN(VD_SECTOR_SIZE - cbMisalignHead, cbRead);326 memcpy(pbBuf, &abBuf[cbMisalign Head], cbPart);327 pbBuf += cbPart ;328 off += cbPart ; /* Beginning of next sector or EOD */329 cbRead -= cbPart ; /* # left to read */436 size_t const cbPartial = RT_MIN(VD_SECTOR_SIZE - cbMisalignmentOfStart, cbRead); 437 memcpy(pbBuf, &abBuf[cbMisalignmentOfStart], cbPartial); 438 pbBuf += cbPartial; 439 off += cbPartial; /* Beginning of next sector or EOD */ 440 cbRead -= cbPartial; /* # left to read */ 330 441 } 331 442 } … … 338 449 Assert(!(off % VD_SECTOR_SIZE)); 339 450 340 size_t cbPart = cbRead - cbMisalignTail;341 Assert(!(cbPart % VD_SECTOR_SIZE));342 rc = VDRead(pDisk, off, pbBuf, cbPart );451 size_t cbPartial = cbRead - cbMisalignmentOfEnd; 452 Assert(!(cbPartial % VD_SECTOR_SIZE)); 453 rc = VDRead(pDisk, off, pbBuf, cbPartial); 343 454 if (RT_SUCCESS(rc)) 344 455 { 345 pbBuf += cbPart ;346 off += cbPart ;347 cbRead -= cbPart ;456 pbBuf += cbPartial; 457 off += cbPartial; 458 cbRead -= cbPartial; 348 459 } 349 460 } … … 352 463 if (RT_SUCCESS(rc) && cbRead) 353 464 { 354 Assert(cbRead == cbMisalign Tail);465 Assert(cbRead == cbMisalignmentOfEnd); 355 466 Assert(cbRead < VD_SECTOR_SIZE); 356 467 Assert(!(off % VD_SECTOR_SIZE)); … … 374 485 * VD write Sanitizer taking care of unaligned accesses. 375 486 * 376 * @return VBox statuscode.487 * @return VBox bootIndicator code. 377 488 * @param pDisk VD disk container. 378 489 * @param off Offset to start writing to. … … 386 497 int rc; 387 498 int cbRemaining = cbWrite; 499 388 500 /* 389 501 * Take direct route if the request is sector aligned. 390 502 */ 391 uint64_t const cbMisalign Head = off & 511;392 size_t const cbMisalign Tail = (off + cbWrite) & 511;393 if (!cbMisalign Head && !cbMisalignTail)503 uint64_t const cbMisalignmentOfStart = off & VD_SECTOR_MASK; 504 size_t const cbMisalignmentOfEnd = (off + cbWrite) & VD_SECTOR_MASK; 505 if (!cbMisalignmentOfStart && !cbMisalignmentOfEnd) 394 506 { 395 507 rc = VDWrite(pDisk, off, pbSrc, cbWrite); … … 413 525 * Unaligned buffered read+write of head. Aligns the offset. 414 526 */ 415 if (cbMisalign Head)416 { 417 rc = VDRead(pDisk, off - cbMisalign Head, abBuf, VD_SECTOR_SIZE);527 if (cbMisalignmentOfStart) 528 { 529 rc = VDRead(pDisk, off - cbMisalignmentOfStart, abBuf, VD_SECTOR_SIZE); 418 530 if (RT_SUCCESS(rc)) 419 531 { 420 size_t const cbPart = RT_MIN(VD_SECTOR_SIZE - cbMisalignHead, cbWrite);421 memcpy(&abBuf[cbMisalign Head], pbSrc, cbPart);422 rc = VDWrite(pDisk, off - cbMisalign Head, abBuf, VD_SECTOR_SIZE);532 size_t const cbPartial = RT_MIN(VD_SECTOR_SIZE - cbMisalignmentOfStart, cbWrite); 533 memcpy(&abBuf[cbMisalignmentOfStart], pbSrc, cbPartial); 534 rc = VDWrite(pDisk, off - cbMisalignmentOfStart, abBuf, VD_SECTOR_SIZE); 423 535 if (RT_SUCCESS(rc)) 424 536 { 425 pbSrc += cbPart ;426 off += cbPart ;427 cbRemaining -= cbPart ;537 pbSrc += cbPartial; 538 off += cbPartial; 539 cbRemaining -= cbPartial; 428 540 } 429 541 } … … 438 550 { 439 551 Assert(!(off % VD_SECTOR_SIZE)); 440 size_t cbPart = cbWrite - cbMisalignTail;441 Assert(!(cbPart % VD_SECTOR_SIZE));442 rc = VDWrite(pDisk, off, pbSrc, cbPart );552 size_t cbPartial = cbWrite - cbMisalignmentOfEnd; 553 Assert(!(cbPartial % VD_SECTOR_SIZE)); 554 rc = VDWrite(pDisk, off, pbSrc, cbPartial); 443 555 if (RT_SUCCESS(rc)) 444 556 { 445 pbSrc += cbPart ;446 off += cbPart ;447 cbRemaining -= cbPart ;557 pbSrc += cbPartial; 558 off += cbPartial; 559 cbRemaining -= cbPartial; 448 560 } 449 561 } … … 454 566 if ( RT_SUCCESS(rc) && cbWrite > 0) 455 567 { 456 Assert(cbWrite == cbMisalign Tail);568 Assert(cbWrite == cbMisalignmentOfEnd); 457 569 Assert(cbWrite < VD_SECTOR_SIZE); 458 570 Assert(!(off % VD_SECTOR_SIZE)); … … 488 600 AssertReturn((unsigned)cbBuf == cbBuf, -EINVAL); 489 601 602 AssertReturn(offset + g_vDiskOffset >= 0, -EINVAL); 603 int64_t adjOff = offset + g_vDiskOffset; 604 490 605 int rc = 0; 491 if ((off_t)( offset + cbBuf) < offset)606 if ((off_t)(adjOff + cbBuf) < adjOff) 492 607 rc = -EINVAL; 493 else if ( offset >= g_cbPrimary)608 else if (adjOff >= g_vDiskSize) 494 609 return 0; 495 610 else if (!cbBuf) … … 497 612 498 613 if (rc >= 0) 499 rc = vdReadSanitizer(g_pVDisk, offset, pbBuf, cbBuf);614 rc = vdReadSanitizer(g_pVDisk, adjOff, pbBuf, cbBuf); 500 615 if (rc < 0) 501 616 LogFlowFunc(("%s\n", strerror(rc))); … … 515 630 AssertReturn((int)cbBuf >= 0, -EINVAL); 516 631 AssertReturn((unsigned)cbBuf == cbBuf, -EINVAL); 632 AssertReturn(offset + g_vDiskOffset >= 0, -EINVAL); 633 int64_t adjOff = offset + g_vDiskOffset; 517 634 518 635 int rc = 0; … … 521 638 " (write operation ignored w/o error!)\n")); 522 639 return cbBuf; 523 } else if ((off_t)( offset + cbBuf) < offset)640 } else if ((off_t)(adjOff + cbBuf) < adjOff) 524 641 rc = -EINVAL; 525 else if (offset >= g_ cbPrimary)642 else if (offset >= g_vDiskSize) 526 643 return 0; 527 644 else if (!cbBuf) … … 529 646 530 647 if (rc >= 0) 531 rc = vdWriteSanitizer(g_pVDisk, offset, pbBuf, cbBuf);648 rc = vdWriteSanitizer(g_pVDisk, adjOff, pbBuf, cbBuf); 532 649 if (rc < 0) 533 650 LogFlowFunc(("%s\n", strerror(rc))); … … 556 673 if (rc < 0) 557 674 return rc; 558 559 stbuf->st_size = VDGetSize(g_pVDisk, 0); 675 /* 676 * st_size represents the size of the FUSE FS-mounted portion of the disk. 677 * By default it is the whole disk, but can be a partition or specified 678 * (or overridden) directly by the { -s | --size } option on the command line. 679 */ 680 stbuf->st_size = g_vDiskSize; 560 681 stbuf->st_nlink = 1; 561 682 } 562 else if (RTStrCmp(pszPath + 1, g_pszBaseImageName) == 0) 563 { 683 else if (RTStrNCmp(pszPath + 1, g_pszBaseImageName, strlen(g_pszBaseImageName)) == 0) 684 { 685 /* When the disk is partitioned, the symbolic link named from `basename` of 686 * resolved path to VBox disk image, has appended to it formatted text 687 * representing the offset range of the partition. 688 * 689 * $ vboxraw -i /stroll/along/the/path/simple_fixed_disk.vdi -p 1 /mnt/tmpdir 690 * $ ls /mnt/tmpdir 691 * simple_fixed_disk.vdi[20480:2013244928] vhdd 692 */ 564 693 rc = stat(g_pszBaseImagePath, stbuf); 565 694 if (rc < 0) … … 590 719 591 720 /* 592 * The usual suspects (mandatory)721 * mandatory '.', '..', ... 593 722 */ 594 723 pfnFiller(pvBuf, ".", NULL, 0); … … 596 725 597 726 /* 598 * Create one entry w/basename of original image that getattr() will 599 * depict as a symbolic link pointing back to the original file, 600 * as a convenience, so anyone who lists the FUSE file system can 601 * easily find the associated vdisk. 727 * Create FUSE FS dir entry that is depicted here (and exposed via stat()) as 728 * a symbolic link back to the resolved path to the VBox virtual disk image, 729 * whose symlink name is basename that path. This is a convenience so anyone 730 * listing the dir can figure out easily what the vhdd FUSE node entry 731 * represents. 602 732 */ 603 pfnFiller(pvBuf, g_pszBaseImageName, NULL, 0); 604 733 734 if (g_vDiskOffset == 0 && (g_vDiskSize == 0 || g_vDiskSize == g_cbEntireVDisk)) 735 pfnFiller(pvBuf, g_pszBaseImageName, NULL, 0); 736 else 737 { 738 char tmp[BASENAME_MAX]; 739 RTStrPrintf(tmp, sizeof (tmp), "%s[%d:%d]", g_pszBaseImageName, g_vDiskOffset, g_vDiskSize); 740 pfnFiller(pvBuf, tmp, NULL, 0); 741 } 605 742 /* 606 743 * Create entry named "vhdd", which getattr() will describe as a … … 622 759 623 760 static void 624 listMedia(IMachine *pMachine )761 listMedia(IMachine *pMachine, char *vmName, char *vmUuid) 625 762 { 626 763 int rc = 0; … … 628 765 629 766 CHECK_ERROR(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(pMediumAttachments))); 767 int firstIteration = 1; 630 768 for (size_t i = 0; i < pMediumAttachments.size(); i++) 631 769 { 770 632 771 ComPtr<IMedium> pMedium; 633 772 DeviceType_T deviceType; … … 661 800 if (pEarliestAncestor.isNull()) 662 801 return; 663 RTPrintf("\n");664 802 do 665 803 { … … 671 809 if (ancestorNumber == 0) 672 810 { 673 RTPrintf(" -----------------------\n"); 674 RTPrintf(" HDD base: \"%s\"\n", CSTR(pMediumName)); 675 RTPrintf(" UUID: %s\n", CSTR(pMediumUuid)); 676 RTPrintf(" Location: %s\n\n", CSTR(pMediumPath)); 811 if (!g_vboxrawOpts.fListMediaBrief) 812 { 813 RTPrintf(" -----------------------\n"); 814 RTPrintf(" HDD base: \"%s\"\n", CSTR(pMediumName)); 815 RTPrintf(" UUID: %s\n", CSTR(pMediumUuid)); 816 RTPrintf(" Location: %s\n\n", CSTR(pMediumPath)); 817 } 818 else 819 { 820 if (firstIteration) 821 RTPrintf("\nVM: %s " ANSI_BOLD "%-20s" ANSI_RESET "\n", 822 vmUuid, vmName); 823 RTPrintf(" img: %s " ANSI_BOLD " %s" ANSI_RESET "\n", 824 CSTR(pMediumUuid), CSTR(pMediumName)); 825 } 677 826 } 678 827 else 679 828 { 680 RTPrintf(" Diff %d:\n", ancestorNumber); 681 RTPrintf(" UUID: %s\n", CSTR(pMediumUuid)); 682 RTPrintf(" Location: %s\n\n", CSTR(pMediumPath)); 829 if (!g_vboxrawOpts.fListMediaBrief) 830 { 831 RTPrintf(" Diff %d:\n", ancestorNumber); 832 RTPrintf(" UUID: %s\n", CSTR(pMediumUuid)); 833 RTPrintf(" Location: %s\n", CSTR(pMediumPath)); 834 } 683 835 } 684 836 CHECK_ERROR_BREAK(pChild, COMGETTER(Children)(ComSafeArrayAsOutParam(aMediumChildren))); 685 837 pChild = (aMediumChildren.size()) ? aMediumChildren[0] : NULL; 686 838 ++ancestorNumber; 839 firstIteration = 0; 687 840 } while(pChild); 688 841 } … … 720 873 721 874 if ( g_vboxrawOpts.pszVm == NULL 722 || RTStrNCmp(CSTR(pMachineUuid), g_vboxrawOpts.pszVm, MAX_ ID_LEN) == 0723 || RTStrNCmp((const char *)pMachineName.raw(), g_vboxrawOpts.pszVm, MAX_ ID_LEN) == 0)875 || RTStrNCmp(CSTR(pMachineUuid), g_vboxrawOpts.pszVm, MAX_UUID_LEN) == 0 876 || RTStrNCmp((const char *)pMachineName.raw(), g_vboxrawOpts.pszVm, MAX_UUID_LEN) == 0) 724 877 { 725 RTPrintf("------------------------------------------------------\n"); 726 RTPrintf("VM Name: \"%s\"\n", CSTR(pMachineName)); 727 RTPrintf("UUID: %s\n", CSTR(pMachineUuid)); 728 if (*pDescription.raw() != '\0') 729 RTPrintf("Description: %s\n", CSTR(pDescription)); 730 RTPrintf("Location: %s\n", CSTR(pMachineLocation)); 731 732 listMedia(pMachine); 733 734 RTPrintf("\n"); 878 if (!g_vboxrawOpts.fListMediaBrief) 879 { 880 RTPrintf("------------------------------------------------------\n"); 881 RTPrintf("VM Name: \"%s\"\n", CSTR(pMachineName)); 882 RTPrintf("UUID: %s\n", CSTR(pMachineUuid)); 883 if (*pDescription.raw() != '\0') 884 RTPrintf("Description: %s\n", CSTR(pDescription)); 885 RTPrintf("Location: %s\n", CSTR(pMachineLocation)); 886 } 887 listMedia(pMachine, RTStrDup(CSTR(pMachineName)), RTStrDup(CSTR(pMachineUuid))); 888 } 889 else 890 { 891 listMedia(pMachine, RTStrDup(CSTR(pMachineName)), RTStrDup(CSTR(pMachineUuid))); 735 892 } 736 893 } … … 766 923 } 767 924 925 uint8_t 926 parsePartitionTable(void) 927 { 928 MBR_t mbr; 929 EBR_t ebr; 930 PTH_t parTblHdr; 931 932 ASSERT(sizeof (mbr) == 512); 933 ASSERT(sizeof (ebr) == 512); 934 /* 935 * First entry describes entire disk as a single entity 936 */ 937 g_aParsedPartitionInfo[0].idxPartition = 0; 938 g_aParsedPartitionInfo[0].offPartition = 0; 939 g_aParsedPartitionInfo[0].cbPartition = VDGetSize(g_pVDisk, 0); 940 g_aParsedPartitionInfo[0].pszName = RTStrDup("EntireDisk"); 941 942 /* 943 * Currently only DOS partitioned disks are supported. Ensure this one conforms 944 */ 945 int rc = vdReadSanitizer(g_pVDisk, 0, &mbr, sizeof (mbr)); 946 if (RT_FAILURE(rc)) 947 return RTMsgErrorExitFailure("Error reading MBR block from disk\n"); 948 949 if (mbr.signature == NULL_BOOT_RECORD_SIGNATURE) 950 return RTMsgErrorExitFailure("Unprt disk (null MBR signature)\n"); 951 952 if (mbr.signature != DOS_BOOT_RECORD_SIGNATURE) 953 return RTMsgErrorExitFailure("Invalid MBR found on image with signature 0x%04hX\n", 954 mbr.signature); 955 /* 956 * Parse the four physical partition entires in the MBR (any one, and only one, can be an EBR) 957 */ 958 int ebridxPartitionInMbr = 0; 959 for (int idxPartition = 1; 960 idxPartition <= MBR_PARTITIONS_MAX; 961 idxPartition++) 962 { 963 MBRPARTITIONENTRY *pMbrPartitionEntry = 964 &g_aParsedPartitionInfo[idxPartition].partitionEntry.mbrEntry;; 965 memcpy (pMbrPartitionEntry, &mbr.partitionEntry[idxPartition - 1], sizeof (MBRPARTITIONENTRY)); 966 967 if (PARTTYPE_IS_NULL(pMbrPartitionEntry->type)) 968 continue; 969 970 if (PARTTYPE_IS_EXT(pMbrPartitionEntry->type)) 971 { 972 if (ebridxPartitionInMbr) 973 return RTMsgErrorExitFailure("Multiple EBRs found found in MBR\n"); 974 ebridxPartitionInMbr = idxPartition; 975 } 976 977 PARTITIONINFO *ppi = &g_aParsedPartitionInfo[idxPartition]; 978 979 ppi->idxPartition = idxPartition; 980 ppi->offPartition = (off_t) pMbrPartitionEntry->partitionLba * BLOCKSIZE; 981 ppi->cbPartition = (off_t) pMbrPartitionEntry->partitionBlkCnt * BLOCKSIZE; 982 ppi->fBootable = pMbrPartitionEntry->bootIndicator == 0x80; 983 (ppi->partitionType).legacy = pMbrPartitionEntry->type; 984 985 g_lastPartNbr = idxPartition; 986 987 if (PARTTYPE_IS_GPT(pMbrPartitionEntry->type)) 988 { 989 g_fGPT = true; 990 break; 991 } 992 } 993 994 if (g_fGPT) 995 { 996 g_lastPartNbr = 2; /* from the 'protective MBR' */ 997 998 rc = vdReadSanitizer(g_pVDisk, LBA(1), &parTblHdr, sizeof (parTblHdr)); 999 if (RT_FAILURE(rc)) 1000 return RTMsgErrorExitFailure("Error reading Partition Table Header (LBA 1) from disk\n"); 1001 1002 uint8_t *pTblBuf = (uint8_t *)RTMemAlloc(GPT_PTABLE_SIZE); 1003 1004 RTPrintf( "Virtual disk image:\n\n"); 1005 RTPrintf(" Path: %s\n", g_pszBaseImagePath); 1006 if (g_pvDiskUuid) 1007 RTPrintf(" UUID: %s\n\n", g_pvDiskUuid); 1008 1009 if (g_vboxrawOpts.fVerbose) 1010 { 1011 RTPrintf(" GPT Partition Table Header:\n\n"); 1012 if (RTStrCmp((const char *)&parTblHdr.signature, "EFI PART") == 0) 1013 RTPrintf( 1014 " Signature \"EFI PART\" (0x%llx)\n", parTblHdr.signature); 1015 else 1016 RTPrintf( 1017 " Signature: 0x%llx\n", parTblHdr.signature); 1018 RTPrintf(" Revision: %-8.8x\n", parTblHdr.revision); 1019 RTPrintf(" Current LBA: %lld\n", parTblHdr.headerLba); 1020 RTPrintf(" Backup LBA: %lld\n", parTblHdr.backupLba); 1021 RTPrintf(" Partition entries LBA: %lld\n", parTblHdr.partitionEntriesLba); 1022 RTPrintf(" # of partitions: %d\n", parTblHdr.cPartitionEntries); 1023 RTPrintf(" size of entry: %d\n\n", parTblHdr.cbPartitionEntry); 1024 } 1025 1026 if (!pTblBuf) 1027 return RTMsgErrorExitFailure("Out of memory\n"); 1028 1029 rc = vdReadSanitizer(g_pVDisk, LBA(2), pTblBuf, GPT_PTABLE_SIZE); 1030 if (RT_FAILURE(rc)) 1031 return RTMsgErrorExitFailure("Error reading Partition Table blocks from disk\n"); 1032 1033 uint32_t cEntries = parTblHdr.cPartitionEntries; 1034 uint32_t cbEntry = parTblHdr.cbPartitionEntry; 1035 if (cEntries * cbEntry > GPT_PTABLE_SIZE) 1036 { 1037 RTPrintf("Partition entries exceed GPT table read from disk (pruning!)\n"); 1038 while (cEntries * cbEntry > GPT_PTABLE_SIZE && cEntries > 0) 1039 --cEntries; 1040 } 1041 uint8_t *pEntryRaw = pTblBuf; 1042 for (uint32_t i = 0; i < cEntries; i++) 1043 { 1044 GPTPARTITIONENTRY *pEntry = (GPTPARTITIONENTRY *)pEntryRaw; 1045 PARTITIONINFO *ppi = &g_aParsedPartitionInfo[g_lastPartNbr]; 1046 memcpy(&(ppi->partitionEntry).gptEntry, pEntry, sizeof(GPTPARTITIONENTRY)); 1047 uint64_t firstLba = pEntry->firstLba; 1048 uint64_t lastLba = pEntry->lastLba; 1049 if (!firstLba) 1050 break; 1051 ppi->offPartition = firstLba * BLOCKSIZE; 1052 ppi->cbPartition = (lastLba - firstLba) * BLOCKSIZE; 1053 ppi->fBootable = pEntry->attrFlags & (1 << GPT_LEGACY_BIOS_BOOTABLE); 1054 ppi->partitionType.gptGuidTypeSpecifier = pEntry->partitionTypeGuid; 1055 size_t cwName = sizeof (pEntry->partitionName) / 2; 1056 char *pszTmp = NULL, **pPszTmp = &pszTmp; 1057 RTUtf16LittleToUtf8Ex((PRTUTF16)pEntry->partitionName, RTSTR_MAX, &ppi->pszName, cwName, NULL); 1058 ppi->idxPartition = g_lastPartNbr++; 1059 pEntryRaw += cbEntry; 1060 } 1061 return PARTITION_TABLE_GPT; 1062 } 1063 1064 /* 1065 * Starting with EBR located in MBR, walk EBR chain to parse the logical partition entries 1066 */ 1067 if (ebridxPartitionInMbr) 1068 { 1069 uint32_t firstEbrLba 1070 = g_aParsedPartitionInfo[ebridxPartitionInMbr].partitionEntry.mbrEntry.partitionLba; 1071 off_t firstEbrOffset = (off_t)firstEbrLba * BLOCKSIZE; 1072 off_t chainedEbrOffset = 0; 1073 1074 if (!firstEbrLba) 1075 return RTMsgErrorExitFailure("Inconsistency for logical partition start. Aborting\n"); 1076 1077 for (int idxPartition = 5; 1078 idxPartition <= VBOXRAW_PARTITION_MAX; 1079 idxPartition++) 1080 { 1081 1082 off_t currentEbrOffset = firstEbrOffset + chainedEbrOffset; 1083 vdReadSanitizer(g_pVDisk, currentEbrOffset, &ebr, sizeof (ebr)); 1084 1085 if (ebr.signature != DOS_BOOT_RECORD_SIGNATURE) 1086 return RTMsgErrorExitFailure("Invalid EBR found on image with signature 0x%04hX\n", 1087 ebr.signature); 1088 1089 MBRPARTITIONENTRY *pEbrPartitionEntry = 1090 &g_aParsedPartitionInfo[idxPartition].partitionEntry.mbrEntry; /* EBR entry struct same as MBR */ 1091 memcpy(pEbrPartitionEntry, &ebr.partitionEntry, sizeof (MBRPARTITIONENTRY)); 1092 1093 if (pEbrPartitionEntry->type == NULL_BOOT_RECORD_SIGNATURE) 1094 return RTMsgErrorExitFailure("Logical partition with type 0 encountered"); 1095 1096 if (!pEbrPartitionEntry->partitionLba) 1097 return RTMsgErrorExitFailure("Logical partition invalid partition start offset (LBA) encountered"); 1098 1099 PARTITIONINFO *ppi = &g_aParsedPartitionInfo[idxPartition]; 1100 ppi->idxPartition = idxPartition; 1101 ppi->offPartition = currentEbrOffset + (off_t)pEbrPartitionEntry->partitionLba * BLOCKSIZE; 1102 ppi->cbPartition = (off_t)pEbrPartitionEntry->partitionBlkCnt * BLOCKSIZE; 1103 ppi->fBootable = pEbrPartitionEntry->bootIndicator == 0x80; 1104 ppi->partitionType.legacy = pEbrPartitionEntry->type; 1105 1106 g_lastPartNbr = idxPartition; 1107 1108 if (ebr.chainingPartitionEntry.type == 0) /* end of chain */ 1109 break; 1110 1111 if (!PARTTYPE_IS_EXT(ebr.chainingPartitionEntry.type)) 1112 return RTMsgErrorExitFailure("Logical partition chain broken"); 1113 1114 chainedEbrOffset = ebr.chainingPartitionEntry.partitionLba * BLOCKSIZE; 1115 } 1116 } 1117 return PARTITION_TABLE_MBR; 1118 } 1119 1120 const char *getClassicPartitionDesc(uint8_t type) 1121 { 1122 for (uint32_t i = 0; i < sizeof (g_partitionDescTable) / sizeof (struct PartitionDesc); i++) 1123 { 1124 if (g_partitionDescTable[i].type == type) 1125 return g_partitionDescTable[i].desc; 1126 } 1127 return "????"; 1128 } 1129 1130 void 1131 displayGptPartitionTable(void) 1132 { 1133 1134 void *colBoot = NULL; 1135 1136 SELFSIZINGTABLE tbl(2); 1137 1138 /* Note: Omitting partition name column because type/UUID seems suffcient */ 1139 void *colPartNbr = tbl.addCol("#", "%3d", 1); 1140 1141 /* If none of the partitions supports legacy BIOS boot, don't show column */ 1142 for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++) 1143 if (g_aParsedPartitionInfo[idxPartition].fBootable) { 1144 colBoot = tbl.addCol("Boot", "%c ", 1); 1145 break; 1146 } 1147 1148 void *colStart = tbl.addCol("Start", "%lld", 1); 1149 void *colSectors = tbl.addCol("Sectors", "%lld", -1, 2); 1150 void *colSize = tbl.addCol("Size", "%d.%d%c", 1); 1151 void *colOffset = tbl.addCol("Offset", "%lld", 1); 1152 /* Need to see how other OSes with GPT schemes use this field. Seems like type covers it 1153 void *colName = tbl.addCol("Name", "%s", -1); */ 1154 void *colType = tbl.addCol("Type", "%s", -1, 2); 1155 1156 for (int idxPartition = 2; idxPartition <= g_lastPartNbr; idxPartition++) 1157 { 1158 PARTITIONINFO *ppi = &g_aParsedPartitionInfo[idxPartition]; 1159 if (ppi->idxPartition) 1160 { 1161 uint8_t exp = log2((double)ppi->cbPartition); 1162 char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10]; 1163 1164 /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */ 1165 double cbPartitionScaled = (double)ppi->cbPartition / pow(2, (double)(((uint8_t)(exp / 10)) * 10)); 1166 uint8_t cbPartitionIntPart = cbPartitionScaled; 1167 uint8_t cbPartitionFracPart = (cbPartitionScaled - (double)cbPartitionIntPart) * 10; 1168 1169 char abGuid[GUID_STRING_LENGTH * 2]; 1170 RTStrPrintf(abGuid, sizeof(abGuid), "%RTuuid", &ppi->partitionType.gptGuidTypeSpecifier); 1171 1172 char *pszPartitionTypeDesc = NULL; 1173 for (uint32_t i = 0; i < sizeof(g_gptPartitionTypes) / sizeof(GPTPARTITIONTYPE); i++) 1174 if (RTStrNICmp(abGuid, g_gptPartitionTypes[i].gptPartitionUuid, GUID_STRING_LENGTH) == 0) 1175 { 1176 pszPartitionTypeDesc = (char *)g_gptPartitionTypes[i].gptPartitionTypeDesc; 1177 break; 1178 } 1179 1180 if (!pszPartitionTypeDesc) 1181 RTPrintf("Couldn't find GPT partitiontype for GUID: %s\n", abGuid); 1182 1183 void *row = tbl.addRow(); 1184 tbl.setCell(row, colPartNbr, idxPartition - 1); 1185 if (colBoot) 1186 tbl.setCell(row, colBoot, ppi->fBootable ? '*' : ' '); 1187 tbl.setCell(row, colStart, ppi->offPartition / BLOCKSIZE); 1188 tbl.setCell(row, colSectors, ppi->cbPartition / BLOCKSIZE); 1189 tbl.setCell(row, colSize, cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude); 1190 tbl.setCell(row, colOffset, ppi->offPartition); 1191 /* tbl.setCell(row, colName, ppi->pszName); ... see comment for column definition */ 1192 tbl.setCell(row, colType, SAFENULL(pszPartitionTypeDesc)); 1193 } 1194 } 1195 tbl.displayTable(); 1196 RTPrintf ("\n"); 1197 } 1198 1199 void 1200 displayLegacyPartitionTable(void) 1201 { 1202 /* 1203 * Partition table is most readable and concise when headers and columns 1204 * are adapted to the actual data, to avoid insufficient or excessive whitespace. 1205 */ 1206 RTPrintf( "Virtual disk image:\n\n"); 1207 RTPrintf(" Path: %s\n", g_pszBaseImagePath); 1208 if (g_pvDiskUuid) 1209 RTPrintf(" UUID: %s\n\n", g_pvDiskUuid); 1210 1211 SELFSIZINGTABLE tbl(2); 1212 1213 void *colPartition = tbl.addCol("Partition", "%s%d", -1); 1214 void *colBoot = tbl.addCol("Boot", "%c ", 1); 1215 void *colStart = tbl.addCol("Start", "%lld", 1); 1216 void *colSectors = tbl.addCol("Sectors", "%lld", -1, 2); 1217 void *colSize = tbl.addCol("Size", "%d.%d%c", 1); 1218 void *colOffset = tbl.addCol("Offset", "%lld", 1); 1219 void *colId = tbl.addCol("Id", "%2x", 1); 1220 void *colType = tbl.addCol("Type", "%s", -1, 2); 1221 1222 for (int idxPartition = 1; idxPartition <= g_lastPartNbr; idxPartition++) 1223 { 1224 PARTITIONINFO *p = &g_aParsedPartitionInfo[idxPartition]; 1225 if (p->idxPartition) 1226 { 1227 uint8_t exp = log2((double)p->cbPartition); 1228 char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10]; 1229 1230 /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */ 1231 double cbPartitionScaled = (double)p->cbPartition / pow(2, (double)(((uint8_t)(exp / 10)) * 10)); 1232 uint8_t cbPartitionIntPart = cbPartitionScaled; 1233 uint8_t cbPartitionFracPart = (cbPartitionScaled - (double)cbPartitionIntPart) * 10; 1234 1235 void *row = tbl.addRow(); 1236 1237 tbl.setCell(row, colPartition, g_pszBaseImageName, idxPartition); 1238 tbl.setCell(row, colBoot, p->fBootable ? '*' : ' '); 1239 tbl.setCell(row, colStart, p->offPartition / BLOCKSIZE); 1240 tbl.setCell(row, colSectors, p->cbPartition / BLOCKSIZE); 1241 tbl.setCell(row, colSize, cbPartitionIntPart, cbPartitionFracPart, scaledMagnitude); 1242 tbl.setCell(row, colOffset, p->offPartition); 1243 tbl.setCell(row, colId, p->partitionType.legacy); 1244 tbl.setCell(row, colType, getClassicPartitionDesc((p->partitionType).legacy)); 1245 } 1246 } 1247 tbl.displayTable(); 1248 RTPrintf ("\n"); 1249 } 1250 768 1251 int 769 1252 main(int argc, char **argv) … … 772 1255 int rc = RTR3InitExe(argc, &argv, 0); 773 1256 if (RT_FAILURE(rc)) 774 return RTMsgErrorExitFailure(" vboxraw: ERROR:RTR3InitExe failed, rc=%Rrc\n", rc);1257 return RTMsgErrorExitFailure("RTR3InitExe failed, rc=%Rrc\n", rc); 775 1258 776 1259 rc = VDInit(); 777 1260 if (RT_FAILURE(rc)) 778 return RTMsgErrorExitFailure(" vboxraw: ERROR:VDInit failed, rc=%Rrc\n", rc);1261 return RTMsgErrorExitFailure("VDInit failed, rc=%Rrc\n", rc); 779 1262 780 1263 memset(&g_vboxrawOps, 0, sizeof(g_vboxrawOps)); … … 786 1269 g_vboxrawOps.readdir = vboxrawOp_readdir; 787 1270 g_vboxrawOps.readlink = vboxrawOp_readlink; 1271 788 1272 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 789 790 1273 memset(&g_vboxrawOpts, 0, sizeof(g_vboxrawOpts)); 791 1274 792 1275 rc = fuse_opt_parse(&args, &g_vboxrawOpts, vboxrawOptDefs, vboxrawOptHandler); 1276 793 1277 if (g_vboxrawOpts.fAllowRoot) 794 1278 fuse_opt_add_arg(&args, "-oallow_root"); 795 1279 796 1280 if (rc == -1) 797 return RTMsgErrorExitFailure("vboxraw: ERROR: Couldn't parse fuse options, rc=%Rrc\n", rc); 1281 return RTMsgErrorExitFailure("Couldn't parse fuse options, rc=%Rrc\n", rc); 1282 if (g_vboxrawOpts.fBriefUsage) 1283 { 1284 briefUsage(); 1285 return 0; 1286 } 798 1287 799 1288 /* … … 826 1315 hrc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam()); 827 1316 if (FAILED(hrc)) 828 1317 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get IVirtualBox object! (hrc=%Rhrc)", hrc); 829 1318 830 1319 if (g_vboxrawOpts.fVerbose) 831 1320 RTPrintf("vboxraw: VirtualBox XPCOM object created\n"); 832 1321 833 if (g_vboxrawOpts.fList) 834 { 835 listVMs(pVirtualBox); 836 return 0; 837 } 1322 if (g_vboxrawOpts.fListMedia || g_vboxrawOpts.fListMediaBrief) 1323 { 1324 listVMs(pVirtualBox); 1325 return 0; 1326 } 1327 838 1328 839 1329 if (g_vboxrawOpts.pszImage == NULL) 840 1330 { 841 RTMsgErrorExitFailure("vboxraw: ERROR: " 842 "Must provide at at least --list or --image option\n"); 843 return 0; 1331 RTMsgErrorExitFailure("To list partitions, must also specify --i or --image option\n"); 1332 return 0; 844 1333 } 845 1334 ComPtr<IMedium> pBaseImageMedium = NULL; 846 1335 char *pszFormat; 847 1336 VDTYPE enmType; 848 849 1337 searchForBaseImage(pVirtualBox, g_vboxrawOpts.pszImage, &pBaseImageMedium); 850 1338 if (pBaseImageMedium == NULL) … … 860 1348 g_pszBaseImagePath = RTStrDup(g_vboxrawOpts.pszImage); 861 1349 if (g_pszBaseImagePath == NULL) 862 return RTMsgErrorExitFailure(" vboxraw:out of memory\n");1350 return RTMsgErrorExitFailure("out of memory\n"); 863 1351 864 1352 if (access(g_pszBaseImagePath, F_OK) < 0) 865 return RTMsgErrorExitFailure("vboxraw: ERROR: " 866 "Virtual disk image not found: \"%s\"\n", g_pszBaseImagePath); 1353 return RTMsgErrorExitFailure("Virtual disk image not found: \"%s\"\n", g_pszBaseImagePath); 867 1354 868 1355 if (access(g_pszBaseImagePath, R_OK) < 0) 869 return RTMsgErrorExitFailure( "vboxraw: ERROR: "1356 return RTMsgErrorExitFailure( 870 1357 "Virtual disk image not readable: \"%s\"\n", g_pszBaseImagePath); 871 1358 872 if ( 873 return RTMsgErrorExitFailure( "vboxraw: ERROR: "1359 if (g_vboxrawOpts.fRW && access(g_vboxrawOpts.pszImage, W_OK) < 0) 1360 return RTMsgErrorExitFailure( 874 1361 "Virtual disk image not writeable: \"%s\"\n", g_pszBaseImagePath); 875 1362 rc = RTPathSplit(g_pszBaseImagePath, &g_u.split, sizeof(g_u), 0); 876 1363 877 1364 if (RT_FAILURE(rc)) 878 return RTMsgErrorExitFailure( "vboxraw: "1365 return RTMsgErrorExitFailure( 879 1366 "RTPathSplit failed on '%s': %Rrc", g_pszBaseImagePath); 880 1367 881 1368 if (!(g_u.split.fProps & RTPATH_PROP_FILENAME)) 882 return RTMsgErrorExitFailure( "vboxraw: "1369 return RTMsgErrorExitFailure( 883 1370 "RTPATH_PROP_FILENAME not set for: '%s'", g_pszBaseImagePath); 884 1371 … … 896 1383 g_pszBaseImagePath, &pszFormat, &enmType); 897 1384 if (RT_FAILURE(rc)) 898 return RTMsgErrorExitFailure(" vboxraw: ERROR:VDGetFormat(%s,) "1385 return RTMsgErrorExitFailure("VDGetFormat(%s,) " 899 1386 "failed, rc=%Rrc\n", g_pszBaseImagePath, rc); 900 1387 … … 907 1394 { 908 1395 VDClose(g_pVDisk, false /* fDeletes */); 909 return RTMsgErrorExitFailure(" vboxraw: ERROR:VDCreate(,%s,%s,,,) failed,"1396 return RTMsgErrorExitFailure("VDCreate(,%s,%s,,,) failed," 910 1397 " rc=%Rrc\n", pszFormat, g_pszBaseImagePath, rc); 911 1398 } 912 1399 } 913 1400 else 914 return RTMsgErrorExitFailure("vboxraw: ERROR: VDCreate failed, rc=%Rrc\n", rc); 915 } 1401 return RTMsgErrorExitFailure("VDCreate failed, rc=%Rrc\n", rc); 1402 } 1403 } else { 1404 Bstr pMediumUuid; 1405 CHECK_ERROR(pBaseImageMedium, COMGETTER(Id)(pMediumUuid.asOutParam())); 1406 g_pvDiskUuid = RTStrDup((char *)CSTR(pMediumUuid)); 916 1407 } 917 1408 918 1409 if (g_pVDisk == NULL) 919 1410 { 1411 920 1412 com::SafeIfaceArray<IMedium> aMediumChildren; 921 1413 ComPtr<IMedium> pChild = pBaseImageMedium; … … 937 1429 g_pszBaseImagePath = RTStrDup(CSTR(pMediumPath)); 938 1430 if (g_pszBaseImageName == NULL) 939 return RTMsgErrorExitFailure(" vboxraw:out of memory\n");1431 return RTMsgErrorExitFailure("out of memory\n"); 940 1432 941 1433 if (g_pszBaseImagePath == NULL) 942 return RTMsgErrorExitFailure(" vboxraw:out of memory\n");1434 return RTMsgErrorExitFailure("out of memory\n"); 943 1435 /* 944 1436 * Create HDD container to open base image and differencing images into … … 947 1439 g_pszBaseImagePath, &pszFormat, &enmType); 948 1440 if (RT_FAILURE(rc)) 949 return RTMsgErrorExitFailure(" vboxraw:VDGetFormat(,,%s,,) "1441 return RTMsgErrorExitFailure("VDGetFormat(,,%s,,) " 950 1442 "failed (during HDD container creation), rc=%Rrc\n", g_pszBaseImagePath, rc); 951 1443 if (g_vboxrawOpts.fVerbose) 952 RTPrintf(" vboxraw:Creating container for base image of format %s\n", pszFormat);1444 RTPrintf("Creating container for base image of format %s\n", pszFormat); 953 1445 /** @todo Remove I/O CB's and crit sect. when VDRead()/VDWrite() are made threadsafe */ 954 1446 rc = RTCritSectInit(&g_vdioLock); … … 963 1455 } 964 1456 else 965 return RTMsgErrorExitFailure(" vboxraw:ERROR: Failed to create critsects "1457 return RTMsgErrorExitFailure("ERROR: Failed to create critsects " 966 1458 "for virtual disk I/O, rc=%Rrc\n", rc); 967 1459 … … 969 1461 rc = VDCreate(g_pVdIfs, enmType, &g_pVDisk); 970 1462 if (NS_FAILED(rc)) 971 return RTMsgErrorExitFailure(" vboxraw:ERROR: Couldn't create virtual disk container\n");1463 return RTMsgErrorExitFailure("ERROR: Couldn't create virtual disk container\n"); 972 1464 } 973 1465 /** @todo (end of to do section) */ … … 990 1482 { 991 1483 VDClose(g_pVDisk, false /* fDeletes */); 992 return RTMsgErrorExitFailure(" vboxraw:VDOpen(,,%s,,) failed, rc=%Rrc\n",1484 return RTMsgErrorExitFailure("VDOpen(,,%s,,) failed, rc=%Rrc\n", 993 1485 g_pszBaseImagePath, rc); 994 1486 } … … 1010 1502 g_cReaders = VDIsReadOnly(g_pVDisk) ? INT32_MAX / 2 : 0; 1011 1503 g_cWriters = 0; 1012 g_cbPrimary = VDGetSize(g_pVDisk, 0 /* base */); 1504 g_cbEntireVDisk = VDGetSize(g_pVDisk, 0 /* base */); 1505 1506 if (g_vboxrawOpts.fListParts) 1507 { 1508 if (g_pVDisk == NULL) 1509 return RTMsgErrorExitFailure("No valid --image to list partitions from\n"); 1510 1511 RTPrintf("\n"); 1512 1513 rc = parsePartitionTable(); 1514 switch(rc) 1515 { 1516 case PARTITION_TABLE_MBR: 1517 displayLegacyPartitionTable(); 1518 break; 1519 case PARTITION_TABLE_GPT: 1520 displayGptPartitionTable(); 1521 break; 1522 default: 1523 return rc; 1524 } 1525 return 0; 1526 } 1527 if (g_vboxrawOpts.idxPartition >= 0) 1528 { 1529 if (g_vboxrawOpts.offset) 1530 return RTMsgErrorExitFailure("--offset and --partition are mutually exclusive options\n"); 1531 1532 if (g_vboxrawOpts.size) 1533 return RTMsgErrorExitFailure("--size and --partition are mutually exclusive options\n"); 1534 1535 /* 1536 * --partition option specified. That will set the global offset and limit 1537 * honored by the disk read and write sanitizers to constrain operations 1538 * to within the specified partion based on an initial parsing of the MBR 1539 */ 1540 rc = parsePartitionTable(); 1541 if (rc < 0) 1542 return RTMsgErrorExitFailure("Error parsing disk MBR/Partition table\n"); 1543 int partNbr = g_vboxrawOpts.idxPartition; 1544 1545 if (partNbr < 0 || partNbr > g_lastPartNbr) 1546 return RTMsgErrorExitFailure("Non-valid partition number specified\n"); 1547 1548 if (partNbr == 0) 1549 { 1550 g_vDiskOffset = 0; 1551 g_vDiskSize = VDGetSize(g_pVDisk, 0); 1552 if (g_vboxrawOpts.fVerbose) 1553 RTPrintf("Partition 0 specified - Whole disk will be accessible\n"); 1554 } else { 1555 for (int i = 0; i < g_lastPartNbr; i++) 1556 { 1557 /* If GPT, display vboxraw's representation of partition table starts at partition 2 1558 * but the table is displayed calling it partition 1, because the protective MBR 1559 * record is relatively pointless to display or reference in this context */ 1560 1561 if (g_aParsedPartitionInfo[i].idxPartition == partNbr + g_fGPT ? 1 : 0) 1562 { 1563 g_vDiskOffset = g_aParsedPartitionInfo[i].offPartition; 1564 g_vDiskSize = g_vDiskOffset + g_aParsedPartitionInfo[i].cbPartition; 1565 if (g_vboxrawOpts.fVerbose) 1566 RTPrintf("Partition %d specified. Only sectors %llu to %llu of disk will be accessible\n", 1567 g_vboxrawOpts.idxPartition, g_vDiskOffset / BLOCKSIZE, g_vDiskSize / BLOCKSIZE); 1568 } 1569 } 1570 } 1571 } else { 1572 if (g_vboxrawOpts.offset) { 1573 if (g_vboxrawOpts.offset < 0 || g_vboxrawOpts.offset + g_vboxrawOpts.size > g_cbEntireVDisk) 1574 return RTMsgErrorExitFailure("User specified offset out of range of virtual disk\n"); 1575 1576 if (g_vboxrawOpts.fVerbose) 1577 RTPrintf("Setting r/w bias (offset) to user requested value for sector %llu\n", g_vDiskOffset / BLOCKSIZE); 1578 1579 g_vDiskOffset = g_vboxrawOpts.offset; 1580 } 1581 if (g_vboxrawOpts.size) { 1582 if (g_vboxrawOpts.size < 0 || g_vboxrawOpts.offset + g_vboxrawOpts.size > g_cbEntireVDisk) 1583 return RTMsgErrorExitFailure("User specified size out of range of virtual disk\n"); 1584 1585 if (g_vboxrawOpts.fVerbose) 1586 RTPrintf("Setting r/w size limit to user requested value %llu\n", g_vDiskSize / BLOCKSIZE); 1587 1588 g_vDiskSize = g_vboxrawOpts.size; 1589 } 1590 } 1591 if (g_vDiskSize == 0) 1592 g_vDiskSize = g_cbEntireVDisk - g_vDiskOffset; 1013 1593 1014 1594 /*
Note:
See TracChangeset
for help on using the changeset viewer.