static int parallelsFindVolumes(virStoragePoolObjPtr pool) { DIR *dir; struct dirent *ent; char *path = NULL; int ret = -1; if (!(dir = opendir(pool->def->target.path))) { virReportSystemError(errno, _("cannot open path '%s'"), pool->def->target.path); return -1; } while ((ent = readdir(dir)) != NULL) { if (!virFileHasSuffix(ent->d_name, ".xml")) continue; if (!(path = virFileBuildPath(pool->def->target.path, ent->d_name, NULL))) goto cleanup; if (!parallelsStorageVolDefineXML(pool, NULL, path, false)) goto cleanup; VIR_FREE(path); } ret = 0; cleanup: VIR_FREE(path); closedir(dir); return ret; }
static int testSchemaDir(const char *schema, virXMLValidatorPtr validator, const char *dir_path) { DIR *dir = NULL; struct dirent *ent; int ret = 0; int rc; char *test_name = NULL; char *xml_path = NULL; struct testSchemaData data = { .validator = validator, }; if (virDirOpen(&dir, dir_path) < 0) return -1; while ((rc = virDirRead(dir, &ent, dir_path)) > 0) { if (!virFileHasSuffix(ent->d_name, ".xml")) continue; if (virAsprintf(&xml_path, "%s/%s", dir_path, ent->d_name) < 0) goto cleanup; if (virAsprintf(&test_name, "Checking %s against %s", ent->d_name, schema) < 0) goto cleanup; data.xml_path = xml_path; if (virTestRun(test_name, testSchemaFile, &data) < 0) ret = -1; VIR_FREE(test_name); VIR_FREE(xml_path); } if (rc < 0) ret = -1; cleanup: VIR_FREE(test_name); VIR_FREE(xml_path); VIR_DIR_CLOSE(dir); return ret; }
static int testSchemaFile(const void *args) { const struct testSchemaData *data = args; bool shouldFail = virFileHasSuffix(data->xml_path, "-invalid.xml"); xmlDocPtr xml = NULL; int ret = -1; if (!(xml = virXMLParseFile(data->xml_path))) return -1; if (virXMLValidatorValidate(data->validator, xml) < 0) { if (!shouldFail) goto cleanup; } else { if (shouldFail) goto cleanup; } ret = 0; cleanup: xmlFreeDoc(xml); return ret; }
int vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath) { virDomainDiskDefPtr disk = NULL; char *directoryName = NULL; char *fileName = NULL; int ret = -1; size_t i; /* * Build VMX URL. Use the source of the first file-based harddisk * to deduce the path for the VMX file. Don't just use the * first disk, because it may be CDROM disk and ISO images are normaly not * located in the virtual machine's directory. This approach * isn't perfect but should work in the majority of cases. */ if (vmdef->ndisks < 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Domain XML doesn't contain any disks, " "cannot deduce datastore and path for VMX file")); goto cleanup; } for (i = 0; i < vmdef->ndisks; ++i) { if (vmdef->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK && vmdef->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) { disk = vmdef->disks[i]; break; } } if (disk == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Domain XML doesn't contain any file-based harddisks, " "cannot deduce datastore and path for VMX file")); goto cleanup; } if (disk->src == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("First file-based harddisk has no source, cannot " "deduce datastore and path for VMX file")); goto cleanup; } if (vmwareParsePath(disk->src, &directoryName, &fileName) < 0) { goto cleanup; } if (!virFileHasSuffix(fileName, ".vmdk")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Expecting source '%s' of first file-based harddisk " "to be a VMDK image"), disk->src); goto cleanup; } if (vmwareConstructVmxPath(directoryName, vmdef->name, vmxPath) < 0) goto cleanup; ret = 0; cleanup: VIR_FREE(directoryName); VIR_FREE(fileName); return ret; }
static virStorageVolPtr esxStorageVolCreateXML(virStoragePoolPtr pool, const char *xmldesc, unsigned int flags) { virStorageVolPtr volume = NULL; esxPrivate *priv = pool->conn->privateData; virStoragePoolDef poolDef; virStorageVolDefPtr def = NULL; char *tmp; char *unescapedDatastorePath = NULL; char *unescapedDirectoryName = NULL; char *unescapedDirectoryAndFileName = NULL; char *directoryName = NULL; char *fileName = NULL; char *datastorePathWithoutFileName = NULL; char *datastorePath = NULL; esxVI_FileInfo *fileInfo = NULL; esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL; esxVI_ManagedObjectReference *task = NULL; esxVI_TaskInfoState taskInfoState; char *taskInfoErrorMessage = NULL; char *uuid_string = NULL; char *key = NULL; virCheckFlags(0, NULL); memset(&poolDef, 0, sizeof(poolDef)); if (esxLookupVMFSStoragePoolType(priv->primary, pool->name, &poolDef.type) < 0) { goto cleanup; } /* Parse config */ def = virStorageVolDefParseString(&poolDef, xmldesc); if (!def) goto cleanup; if (def->type != VIR_STORAGE_VOL_FILE) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Creating non-file volumes is not supported")); goto cleanup; } /* Validate config */ tmp = strrchr(def->name, '/'); if (!tmp || *def->name == '/' || tmp[1] == '\0') { virReportError(VIR_ERR_INTERNAL_ERROR, _("Volume name '%s' doesn't have expected format " "'<directory>/<file>'"), def->name); goto cleanup; } if (! virFileHasSuffix(def->name, ".vmdk")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Volume name '%s' has unsupported suffix, " "expecting '.vmdk'"), def->name); goto cleanup; } if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name, def->name) < 0) goto cleanup; if (def->target.format == VIR_STORAGE_FILE_VMDK) { /* Parse and escape datastore path */ if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL, &unescapedDirectoryName, &unescapedDirectoryAndFileName) < 0) { goto cleanup; } directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName); if (!directoryName) goto cleanup; fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName + strlen(unescapedDirectoryName) + 1); if (!fileName) goto cleanup; if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name, directoryName) < 0) goto cleanup; if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName, fileName) < 0) goto cleanup; /* Create directory, if it doesn't exist yet */ if (esxVI_LookupFileInfoByDatastorePath (priv->primary, datastorePathWithoutFileName, true, &fileInfo, esxVI_Occurrence_OptionalItem) < 0) { goto cleanup; } if (!fileInfo) { if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName, priv->primary->datacenter->_reference, esxVI_Boolean_True) < 0) { goto cleanup; } } /* Create VirtualDisk */ if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 || esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) { goto cleanup; } /* From the vSphere API documentation about VirtualDiskType ... */ if (def->target.allocation == def->target.capacity) { /* * "A preallocated disk has all space allocated at creation time * and the space is zeroed on demand as the space is used." */ virtualDiskSpec->diskType = (char *)"preallocated"; } else if (def->target.allocation == 0) { /* * "Space required for thin-provisioned virtual disk is allocated * and zeroed on demand as the space is used." */ virtualDiskSpec->diskType = (char *)"thin"; } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported capacity-to-allocation relation")); goto cleanup; } /* * FIXME: The adapter type is a required parameter, but there is no * way to let the user specify it in the volume XML config. Therefore, * default to 'busLogic' here. */ virtualDiskSpec->adapterType = (char *)"busLogic"; virtualDiskSpec->capacityKb->value = VIR_DIV_UP(def->target.capacity, 1024); /* Scale from byte to kilobyte */ if (esxVI_CreateVirtualDisk_Task (priv->primary, datastorePath, priv->primary->datacenter->_reference, esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 || esxVI_WaitForTaskCompletion(priv->primary, task, NULL, esxVI_Occurrence_None, priv->parsedUri->autoAnswer, &taskInfoState, &taskInfoErrorMessage) < 0) { goto cleanup; } if (taskInfoState != esxVI_TaskInfoState_Success) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"), taskInfoErrorMessage); goto cleanup; } if (priv->primary->hasQueryVirtualDiskUuid) { if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) goto cleanup; if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath, priv->primary->datacenter->_reference, &uuid_string) < 0) { goto cleanup; } if (esxUtil_ReformatUuid(uuid_string, key) < 0) goto cleanup; } else { /* Fall back to the path as key */ if (VIR_STRDUP(key, datastorePath) < 0) goto cleanup; } } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Creation of %s volumes is not supported"), virStorageFileFormatTypeToString(def->target.format)); goto cleanup; } volume = virGetStorageVol(pool->conn, pool->name, def->name, key, &esxStorageBackendVMFS, NULL); cleanup: if (virtualDiskSpec) { virtualDiskSpec->diskType = NULL; virtualDiskSpec->adapterType = NULL; } virStorageVolDefFree(def); VIR_FREE(unescapedDatastorePath); VIR_FREE(unescapedDirectoryName); VIR_FREE(unescapedDirectoryAndFileName); VIR_FREE(directoryName); VIR_FREE(fileName); VIR_FREE(datastorePathWithoutFileName); VIR_FREE(datastorePath); esxVI_FileInfo_Free(&fileInfo); esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec); esxVI_ManagedObjectReference_Free(&task); VIR_FREE(taskInfoErrorMessage); VIR_FREE(uuid_string); VIR_FREE(key); return volume; }
static virStorageVolPtr esxStorageVolCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc, virStorageVolPtr sourceVolume, unsigned int flags) { virStorageVolPtr volume = NULL; esxPrivate *priv = pool->conn->privateData; virStoragePoolDef poolDef; char *sourceDatastorePath = NULL; virStorageVolDefPtr def = NULL; char *tmp; char *unescapedDatastorePath = NULL; char *unescapedDirectoryName = NULL; char *unescapedDirectoryAndFileName = NULL; char *directoryName = NULL; char *fileName = NULL; char *datastorePathWithoutFileName = NULL; char *datastorePath = NULL; esxVI_FileInfo *fileInfo = NULL; esxVI_ManagedObjectReference *task = NULL; esxVI_TaskInfoState taskInfoState; char *taskInfoErrorMessage = NULL; char *uuid_string = NULL; char *key = NULL; virCheckFlags(0, NULL); memset(&poolDef, 0, sizeof(poolDef)); if (esxLookupVMFSStoragePoolType(priv->primary, pool->name, &poolDef.type) < 0) { goto cleanup; } if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool, sourceVolume->name) < 0) goto cleanup; /* Parse config */ def = virStorageVolDefParseString(&poolDef, xmldesc); if (!def) goto cleanup; if (def->type != VIR_STORAGE_VOL_FILE) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Creating non-file volumes is not supported")); goto cleanup; } /* Validate config */ tmp = strrchr(def->name, '/'); if (!tmp || *def->name == '/' || tmp[1] == '\0') { virReportError(VIR_ERR_INTERNAL_ERROR, _("Volume name '%s' doesn't have expected format " "'<directory>/<file>'"), def->name); goto cleanup; } if (! virFileHasSuffix(def->name, ".vmdk")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Volume name '%s' has unsupported suffix, " "expecting '.vmdk'"), def->name); goto cleanup; } if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name, def->name) < 0) goto cleanup; if (def->target.format == VIR_STORAGE_FILE_VMDK) { /* Parse and escape datastore path */ if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL, &unescapedDirectoryName, &unescapedDirectoryAndFileName) < 0) { goto cleanup; } directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName); if (!directoryName) goto cleanup; fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName + strlen(unescapedDirectoryName) + 1); if (!fileName) goto cleanup; if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name, directoryName) < 0) goto cleanup; if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName, fileName) < 0) goto cleanup; /* Create directory, if it doesn't exist yet */ if (esxVI_LookupFileInfoByDatastorePath (priv->primary, datastorePathWithoutFileName, true, &fileInfo, esxVI_Occurrence_OptionalItem) < 0) { goto cleanup; } if (!fileInfo) { if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName, priv->primary->datacenter->_reference, esxVI_Boolean_True) < 0) { goto cleanup; } } /* Copy VirtualDisk */ if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath, priv->primary->datacenter->_reference, datastorePath, priv->primary->datacenter->_reference, NULL, esxVI_Boolean_False, &task) < 0 || esxVI_WaitForTaskCompletion(priv->primary, task, NULL, esxVI_Occurrence_None, priv->parsedUri->autoAnswer, &taskInfoState, &taskInfoErrorMessage) < 0) { goto cleanup; } if (taskInfoState != esxVI_TaskInfoState_Success) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"), taskInfoErrorMessage); goto cleanup; } if (priv->primary->hasQueryVirtualDiskUuid) { if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) goto cleanup; if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath, priv->primary->datacenter->_reference, &uuid_string) < 0) { goto cleanup; } if (esxUtil_ReformatUuid(uuid_string, key) < 0) goto cleanup; } else { /* Fall back to the path as key */ if (VIR_STRDUP(key, datastorePath) < 0) goto cleanup; } } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Creation of %s volumes is not supported"), virStorageFileFormatTypeToString(def->target.format)); goto cleanup; } volume = virGetStorageVol(pool->conn, pool->name, def->name, key, &esxStorageBackendVMFS, NULL); cleanup: VIR_FREE(sourceDatastorePath); virStorageVolDefFree(def); VIR_FREE(unescapedDatastorePath); VIR_FREE(unescapedDirectoryName); VIR_FREE(unescapedDirectoryAndFileName); VIR_FREE(directoryName); VIR_FREE(fileName); VIR_FREE(datastorePathWithoutFileName); VIR_FREE(datastorePath); esxVI_FileInfo_Free(&fileInfo); esxVI_ManagedObjectReference_Free(&task); VIR_FREE(taskInfoErrorMessage); VIR_FREE(uuid_string); VIR_FREE(key); return volume; }
/** * Probe the header of a file to determine what type of disk image * it is, and info about its capacity if available. */ int virStorageFileGetMetadataFromFD(const char *path, int fd, virStorageFileMetadata *meta) { unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ int len, i; memset(meta, 0, sizeof (*meta)); /* If all else fails, call it a raw file */ meta->format = VIR_STORAGE_FILE_RAW; if ((len = read(fd, head, sizeof(head))) < 0) { virReportSystemError(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(&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(); 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; }