From 5bb2da190bc6d5a36952315dd48a00709f88c3c2 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Fri, 25 Sep 2009 14:20:13 +0100 Subject: [PATCH] Re-label image file backing stores Use virStorageFileGetMetadata() to find any backing stores for images and re-label them Without this, qemu cannot access qcow2 backing files, see: https://bugzilla.redhat.com/497131 * src/security/security_selinux.c: re-label backing store files in SELinuxSetSecurityImageLabel() (cherry picked from commit fe627697a3830cd2db0efcc201d8caa9e171263d) Includes the following commits: util.h needs libvirt.h for virConnectPtr Seems standard to include internal.h in order to pull in libvirt.h * src/util/util.h: include internal.h (cherry picked from commit 25e2857c219e7fb91412746f7919931552c4e07a) Move file format enum to libvirt_util Rename virStorageVolFormatFileSystem to virStorageFileFormat and move to src/util/storage_file.[ch] * src/Makefile.am: add src/util/storage_file.[ch] * src/conf/storage_conf.[ch]: move enum from here ... * src/util/storage_file.[ch]: .. to here * src/libvirt_private.syms: update To/FromString exports * src/storage/storage_backend.c, src/storage/storage_backend_fs.c, src/vbox/vbox_tmpl.c: update for above changes (cherry picked from commit 00fd3ff49bb1e4578756a32a812fdbf5ee335d8c) Split virStorageGetMetadataFromFD() from virStorageBackendProbeTarget() Prepare the code probing a file's format and associated metadata for moving into libvirt_util. * src/storage/storage_backend_fs.c: re-factor the format and metadata probing code in preparation for moving it (cherry picked from commit f5fc670638d94776a4eba55f5affa69f69ba1ae2) Introduce virStorageFileMetadata structure Introduce a metadata structure and make virStorageGetMetadataFromFD() fill it in. * src/util/storage_file.h: add virStorageFileMetadata * src/backend/storage_backend_fs.c: virStorageGetMetadataFromFD() now fills in the virStorageFileMetadata structure (cherry picked from commit 5fede0a90be565e1c44b7c8236cb8910fd06b52f) Move virStorageGetMetadataFromFD() to libvirt_util Finally, we get to the point of all this. Move virStorageGetMetadataFromFD() to virStorageFileGetMetadataFromFD() and move to src/util/storage_file.[ch] There's no functional changes in this patch, just code movement * src/storage/storage_backend_fs.c: move code from here ... * src/util/storage_file.[ch]: ... to here * src/libvirt_private.syms: export virStorageFileGetMetadataFromFD() (cherry picked from commit a010fb58d6bce026852d611e32302da7687639e5) Add virStorageFileGetMetadata() helper * src/util/storage_file.c: add virStorageFileGetMetadata() so that the caller does not need to open the file (cherry picked from commit 295fd6e8330c7416e2d97634364f2890133c28fa) Fedora-patch: libvirt-svirt-relabel-qcow2-backing-files.patch --- src/Makefile.am | 1 + src/libvirt_private.syms | 7 +- src/security_selinux.c | 28 +++ src/storage_backend.c | 17 +- src/storage_backend_fs.c | 418 +++++---------------------------------------- src/storage_conf.c | 25 +-- src/storage_conf.h | 17 -- src/storage_file.c | 424 ++++++++++++++++++++++++++++++++++++++++++++++ src/storage_file.h | 62 +++++++ src/util.h | 1 + src/vbox/vbox_tmpl.c | 15 +- 11 files changed, 591 insertions(+), 424 deletions(-) create mode 100644 src/storage_file.c create mode 100644 src/storage_file.h diff --git a/src/Makefile.am b/src/Makefile.am index 463252e..3d279f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,6 +54,7 @@ UTIL_SOURCES = \ hostusb.c hostusb.h \ qparams.c qparams.h \ storage_encryption_conf.h storage_encryption_conf.c \ + storage_file.c storage_file.h \ threads.c threads.h \ threads-pthread.h \ threads-win32.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 867678f..500c209 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -359,8 +359,6 @@ virStorageVolDefParseNode; virStoragePoolFormatDiskTypeToString; virStoragePoolFormatFileSystemTypeToString; virStoragePoolFormatFileSystemNetTypeToString; -virStorageVolFormatFileSystemTypeToString; -virStorageVolFormatFileSystemTypeFromString; virStoragePoolTypeFromString; virStoragePartedFsTypeTypeToString; virStoragePoolObjLock; @@ -373,6 +371,11 @@ virStorageEncryptionParseNode; virStorageEncryptionFormat; virStorageGenerateQcowPassphrase; +# storage_file.h +virStorageFileFormatTypeToString; +virStorageFileFormatTypeFromString; +virStorageFileGetMetadata; +virStorageFileGetMetadataFromFD; # threads.h virMutexInit; diff --git a/src/security_selinux.c b/src/security_selinux.c index b4dc153..600fc75 100644 --- a/src/security_selinux.c +++ b/src/security_selinux.c @@ -27,6 +27,7 @@ #include "logging.h" #include "pci.h" #include "hostusb.h" +#include "storage_file.h" #define VIR_FROM_THIS VIR_FROM_SECURITY @@ -403,10 +404,37 @@ SELinuxSetSecurityImageLabel(virConnectPtr conn, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + const char *path; if (!disk->src) return 0; + path = disk->src; + do { + virStorageFileMetadata meta; + int ret; + + memset(&meta, 0, sizeof(meta)); + + ret = virStorageFileGetMetadata(conn, path, &meta); + + if (path != disk->src) + VIR_FREE(path); + path = NULL; + + if (ret < 0) + return -1; + + if (meta.backingStore != NULL && + SELinuxSetFilecon(conn, meta.backingStore, + default_content_context) < 0) { + VIR_FREE(meta.backingStore); + return -1; + } + + path = meta.backingStore; + } while (path != NULL); + if (disk->shared) { return SELinuxSetFilecon(conn, disk->src, default_image_context); } else if (disk->readonly) { diff --git a/src/storage_backend.c b/src/storage_backend.c index 800d4ea..1b65c5d 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -51,6 +51,7 @@ #include "internal.h" #include "secret_conf.h" #include "uuid.h" +#include "storage_file.h" #include "storage_backend.h" #include "logging.h" @@ -462,16 +463,16 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, char *create_tool; short use_kvmimg; - const char *type = virStorageVolFormatFileSystemTypeToString(vol->target.format); + const char *type = virStorageFileFormatTypeToString(vol->target.format); const char *backingType = vol->backingStore.path ? - virStorageVolFormatFileSystemTypeToString(vol->backingStore.format) : NULL; + virStorageFileFormatTypeToString(vol->backingStore.format) : NULL; const char *inputBackingPath = (inputvol ? inputvol->backingStore.path : NULL); const char *inputPath = inputvol ? inputvol->target.path : NULL; /* Treat input block devices as 'raw' format */ const char *inputType = inputPath ? - virStorageVolFormatFileSystemTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_VOL_FILE_RAW : inputvol->target.format) : + virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) : NULL; const char **imgargv; @@ -552,8 +553,8 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, if (vol->target.encryption != NULL) { virStorageEncryptionPtr enc; - if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW && - vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { + if (vol->target.format != VIR_STORAGE_FILE_QCOW && + vol->target.format != VIR_STORAGE_FILE_QCOW2) { virStorageReportError(conn, VIR_ERR_NO_SUPPORT, _("qcow volume encryption unsupported with " "volume format %s"), type); @@ -644,7 +645,7 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn, return -1; } - if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { + if (vol->target.format != VIR_STORAGE_FILE_QCOW2) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unsupported storage vol type %d"), vol->target.format); @@ -735,9 +736,9 @@ virStorageBackendGetBuildVolFromFunction(virConnectPtr conn, * tool for converting */ if ((vol->type == VIR_STORAGE_VOL_FILE && - vol->target.format != VIR_STORAGE_VOL_FILE_RAW) || + vol->target.format != VIR_STORAGE_FILE_RAW) || (inputvol->type == VIR_STORAGE_VOL_FILE && - inputvol->target.format != VIR_STORAGE_VOL_FILE_RAW)) { + inputvol->target.format != VIR_STORAGE_FILE_RAW)) { if ((tool_type = virStorageBackendFindFSImageTool(NULL)) < 0) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index 01cb171..6816da8 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -41,259 +41,24 @@ #include "virterror_internal.h" #include "storage_backend_fs.h" #include "storage_conf.h" +#include "storage_file.h" #include "util.h" #include "memory.h" #include "xml.h" -enum lv_endian { - LV_LITTLE_ENDIAN = 1, /* 1234 */ - LV_BIG_ENDIAN /* 4321 */ -}; - -enum { - BACKING_STORE_OK, - BACKING_STORE_INVALID, - BACKING_STORE_ERROR, -}; - -static int cowGetBackingStore(virConnectPtr, char **, - const unsigned char *, size_t); -static int qcowXGetBackingStore(virConnectPtr, char **, - const unsigned char *, size_t); -static int vmdk4GetBackingStore(virConnectPtr, char **, - const unsigned char *, size_t); - -/* Either 'magic' or 'extension' *must* be provided */ -struct FileTypeInfo { - int type; /* One of the constants above */ - const char *magic; /* Optional string of file magic - * to check at head of file */ - const char *extension; /* Optional file extension to check */ - enum lv_endian endian; /* Endianness of file format */ - int versionOffset; /* Byte offset from start of file - * where we find version number, - * -1 to skip version test */ - int versionNumber; /* Version number to validate */ - int sizeOffset; /* Byte offset from start of file - * where we find capacity info, - * -1 to use st_size as capacity */ - int sizeBytes; /* Number of bytes for size field */ - int sizeMultiplier; /* A scaling factor if size is not in bytes */ - /* Store a COW base image path (possibly relative), - * or NULL if there is no COW base image, to RES; - * return BACKING_STORE_* */ - int qcowCryptOffset; /* Byte offset from start of file - * where to find encryption mode, - * -1 if encryption is not used */ - int (*getBackingStore)(virConnectPtr conn, char **res, - const unsigned char *buf, size_t buf_size); -}; -struct FileTypeInfo const fileTypeInfo[] = { - /* Bochs */ - /* XXX Untested - { VIR_STORAGE_VOL_FILE_BOCHS, "Bochs Virtual HD Image", NULL, - LV_LITTLE_ENDIAN, 64, 0x20000, - 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/ - /* CLoop */ - /* XXX Untested - { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL, - LV_LITTLE_ENDIAN, -1, 0, - -1, 0, 0, -1, NULL }, */ - /* Cow */ - { VIR_STORAGE_VOL_FILE_COW, "OOOM", NULL, - LV_BIG_ENDIAN, 4, 2, - 4+4+1024+4, 8, 1, -1, cowGetBackingStore }, - /* DMG */ - /* XXX QEMU says there's no magic for dmg, but we should check... */ - { VIR_STORAGE_VOL_FILE_DMG, NULL, ".dmg", - 0, -1, 0, - -1, 0, 0, -1, NULL }, - /* XXX there's probably some magic for iso we can validate too... */ - { VIR_STORAGE_VOL_FILE_ISO, NULL, ".iso", - 0, -1, 0, - -1, 0, 0, -1, NULL }, - /* Parallels */ - /* XXX Untested - { VIR_STORAGE_VOL_FILE_PARALLELS, "WithoutFreeSpace", NULL, - LV_LITTLE_ENDIAN, 16, 2, - 16+4+4+4+4, 4, 512, -1, NULL }, - */ - /* QCow */ - { VIR_STORAGE_VOL_FILE_QCOW, "QFI", NULL, - LV_BIG_ENDIAN, 4, 1, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore }, - /* QCow 2 */ - { VIR_STORAGE_VOL_FILE_QCOW2, "QFI", NULL, - LV_BIG_ENDIAN, 4, 2, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore }, - /* VMDK 3 */ - /* XXX Untested - { VIR_STORAGE_VOL_FILE_VMDK, "COWD", NULL, - LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 4, 512, -1, NULL }, - */ - /* VMDK 4 */ - { VIR_STORAGE_VOL_FILE_VMDK, "KDMV", NULL, - LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 8, 512, -1, vmdk4GetBackingStore }, - /* Connectix / VirtualPC */ - /* XXX Untested - { VIR_STORAGE_VOL_FILE_VPC, "conectix", NULL, - LV_BIG_ENDIAN, -1, 0, - -1, 0, 0, -1, NULL}, - */ -}; - #define VIR_FROM_THIS VIR_FROM_STORAGE static int -cowGetBackingStore(virConnectPtr conn, - char **res, - const unsigned char *buf, - size_t buf_size) -{ -#define COW_FILENAME_MAXLEN 1024 - *res = NULL; - if (buf_size < 4+4+ COW_FILENAME_MAXLEN) - return BACKING_STORE_INVALID; - if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */ - return BACKING_STORE_OK; - - *res = strndup ((const char*)buf + 4+4, COW_FILENAME_MAXLEN); - if (*res == NULL) { - virReportOOMError(conn); - return BACKING_STORE_ERROR; - } - return BACKING_STORE_OK; -} - -static int -qcowXGetBackingStore(virConnectPtr conn, - char **res, - const unsigned char *buf, - size_t buf_size) -{ - unsigned long long offset; - unsigned long size; - - *res = NULL; - if (buf_size < 4+4+8+4) - return BACKING_STORE_INVALID; - offset = (((unsigned long long)buf[4+4] << 56) - | ((unsigned long long)buf[4+4+1] << 48) - | ((unsigned long long)buf[4+4+2] << 40) - | ((unsigned long long)buf[4+4+3] << 32) - | ((unsigned long long)buf[4+4+4] << 24) - | ((unsigned long long)buf[4+4+5] << 16) - | ((unsigned long long)buf[4+4+6] << 8) - | buf[4+4+7]); /* QCowHeader.backing_file_offset */ - if (offset > buf_size) - return BACKING_STORE_INVALID; - size = ((buf[4+4+8] << 24) - | (buf[4+4+8+1] << 16) - | (buf[4+4+8+2] << 8) - | buf[4+4+8+3]); /* QCowHeader.backing_file_size */ - if (size == 0) - return BACKING_STORE_OK; - if (offset + size > buf_size || offset + size < offset) - return BACKING_STORE_INVALID; - if (size + 1 == 0) - return BACKING_STORE_INVALID; - if (VIR_ALLOC_N(*res, size + 1) < 0) { - virReportOOMError(conn); - return BACKING_STORE_ERROR; - } - memcpy(*res, buf + offset, size); - (*res)[size] = '\0'; - return BACKING_STORE_OK; -} - - -static int -vmdk4GetBackingStore(virConnectPtr conn, - char **res, - const unsigned char *buf, - size_t buf_size) -{ - static const char prefix[] = "parentFileNameHint=\""; - - char desc[20*512 + 1], *start, *end; - size_t len; - - *res = NULL; - - if (buf_size <= 0x200) - return BACKING_STORE_INVALID; - len = buf_size - 0x200; - if (len > sizeof(desc) - 1) - len = sizeof(desc) - 1; - memcpy(desc, buf + 0x200, len); - desc[len] = '\0'; - start = strstr(desc, prefix); - if (start == NULL) - return BACKING_STORE_OK; - start += strlen(prefix); - end = strchr(start, '"'); - if (end == NULL) - return BACKING_STORE_INVALID; - if (end == start) - return BACKING_STORE_OK; - *end = '\0'; - *res = strdup(start); - if (*res == NULL) { - virReportOOMError(conn); - return BACKING_STORE_ERROR; - } - return BACKING_STORE_OK; -} - -/** - * Return an absolute path corresponding to PATH, which is absolute or relative - * to the directory containing BASE_FILE, or NULL on error - */ -static char *absolutePathFromBaseFile(const char *base_file, const char *path) +virStorageBackendProbeTarget(virConnectPtr conn, + virStorageVolTargetPtr target, + char **backingStore, + unsigned long long *allocation, + unsigned long long *capacity, + virStorageEncryptionPtr *encryption) { - size_t base_size, path_size; - char *res, *p; - - if (*path == '/') - return strdup(path); - - base_size = strlen(base_file) + 1; - path_size = strlen(path) + 1; - if (VIR_ALLOC_N(res, base_size - 1 + path_size) < 0) - return NULL; - memcpy(res, base_file, base_size); - p = strrchr(res, '/'); - if (p != NULL) - p++; - else - p = res; - memcpy(p, path, path_size); - if (VIR_REALLOC_N(res, (p + path_size) - res) < 0) { - /* Ignore failure */ - } - return res; -} - - - -/** - * Probe the header of a file to determine what type of disk image - * it is, and info about its capacity if available. - */ -static int virStorageBackendProbeTarget(virConnectPtr conn, - virStorageVolTargetPtr target, - char **backingStore, - unsigned long long *allocation, - unsigned long long *capacity, - virStorageEncryptionPtr *encryption) { - int fd; - unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ - int len, i, ret; + int fd, ret; + virStorageFileMetadata meta; - if (backingStore) - *backingStore = NULL; if (encryption) *encryption = NULL; @@ -311,148 +76,51 @@ static int virStorageBackendProbeTarget(virConnectPtr conn, return ret; /* Take care to propagate ret, it is not always -1 */ } - if ((len = read(fd, head, sizeof(head))) < 0) { - virReportSystemError(conn, errno, - _("cannot read header '%s'"), - target->path); + memset(&meta, 0, sizeof(meta)); + + if (virStorageFileGetMetadataFromFD(conn, target->path, fd, &meta) < 0) { close(fd); return -1; } close(fd); - /* First check file magic */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - int mlen; - bool encrypted_qcow = false; - - if (fileTypeInfo[i].magic == NULL) - continue; - - /* Validate magic data */ - mlen = strlen(fileTypeInfo[i].magic); - if (mlen > len) - continue; - if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0) - continue; - - /* Validate version number info */ - if (fileTypeInfo[i].versionNumber != -1) { - int version; - - if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { - version = (head[fileTypeInfo[i].versionOffset+3] << 24) | - (head[fileTypeInfo[i].versionOffset+2] << 16) | - (head[fileTypeInfo[i].versionOffset+1] << 8) | - head[fileTypeInfo[i].versionOffset]; - } else { - version = (head[fileTypeInfo[i].versionOffset] << 24) | - (head[fileTypeInfo[i].versionOffset+1] << 16) | - (head[fileTypeInfo[i].versionOffset+2] << 8) | - head[fileTypeInfo[i].versionOffset+3]; - } - if (version != fileTypeInfo[i].versionNumber) - continue; - } - - /* Optionally extract capacity from file */ - if (fileTypeInfo[i].sizeOffset != -1 && capacity) { - if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { - *capacity = - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset]); - } else { - *capacity = - ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]); - } - /* Avoid unlikely, but theoretically possible overflow */ - if (*capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier)) - continue; - *capacity *= fileTypeInfo[i].sizeMultiplier; - } - - if (fileTypeInfo[i].qcowCryptOffset != -1) { - int crypt_format; + target->format = meta.format; - crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) | - (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) | - (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) | - head[fileTypeInfo[i].qcowCryptOffset+3]; - encrypted_qcow = crypt_format != 0; - } - - /* Validation passed, we know the file format now */ - target->format = fileTypeInfo[i].type; - if (fileTypeInfo[i].getBackingStore != NULL && backingStore) { - char *base; + if (backingStore) { + *backingStore = meta.backingStore; + meta.backingStore = NULL; + } - switch (fileTypeInfo[i].getBackingStore(conn, &base, head, len)) { - case BACKING_STORE_OK: - break; + VIR_FREE(meta.backingStore); - case BACKING_STORE_INVALID: - continue; + if (capacity && meta.capacity) + *capacity = meta.capacity; - case BACKING_STORE_ERROR: - return -1; - } - if (base != NULL) { - *backingStore - = absolutePathFromBaseFile(target->path, base); - VIR_FREE(base); - if (*backingStore == NULL) { - virReportOOMError(conn); - return -1; - } - } + if (encryption != NULL && meta.encrypted) { + if (VIR_ALLOC(*encryption) < 0) { + virReportOOMError(conn); + if (backingStore) + VIR_FREE(*backingStore); + return -1; } - if (encryption != NULL && encrypted_qcow) { - virStorageEncryptionPtr enc; - if (VIR_ALLOC(enc) < 0) { - virReportOOMError(conn); - if (backingStore) - VIR_FREE(*backingStore); - return -1; - } - enc->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; - *encryption = enc; - /* XXX ideally we'd fill in secret UUID here - * but we cannot guarentee 'conn' is non-NULL - * at this point in time :-( So we only fill - * in secrets when someone first queries a vol - */ + switch (target->format) { + case VIR_STORAGE_FILE_QCOW: + case VIR_STORAGE_FILE_QCOW2: + (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; + break; + default: + break; } - return 0; - } - - /* No magic, so check file extension */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - if (fileTypeInfo[i].extension == NULL) - continue; - - if (!virFileHasSuffix(target->path, fileTypeInfo[i].extension)) - continue; - target->format = fileTypeInfo[i].type; - return 0; + /* XXX ideally we'd fill in secret UUID here + * but we cannot guarentee 'conn' is non-NULL + * at this point in time :-( So we only fill + * in secrets when someone first queries a vol + */ } - /* All fails, so call it a raw file */ - target->format = VIR_STORAGE_VOL_FILE_RAW; return 0; } @@ -891,7 +559,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn, goto no_memory; vol->type = VIR_STORAGE_VOL_FILE; - vol->target.format = VIR_STORAGE_VOL_FILE_RAW; /* Real value is filled in during probe */ + vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */ if (virAsprintf(&vol->target.path, "%s/%s", pool->def->target.path, vol->name) == -1) @@ -918,7 +586,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn, } if (backingStore != NULL) { - if (vol->target.format == VIR_STORAGE_VOL_FILE_QCOW2 && + if (vol->target.format == VIR_STORAGE_FILE_QCOW2 && STRPREFIX("fmt:", backingStore)) { char *fmtstr = backingStore + 4; char *path = strchr(fmtstr, ':'); @@ -927,7 +595,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn, } else { *path = '\0'; if ((vol->backingStore.format = - virStorageVolFormatFileSystemTypeFromString(fmtstr)) < 0) { + virStorageFileFormatTypeFromString(fmtstr)) < 0) { VIR_FREE(backingStore); } else { memmove(backingStore, path, strlen(path) + 1); @@ -1121,9 +789,9 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn, inputvol); if (!create_func) return -1; - } else if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) { + } else if (vol->target.format == VIR_STORAGE_FILE_RAW) { create_func = virStorageBackendCreateRaw; - } else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) { + } else if (vol->target.format == VIR_STORAGE_FILE_DIR) { create_func = createFileDir; } else if ((tool_type = virStorageBackendFindFSImageTool(NULL)) != -1) { create_func = virStorageBackendFSImageToolTypeToFunc(conn, tool_type); diff --git a/src/storage_conf.c b/src/storage_conf.c index cb063cc..788de15 100644 --- a/src/storage_conf.c +++ b/src/storage_conf.c @@ -36,6 +36,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "storage_conf.h" +#include "storage_file.h" #include "xml.h" #include "uuid.h" @@ -82,12 +83,6 @@ VIR_ENUM_IMPL(virStorageVolFormatDisk, "linux-lvm", "linux-raid", "extended") -VIR_ENUM_IMPL(virStorageVolFormatFileSystem, - VIR_STORAGE_VOL_FILE_LAST, - "raw", "dir", "bochs", - "cloop", "cow", "dmg", "iso", - "qcow", "qcow2", "vmdk", "vpc") - VIR_ENUM_IMPL(virStoragePartedFsType, VIR_STORAGE_PARTED_FS_TYPE_LAST, "ext2", "ext2", "fat16", @@ -150,9 +145,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { }, { .poolType = VIR_STORAGE_POOL_DIR, .volOptions = { - .defaultFormat = VIR_STORAGE_VOL_FILE_RAW, - .formatFromString = virStorageVolFormatFileSystemTypeFromString, - .formatToString = virStorageVolFormatFileSystemTypeToString, + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatFromString = virStorageFileFormatTypeFromString, + .formatToString = virStorageFileFormatTypeToString, }, }, { .poolType = VIR_STORAGE_POOL_FS, @@ -162,9 +157,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatFileSystemTypeToString, }, .volOptions = { - .defaultFormat = VIR_STORAGE_VOL_FILE_RAW, - .formatFromString = virStorageVolFormatFileSystemTypeFromString, - .formatToString = virStorageVolFormatFileSystemTypeToString, + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatFromString = virStorageFileFormatTypeFromString, + .formatToString = virStorageFileFormatTypeToString, }, }, { .poolType = VIR_STORAGE_POOL_NETFS, @@ -176,9 +171,9 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatFileSystemNetTypeToString, }, .volOptions = { - .defaultFormat = VIR_STORAGE_VOL_FILE_RAW, - .formatFromString = virStorageVolFormatFileSystemTypeFromString, - .formatToString = virStorageVolFormatFileSystemTypeToString, + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatFromString = virStorageFileFormatTypeFromString, + .formatToString = virStorageFileFormatTypeToString, }, }, { .poolType = VIR_STORAGE_POOL_ISCSI, diff --git a/src/storage_conf.h b/src/storage_conf.h index 421d305..9fedb12 100644 --- a/src/storage_conf.h +++ b/src/storage_conf.h @@ -429,23 +429,6 @@ enum virStoragePoolFormatLogical { }; VIR_ENUM_DECL(virStoragePoolFormatLogical) - -enum virStorageVolFormatFileSystem { - VIR_STORAGE_VOL_FILE_RAW = 0, - VIR_STORAGE_VOL_FILE_DIR, - VIR_STORAGE_VOL_FILE_BOCHS, - VIR_STORAGE_VOL_FILE_CLOOP, - VIR_STORAGE_VOL_FILE_COW, - VIR_STORAGE_VOL_FILE_DMG, - VIR_STORAGE_VOL_FILE_ISO, - VIR_STORAGE_VOL_FILE_QCOW, - VIR_STORAGE_VOL_FILE_QCOW2, - VIR_STORAGE_VOL_FILE_VMDK, - VIR_STORAGE_VOL_FILE_VPC, - VIR_STORAGE_VOL_FILE_LAST, -}; -VIR_ENUM_DECL(virStorageVolFormatFileSystem) - /* * XXX these are basically partition types. * diff --git a/src/storage_file.c b/src/storage_file.c new file mode 100644 index 0000000..44057d2 --- /dev/null +++ b/src/storage_file.c @@ -0,0 +1,424 @@ +/* + * storage_file.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#include +#include "storage_file.h" + +#include +#include +#include "memory.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_ENUM_IMPL(virStorageFileFormat, + VIR_STORAGE_FILE_LAST, + "raw", "dir", "bochs", + "cloop", "cow", "dmg", "iso", + "qcow", "qcow2", "vmdk", "vpc") + +enum lv_endian { + LV_LITTLE_ENDIAN = 1, /* 1234 */ + LV_BIG_ENDIAN /* 4321 */ +}; + +enum { + BACKING_STORE_OK, + BACKING_STORE_INVALID, + BACKING_STORE_ERROR, +}; + +/* Either 'magic' or 'extension' *must* be provided */ +struct FileTypeInfo { + int type; /* One of the constants above */ + const char *magic; /* Optional string of file magic + * to check at head of file */ + const char *extension; /* Optional file extension to check */ + enum lv_endian endian; /* Endianness of file format */ + int versionOffset; /* Byte offset from start of file + * where we find version number, + * -1 to skip version test */ + int versionNumber; /* Version number to validate */ + int sizeOffset; /* Byte offset from start of file + * where we find capacity info, + * -1 to use st_size as capacity */ + int sizeBytes; /* Number of bytes for size field */ + int sizeMultiplier; /* A scaling factor if size is not in bytes */ + /* Store a COW base image path (possibly relative), + * or NULL if there is no COW base image, to RES; + * return BACKING_STORE_* */ + int qcowCryptOffset; /* Byte offset from start of file + * where to find encryption mode, + * -1 if encryption is not used */ + int (*getBackingStore)(virConnectPtr conn, char **res, + const unsigned char *buf, size_t buf_size); +}; + +static int cowGetBackingStore(virConnectPtr, char **, + const unsigned char *, size_t); +static int qcowXGetBackingStore(virConnectPtr, char **, + const unsigned char *, size_t); +static int vmdk4GetBackingStore(virConnectPtr, char **, + const unsigned char *, size_t); + + +static struct FileTypeInfo const fileTypeInfo[] = { + /* Bochs */ + /* XXX Untested + { VIR_STORAGE_FILE_BOCHS, "Bochs Virtual HD Image", NULL, + LV_LITTLE_ENDIAN, 64, 0x20000, + 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/ + /* CLoop */ + /* XXX Untested + { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL, + LV_LITTLE_ENDIAN, -1, 0, + -1, 0, 0, -1, NULL }, */ + /* Cow */ + { VIR_STORAGE_FILE_COW, "OOOM", NULL, + LV_BIG_ENDIAN, 4, 2, + 4+4+1024+4, 8, 1, -1, cowGetBackingStore }, + /* DMG */ + /* XXX QEMU says there's no magic for dmg, but we should check... */ + { VIR_STORAGE_FILE_DMG, NULL, ".dmg", + 0, -1, 0, + -1, 0, 0, -1, NULL }, + /* XXX there's probably some magic for iso we can validate too... */ + { VIR_STORAGE_FILE_ISO, NULL, ".iso", + 0, -1, 0, + -1, 0, 0, -1, NULL }, + /* Parallels */ + /* XXX Untested + { VIR_STORAGE_FILE_PARALLELS, "WithoutFreeSpace", NULL, + LV_LITTLE_ENDIAN, 16, 2, + 16+4+4+4+4, 4, 512, -1, NULL }, + */ + /* QCow */ + { VIR_STORAGE_FILE_QCOW, "QFI", NULL, + LV_BIG_ENDIAN, 4, 1, + 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore }, + /* QCow 2 */ + { VIR_STORAGE_FILE_QCOW2, "QFI", NULL, + LV_BIG_ENDIAN, 4, 2, + 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore }, + /* VMDK 3 */ + /* XXX Untested + { VIR_STORAGE_FILE_VMDK, "COWD", NULL, + LV_LITTLE_ENDIAN, 4, 1, + 4+4+4, 4, 512, -1, NULL }, + */ + /* VMDK 4 */ + { VIR_STORAGE_FILE_VMDK, "KDMV", NULL, + LV_LITTLE_ENDIAN, 4, 1, + 4+4+4, 8, 512, -1, vmdk4GetBackingStore }, + /* Connectix / VirtualPC */ + /* XXX Untested + { VIR_STORAGE_FILE_VPC, "conectix", NULL, + LV_BIG_ENDIAN, -1, 0, + -1, 0, 0, -1, NULL}, + */ +}; + +static int +cowGetBackingStore(virConnectPtr conn, + char **res, + const unsigned char *buf, + size_t buf_size) +{ +#define COW_FILENAME_MAXLEN 1024 + *res = NULL; + if (buf_size < 4+4+ COW_FILENAME_MAXLEN) + return BACKING_STORE_INVALID; + if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */ + return BACKING_STORE_OK; + + *res = strndup ((const char*)buf + 4+4, COW_FILENAME_MAXLEN); + if (*res == NULL) { + virReportOOMError(conn); + return BACKING_STORE_ERROR; + } + return BACKING_STORE_OK; +} + +static int +qcowXGetBackingStore(virConnectPtr conn, + char **res, + const unsigned char *buf, + size_t buf_size) +{ + unsigned long long offset; + unsigned long size; + + *res = NULL; + if (buf_size < 4+4+8+4) + return BACKING_STORE_INVALID; + offset = (((unsigned long long)buf[4+4] << 56) + | ((unsigned long long)buf[4+4+1] << 48) + | ((unsigned long long)buf[4+4+2] << 40) + | ((unsigned long long)buf[4+4+3] << 32) + | ((unsigned long long)buf[4+4+4] << 24) + | ((unsigned long long)buf[4+4+5] << 16) + | ((unsigned long long)buf[4+4+6] << 8) + | buf[4+4+7]); /* QCowHeader.backing_file_offset */ + if (offset > buf_size) + return BACKING_STORE_INVALID; + size = ((buf[4+4+8] << 24) + | (buf[4+4+8+1] << 16) + | (buf[4+4+8+2] << 8) + | buf[4+4+8+3]); /* QCowHeader.backing_file_size */ + if (size == 0) + return BACKING_STORE_OK; + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + if (size + 1 == 0) + return BACKING_STORE_INVALID; + if (VIR_ALLOC_N(*res, size + 1) < 0) { + virReportOOMError(conn); + return BACKING_STORE_ERROR; + } + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + return BACKING_STORE_OK; +} + + +static int +vmdk4GetBackingStore(virConnectPtr conn, + char **res, + const unsigned char *buf, + size_t buf_size) +{ + static const char prefix[] = "parentFileNameHint=\""; + + char desc[20*512 + 1], *start, *end; + size_t len; + + *res = NULL; + + if (buf_size <= 0x200) + return BACKING_STORE_INVALID; + len = buf_size - 0x200; + if (len > sizeof(desc) - 1) + len = sizeof(desc) - 1; + memcpy(desc, buf + 0x200, len); + desc[len] = '\0'; + start = strstr(desc, prefix); + if (start == NULL) + return BACKING_STORE_OK; + start += strlen(prefix); + end = strchr(start, '"'); + if (end == NULL) + return BACKING_STORE_INVALID; + if (end == start) + return BACKING_STORE_OK; + *end = '\0'; + *res = strdup(start); + if (*res == NULL) { + virReportOOMError(conn); + return BACKING_STORE_ERROR; + } + return BACKING_STORE_OK; +} + +/** + * Return an absolute path corresponding to PATH, which is absolute or relative + * to the directory containing BASE_FILE, or NULL on error + */ +static char * +absolutePathFromBaseFile(const char *base_file, const char *path) +{ + size_t base_size, path_size; + char *res, *p; + + if (*path == '/') + return strdup(path); + + base_size = strlen(base_file) + 1; + path_size = strlen(path) + 1; + if (VIR_ALLOC_N(res, base_size - 1 + path_size) < 0) + return NULL; + memcpy(res, base_file, base_size); + p = strrchr(res, '/'); + if (p != NULL) + p++; + else + p = res; + memcpy(p, path, path_size); + if (VIR_REALLOC_N(res, (p + path_size) - res) < 0) { + /* Ignore failure */ + } + return res; +} + +/** + * Probe the header of a file to determine what type of disk image + * it is, and info about its capacity if available. + */ +int +virStorageFileGetMetadataFromFD(virConnectPtr conn, + const char *path, + int fd, + virStorageFileMetadata *meta) +{ + unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ + int len, i; + + /* If all else fails, call it a raw file */ + meta->format = VIR_STORAGE_FILE_RAW; + + if ((len = read(fd, head, sizeof(head))) < 0) { + virReportSystemError(conn, errno, _("cannot read header '%s'"), path); + return -1; + } + + /* First check file magic */ + for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { + int mlen; + + if (fileTypeInfo[i].magic == NULL) + continue; + + /* Validate magic data */ + mlen = strlen(fileTypeInfo[i].magic); + if (mlen > len) + continue; + if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0) + continue; + + /* Validate version number info */ + if (fileTypeInfo[i].versionNumber != -1) { + int version; + + if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { + version = (head[fileTypeInfo[i].versionOffset+3] << 24) | + (head[fileTypeInfo[i].versionOffset+2] << 16) | + (head[fileTypeInfo[i].versionOffset+1] << 8) | + head[fileTypeInfo[i].versionOffset]; + } else { + version = (head[fileTypeInfo[i].versionOffset] << 24) | + (head[fileTypeInfo[i].versionOffset+1] << 16) | + (head[fileTypeInfo[i].versionOffset+2] << 8) | + head[fileTypeInfo[i].versionOffset+3]; + } + if (version != fileTypeInfo[i].versionNumber) + continue; + } + + /* Optionally extract capacity from file */ + if (fileTypeInfo[i].sizeOffset != -1) { + if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { + meta->capacity = + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset]); + } else { + meta->capacity = + ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) | + ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]); + } + /* Avoid unlikely, but theoretically possible overflow */ + if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier)) + continue; + meta->capacity *= fileTypeInfo[i].sizeMultiplier; + } + + if (fileTypeInfo[i].qcowCryptOffset != -1) { + int crypt_format; + + crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) | + (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) | + (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) | + head[fileTypeInfo[i].qcowCryptOffset+3]; + meta->encrypted = crypt_format != 0; + } + + /* Validation passed, we know the file format now */ + meta->format = fileTypeInfo[i].type; + if (fileTypeInfo[i].getBackingStore != NULL) { + char *base; + + switch (fileTypeInfo[i].getBackingStore(conn, &base, head, len)) { + case BACKING_STORE_OK: + break; + + case BACKING_STORE_INVALID: + continue; + + case BACKING_STORE_ERROR: + return -1; + } + if (base != NULL) { + meta->backingStore = absolutePathFromBaseFile(path, base); + VIR_FREE(base); + if (meta->backingStore == NULL) { + virReportOOMError(conn); + return -1; + } + } + } + return 0; + } + + /* No magic, so check file extension */ + for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { + if (fileTypeInfo[i].extension == NULL) + continue; + + if (!virFileHasSuffix(path, fileTypeInfo[i].extension)) + continue; + + meta->format = fileTypeInfo[i].type; + return 0; + } + + return 0; +} + +int +virStorageFileGetMetadata(virConnectPtr conn, + const char *path, + virStorageFileMetadata *meta) +{ + int fd, ret; + + if ((fd = open(path, O_RDONLY)) < 0) { + virReportSystemError(conn, errno, _("cannot open file '%s'"), path); + return -1; + } + + ret = virStorageFileGetMetadataFromFD(conn, path, fd, meta); + + close(fd); + + return ret; +} diff --git a/src/storage_file.h b/src/storage_file.h new file mode 100644 index 0000000..b0abcaf --- /dev/null +++ b/src/storage_file.h @@ -0,0 +1,62 @@ +/* + * storage_file.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#ifndef __VIR_STORAGE_FILE_H__ +#define __VIR_STORAGE_FILE_H__ + +#include "util.h" +#include + +enum virStorageFileFormat { + VIR_STORAGE_FILE_RAW = 0, + VIR_STORAGE_FILE_DIR, + VIR_STORAGE_FILE_BOCHS, + VIR_STORAGE_FILE_CLOOP, + VIR_STORAGE_FILE_COW, + VIR_STORAGE_FILE_DMG, + VIR_STORAGE_FILE_ISO, + VIR_STORAGE_FILE_QCOW, + VIR_STORAGE_FILE_QCOW2, + VIR_STORAGE_FILE_VMDK, + VIR_STORAGE_FILE_VPC, + VIR_STORAGE_FILE_LAST, +}; + +VIR_ENUM_DECL(virStorageFileFormat); + +typedef struct _virStorageFileMetadata { + int format; + char *backingStore; + unsigned long long capacity; + bool encrypted; +} virStorageFileMetadata; + +int virStorageFileGetMetadata(virConnectPtr conn, + const char *path, + virStorageFileMetadata *meta); +int virStorageFileGetMetadataFromFD(virConnectPtr conn, + const char *path, + int fd, + virStorageFileMetadata *meta); + +#endif /* __VIR_STORAGE_FILE_H__ */ diff --git a/src/util.h b/src/util.h index f9715ab..75afecc 100644 --- a/src/util.h +++ b/src/util.h @@ -26,6 +26,7 @@ #define __VIR_UTIL_H__ #include "verify.h" +#include "internal.h" #include #include diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 7270710..783a216 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -45,6 +45,7 @@ #include "virterror_internal.h" #include "domain_event.h" #include "storage_conf.h" +#include "storage_file.h" #include "uuid.h" #include "event.h" #include "memory.h" @@ -5980,14 +5981,14 @@ static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool, /* TODO: for now only the vmdk, vpc and vdi type harddisk * variants can be created, also since there is no vdi - * type in enum virStorageVolFormatFileSystem {} the default + * type in enum virStorageFileFormat {} the default * will be to create vdi if nothing is specified in * def->target.format */ - if (def->target.format == VIR_STORAGE_VOL_FILE_VMDK) { + if (def->target.format == VIR_STORAGE_FILE_VMDK) { data->pFuncs->pfnUtf8ToUtf16("VMDK", &hddFormatUtf16); - } else if (def->target.format == VIR_STORAGE_VOL_FILE_VPC) { + } else if (def->target.format == VIR_STORAGE_FILE_VPC) { data->pFuncs->pfnUtf8ToUtf16("VHD", &hddFormatUtf16); } else { data->pFuncs->pfnUtf8ToUtf16("VDI", &hddFormatUtf16); @@ -6302,13 +6303,13 @@ static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags A DEBUG("Storage Volume Format: %s", hddFormatUtf8); if (STRCASEEQ("vmdk", hddFormatUtf8)) - def.target.format = VIR_STORAGE_VOL_FILE_VMDK; + def.target.format = VIR_STORAGE_FILE_VMDK; else if (STRCASEEQ("vhd", hddFormatUtf8)) - def.target.format = VIR_STORAGE_VOL_FILE_VPC; + def.target.format = VIR_STORAGE_FILE_VPC; else - def.target.format = VIR_STORAGE_VOL_FILE_RAW; + def.target.format = VIR_STORAGE_FILE_RAW; - /* TODO: need to add vdi to enum virStorageVolFormatFileSystem {} + /* TODO: need to add vdi to enum virStorageFileFormat {} * and then add it here */ -- 1.6.2.5