* Added assigning an UUID to the image written; you can either pass one via the

new '-u' option, or let it generate one automatically (by building a hash over
  the full path of the image).
* This is allows you to use our images in VirtualBox without having to readd
  the hard drive with every rebuild.
* Enlarged the description section to 1024 bytes - this also prevents VirtualBox
  from writing data beyond the description size.
* Added '-d' option to just dump info about an existing vmdk image file (only
  monolithic mode is supported, though).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28093 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-10-14 17:14:29 +00:00
parent 5604c88c81
commit 700de23e38
2 changed files with 175 additions and 19 deletions

View File

@ -2,16 +2,18 @@
* Copyright 2007, Marcus Overhagen. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "vmdkimage.h"
@ -22,25 +24,130 @@ print_usage()
printf("\n");
printf("vmdkimage\n");
printf("\n");
printf("usage: vmdkimage -i <imagesize> -h <headersize> [-c] [-H] [-f] "
"<file>\n");
printf("usage: vmdkimage -i <imagesize> -h <headersize> [-c] [-H] "
"[-u <uuid>] [-f] <file>\n");
printf(" or: vmdkimage -d <file>\n");
printf(" -d, --dump dumps info for the image file\n");
printf(" -i, --imagesize size of raw partition image file\n");
printf(" -h, --headersize size of the vmdk header to write\n");
printf(" -f, --file the raw partition image file\n");
printf(" -u, --uuid UUID for the image instead of a computed "
"one\n");
printf(" -c, --clear-image set the image content to zero\n");
printf(" -H, --header-only write only the header\n");
exit(EXIT_FAILURE);
}
static void
dump_image_info(const char *filename)
{
int image = open(filename, O_RDONLY);
if (image < 0) {
fprintf(stderr, "Error: couldn't open file %s (%s)\n", filename,
strerror(errno));
exit(EXIT_FAILURE);
}
SparseExtentHeader header;
if (read(image, &header, 512) != 512) {
fprintf(stderr, "Error: couldn't read header: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (header.magicNumber != SPARSE_MAGICNUMBER) {
fprintf(stderr, "Error: invalid header magic.\n");
exit(EXIT_FAILURE);
}
printf("--------------- Header ---------------\n");
printf(" version: %d\n", (int)header.version);
printf(" flags: %d\n", (int)header.flags);
printf(" capacity: %d\n", (int)header.capacity);
printf(" grainSize: %lld\n", header.grainSize);
printf(" descriptorOffset: %lld\n", header.descriptorOffset);
printf(" descriptorSize: %lld\n", header.descriptorSize);
printf(" numGTEsPerGT: %u\n", (unsigned int)header.numGTEsPerGT);
printf(" rgdOffset: %lld\n", header.rgdOffset);
printf(" gdOffset: %lld\n", header.gdOffset);
printf(" overHead: %lld\n", header.overHead);
printf(" uncleanShutdown: %s\n",
header.uncleanShutdown ? "yes" : "no");
printf(" singleEndLineChar: '%c'\n", header.singleEndLineChar);
printf(" nonEndLineChar: '%c'\n", header.nonEndLineChar);
printf(" doubleEndLineChar1: '%c'\n", header.doubleEndLineChar1);
printf(" doubleEndLineChar2: '%c'\n", header.doubleEndLineChar2);
if (header.descriptorOffset != 0) {
printf("\n--------------- Descriptor ---------------\n");
size_t descriptorSize = header.descriptorSize * 512 * 2;
char *descriptor = (char *)malloc(descriptorSize);
if (descriptor == NULL) {
fprintf(stderr, "Error: cannot allocate descriptor size %u.\n",
(unsigned int)descriptorSize);
exit(EXIT_FAILURE);
}
if (pread(image, descriptor, descriptorSize,
header.descriptorOffset * 512) != (ssize_t)descriptorSize) {
fprintf(stderr, "Error: couldn't read header: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
puts(descriptor);
putchar('\n');
free(descriptor);
}
close(image);
}
static uint64
hash_string(const char *string)
{
uint64 hash = 0;
char c;
while ((c = *string++) != 0) {
hash = c + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
static bool
is_valid_uuid(const char *uuid)
{
const char *kHex = "0123456789abcdef";
for (int i = 0; i < 36; i++) {
if (!uuid[i])
return false;
if (i == 8 || i == 13 || i == 18 || i == 23) {
if (uuid[i] != '-')
return false;
continue;
}
if (strchr(kHex, uuid[i]) == NULL)
return false;
}
return uuid[36] == '\0';
}
int
main(int argc, char *argv[])
{
uint64 headersize = 0;
uint64 imagesize = 0;
const char *file = NULL;
const char *uuid = NULL;
bool headerOnly = false;
bool clearImage = false;
bool dumpOnly = false;
if (sizeof(SparseExtentHeader) != 512) {
fprintf(stderr, "compilation error: struct size is %u byte\n",
@ -50,22 +157,27 @@ main(int argc, char *argv[])
while (1) {
int c;
static struct option long_options[] =
{
static struct option long_options[] = {
{"dump", no_argument, 0, 'd'},
{"headersize", required_argument, 0, 'h'},
{"imagesize", required_argument, 0, 'i'},
{"file", required_argument, 0, 'f'},
{"uuid", required_argument, 0, 'u'},
{"clear-image", no_argument, 0, 'c'},
{"header-only", no_argument, 0, 'H'},
{0, 0, 0, 0}
};
opterr = 0; /* don't print errors */
c = getopt_long(argc, argv, "h:i:cHf:", long_options, NULL);
c = getopt_long(argc, argv, "dh:i:u:cHf:", long_options, NULL);
if (c == -1)
break;
switch (c) {
case 'd':
dumpOnly = true;
break;
case 'h':
headersize = strtoull(optarg, NULL, 10);
if (strchr(optarg, 'G') || strchr(optarg, 'g'))
@ -86,6 +198,15 @@ main(int argc, char *argv[])
imagesize *= 1024;
break;
case 'u':
uuid = optarg;
if (!is_valid_uuid(uuid)) {
fprintf(stderr, "Error: invalid UUID given (use "
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format only).\n");
exit(EXIT_FAILURE);
}
break;
case 'f':
file = optarg;
break;
@ -106,10 +227,15 @@ main(int argc, char *argv[])
if (file == NULL && optind == argc - 1)
file = argv[optind];
if (dumpOnly && file != NULL) {
dump_image_info(file);
return 0;
}
if (!headersize || !imagesize || !file)
print_usage();
char desc[512];
char desc[1024];
SparseExtentHeader header;
if (headersize < sizeof(desc) + sizeof(header)) {
@ -170,7 +296,7 @@ main(int argc, char *argv[])
header.capacity = 0;
header.grainSize = 16;
header.descriptorOffset = 1;
header.descriptorSize = sizeof(desc) / 512;
header.descriptorSize = (sizeof(desc) + 511) / 512;
header.numGTEsPerGT = 512;
header.rgdOffset = 0;
header.gdOffset = 0;
@ -181,6 +307,29 @@ main(int argc, char *argv[])
header.doubleEndLineChar1 = '\r';
header.doubleEndLineChar2 = '\n';
// Generate UUID for the image by hashing its full path
uint64 uuid1 = 0, uuid2 = 0, uuid3 = 0, uuid4 = 0, uuid5 = 0;
if (uuid == NULL) {
char fullPath[PATH_MAX + 1];
strcpy(fullPath, "Haiku");
if (realpath(file, fullPath + 5) == NULL)
strncpy(fullPath, file, sizeof(fullPath));
for (size_t i = strlen(fullPath); i < sizeof(fullPath) - 1; i++) {
// fill rest with some numbers
fullPath[i] = i % 10 + '0';
}
fullPath[sizeof(fullPath) - 1] = '\0';
uuid1 = hash_string(fullPath);
uuid2 = hash_string(fullPath) + 5;
uuid3 = hash_string(fullPath) + 13;
uuid4 = hash_string(fullPath) + 19;
uuid5 = hash_string(fullPath) + 29;
}
// Create embedded descriptor
strcat(desc,
"# Disk Descriptor File\n"
"version=1\n"
@ -201,19 +350,27 @@ main(int argc, char *argv[])
"ddb.geometry.cylinders = \"%llu\"\n",
sectors, heads, cylinders);
if (uuid == NULL) {
sprintf(desc + strlen(desc),
"ddb.uuid.image=\"%08llx-%04llx-%04llx-%04llx-%012llx\"\n",
uuid1 & 0xffffffff, uuid2 & 0xffff, uuid3 & 0xffff, uuid4 & 0xffff,
uuid5 & 0xffffffffffffLL);
} else
sprintf(desc + strlen(desc), "ddb.uuid.image=\"%s\"\n", uuid);
int fd = open(file, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
fprintf(stderr, "Error: couldn't open file %s (%s)\n", file,
strerror(errno));
exit(EXIT_FAILURE);
}
if (sizeof(header) != write(fd, &header, sizeof(header)))
if (write(fd, &header, sizeof(header)) != sizeof(header))
goto write_err;
if (sizeof(desc) != write(fd, desc, sizeof(desc)))
if (write(fd, desc, sizeof(desc)) != sizeof(desc))
goto write_err;
if (headersize - 1 != (uint64)lseek(fd, headersize - 1, SEEK_SET))
if ((uint64)lseek(fd, headersize - 1, SEEK_SET) != headersize - 1)
goto write_err;
if (1 != write(fd, "", 1))

View File

@ -6,15 +6,14 @@
#define _VMDKIMAGE_H
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef uint64 SectorType;
typedef uint8 Bool;
struct SparseExtentHeader
{
struct SparseExtentHeader {
uint32 magicNumber;
uint32 version;
uint32 flags;
@ -36,4 +35,4 @@ struct SparseExtentHeader
#define SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
#endif
#endif // _VMDKIMAGE_H