private void LoadDescriptor(Stream s) { s.Position = 0; byte[] header = Utilities.ReadFully(s, (int)Math.Min(Sizes.Sector, s.Length)); if (header.Length < Sizes.Sector || Utilities.ToUInt32LittleEndian(header, 0) != HostedSparseExtentHeader.VmdkMagicNumber) { s.Position = 0; _descriptor = new DescriptorFile(s); if (_access != FileAccess.Read) { _descriptor.ContentId = (uint)_rng.Next(); s.Position = 0; _descriptor.Write(s); s.SetLength(s.Position); } } else { // This is a sparse disk extent, hopefully with embedded descriptor... HostedSparseExtentHeader hdr = HostedSparseExtentHeader.Read(header, 0); if (hdr.DescriptorOffset != 0) { Stream descriptorStream = new SubStream(s, hdr.DescriptorOffset * Sizes.Sector, hdr.DescriptorSize * Sizes.Sector); _descriptor = new DescriptorFile(descriptorStream); if (_access != FileAccess.Read) { _descriptor.ContentId = (uint)_rng.Next(); descriptorStream.Position = 0; _descriptor.Write(descriptorStream); byte[] blank = new byte[descriptorStream.Length - descriptorStream.Position]; descriptorStream.Write(blank, 0, blank.Length); } } } }
/// <summary> /// Creates a new virtual disk at the specified path. /// </summary> /// <param name="fileLocator">The object used to locate / create the component files.</param> /// <param name="path">The name of the VMDK to create.</param> /// <param name="parameters">The desired parameters for the new disk.</param> /// <returns>The newly created disk image</returns> internal static DiskImageFile Initialize(FileLocator fileLocator, string path, DiskParameters parameters) { if (parameters.Capacity <= 0) { throw new ArgumentException("Capacity must be greater than zero", "parameters"); } Geometry geometry = parameters.Geometry ?? DefaultGeometry(parameters.Capacity); Geometry biosGeometry; if (parameters.BiosGeometry != null) { biosGeometry = parameters.BiosGeometry; } else { biosGeometry = Geometry.MakeBiosSafe(geometry, parameters.Capacity); } DiskAdapterType adapterType = (parameters.AdapterType == DiskAdapterType.None) ? DiskAdapterType.LsiLogicScsi : parameters.AdapterType; DiskCreateType createType = (parameters.CreateType == DiskCreateType.None) ? DiskCreateType.MonolithicSparse : parameters.CreateType; DescriptorFile baseDescriptor = CreateSimpleDiskDescriptor(geometry, biosGeometry, createType, adapterType); return(DoInitialize(fileLocator, path, parameters.Capacity, createType, baseDescriptor)); }
private static DescriptorFile CreateDifferencingDiskDescriptor(DiskCreateType type, DiskImageFile parent, string parentPath) { DescriptorFile baseDescriptor = new DescriptorFile(); baseDescriptor.ContentId = (uint)_rng.Next(); baseDescriptor.ParentContentId = parent.ContentId; baseDescriptor.ParentFileNameHint = parentPath; baseDescriptor.CreateType = type; return(baseDescriptor); }
internal static DescriptorFile CreateSimpleDiskDescriptor(Geometry geometry, Geometry biosGeometery, DiskCreateType createType, DiskAdapterType adapterType) { DescriptorFile baseDescriptor = new DescriptorFile(); baseDescriptor.DiskGeometry = geometry; baseDescriptor.BiosGeometry = biosGeometery; baseDescriptor.ContentId = (uint)_rng.Next(); baseDescriptor.CreateType = createType; baseDescriptor.UniqueId = Guid.NewGuid(); baseDescriptor.HardwareVersion = "4"; baseDescriptor.AdapterType = adapterType; return(baseDescriptor); }
/// <summary> /// Initiates the build process. /// </summary> /// <param name="baseName">The base name for the VMDK, for example 'foo' to create 'foo.vmdk'.</param> /// <returns>A set of one or more logical files that constitute the VMDK. The first file is /// the 'primary' file that is normally attached to VMs.</returns> public override DiskImageFileSpecification[] Build(string baseName) { if (string.IsNullOrEmpty(baseName)) { throw new ArgumentException("Invalid base file name", "baseName"); } if (Content == null) { throw new InvalidOperationException("No content stream specified"); } if (_diskType != DiskCreateType.Vmfs && _diskType != DiskCreateType.VmfsSparse) { throw new NotImplementedException("Only Vmfs and VmfsSparse disks implemented"); } List <DiskImageFileSpecification> fileSpecs = new List <DiskImageFileSpecification>(); Geometry geometry = Geometry ?? DiskImageFile.DefaultGeometry(Content.Length); Geometry biosGeometry = BiosGeometry ?? Geometry.LbaAssistedBiosGeometry(Content.Length); DescriptorFile baseDescriptor = DiskImageFile.CreateSimpleDiskDescriptor(geometry, biosGeometry, _diskType, _adapterType); if (_diskType == DiskCreateType.Vmfs) { ExtentDescriptor extent = new ExtentDescriptor(ExtentAccess.ReadWrite, Content.Length / 512, ExtentType.Vmfs, baseName + "-flat.vmdk", 0); baseDescriptor.Extents.Add(extent); MemoryStream ms = new MemoryStream(); baseDescriptor.Write(ms); fileSpecs.Add(new DiskImageFileSpecification(baseName + ".vmdk", new PassthroughStreamBuilder(ms))); fileSpecs.Add(new DiskImageFileSpecification(baseName + "-flat.vmdk", new PassthroughStreamBuilder(Content))); } else if (_diskType == DiskCreateType.VmfsSparse) { ExtentDescriptor extent = new ExtentDescriptor(ExtentAccess.ReadWrite, Content.Length / 512, ExtentType.VmfsSparse, baseName + "-sparse.vmdk", 0); baseDescriptor.Extents.Add(extent); MemoryStream ms = new MemoryStream(); baseDescriptor.Write(ms); fileSpecs.Add(new DiskImageFileSpecification(baseName + ".vmdk", new PassthroughStreamBuilder(ms))); fileSpecs.Add(new DiskImageFileSpecification(baseName + "-sparse.vmdk", new VmfsSparseExtentBuilder(Content))); } return(fileSpecs.ToArray()); }
/// <summary> /// Creates a new virtual disk that is a linked clone of an existing disk. /// </summary> /// <param name="path">The path to the new disk</param> /// <param name="type">The type of the new disk</param> /// <param name="parent">The disk to clone</param> /// <returns>The new virtual disk</returns> public static DiskImageFile InitializeDifferencing(string path, DiskCreateType type, string parent) { if (type != DiskCreateType.MonolithicSparse && type != DiskCreateType.TwoGbMaxExtentSparse && type != DiskCreateType.VmfsSparse) { throw new ArgumentException("Differencing disks must be sparse", "type"); } using (DiskImageFile parentFile = new DiskImageFile(parent, FileAccess.Read)) { DescriptorFile baseDescriptor = CreateDifferencingDiskDescriptor(type, parentFile, parent); FileLocator locator = new LocalFileLocator(Path.GetDirectoryName(path)); return(DoInitialize(locator, Path.GetFileName(path), parentFile.Capacity, type, baseDescriptor)); } }
/// <summary> /// Creates a new virtual disk that is a linked clone of an existing disk. /// </summary> /// <param name="fileSystem">The file system to create the VMDK on</param> /// <param name="path">The path to the new disk</param> /// <param name="type">The type of the new disk</param> /// <param name="parent">The disk to clone</param> /// <returns>The new virtual disk</returns> public static DiskImageFile InitializeDifferencing(DiscFileSystem fileSystem, string path, DiskCreateType type, string parent) { if (type != DiskCreateType.MonolithicSparse && type != DiskCreateType.TwoGbMaxExtentSparse && type != DiskCreateType.VmfsSparse) { throw new ArgumentException("Differencing disks must be sparse", "type"); } string basePath = Utilities.GetDirectoryFromPath(path); FileLocator locator = new DiscFileLocator(fileSystem, basePath); FileLocator parentLocator = locator.GetRelativeLocator(Utilities.GetDirectoryFromPath(parent)); using (DiskImageFile parentFile = new DiskImageFile(parentLocator, Utilities.GetFileFromPath(parent), FileAccess.Read)) { DescriptorFile baseDescriptor = CreateDifferencingDiskDescriptor(type, parentFile, parent); return(DoInitialize(locator, Utilities.GetFileFromPath(path), parentFile.Capacity, type, baseDescriptor)); } }
private static DiskImageFile DoInitialize(FileLocator fileLocator, string file, long capacity, DiskCreateType type, DescriptorFile baseDescriptor) { if (type == DiskCreateType.MonolithicSparse) { // MonolithicSparse is a special case, the descriptor is embedded in the file itself... using (Stream fs = fileLocator.Open(file, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { long descriptorStart; CreateExtent(fs, capacity, ExtentType.Sparse, 10 * Sizes.OneKiB, out descriptorStart); ExtentDescriptor extent = new ExtentDescriptor(ExtentAccess.ReadWrite, capacity / Sizes.Sector, ExtentType.Sparse, file, 0); fs.Position = descriptorStart * Sizes.Sector; baseDescriptor.Extents.Add(extent); baseDescriptor.Write(fs); } } else { ExtentType extentType = CreateTypeToExtentType(type); long totalSize = 0; List <ExtentDescriptor> extents = new List <ExtentDescriptor>(); if (type == DiskCreateType.MonolithicFlat || type == DiskCreateType.VmfsSparse || type == DiskCreateType.Vmfs) { string adornment = "flat"; if (type == DiskCreateType.VmfsSparse) { adornment = string.IsNullOrEmpty(baseDescriptor.ParentFileNameHint) ? "sparse" : "delta"; } string fileName = AdornFileName(file, adornment); using (Stream fs = fileLocator.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { CreateExtent(fs, capacity, extentType); extents.Add(new ExtentDescriptor(ExtentAccess.ReadWrite, capacity / Sizes.Sector, extentType, fileName, 0)); totalSize = capacity; } } else if (type == DiskCreateType.TwoGbMaxExtentFlat || type == DiskCreateType.TwoGbMaxExtentSparse) { int i = 1; while (totalSize < capacity) { string adornment; if (type == DiskCreateType.TwoGbMaxExtentSparse) { adornment = string.Format(CultureInfo.InvariantCulture, "s{0:x3}", i); } else { adornment = string.Format(CultureInfo.InvariantCulture, "{0:x6}", i); } string fileName = AdornFileName(file, adornment); using (Stream fs = fileLocator.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { long extentSize = Math.Min((2 * Sizes.OneGiB) - Sizes.OneMiB, capacity - totalSize); CreateExtent(fs, extentSize, extentType); extents.Add(new ExtentDescriptor(ExtentAccess.ReadWrite, extentSize / Sizes.Sector, extentType, fileName, 0)); totalSize += extentSize; } ++i; } } else { throw new NotSupportedException("Creating disks of this type is not supported"); } using (Stream fs = fileLocator.Open(file, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { baseDescriptor.Extents.AddRange(extents); baseDescriptor.Write(fs); } } return(new DiskImageFile(fileLocator, file, FileAccess.ReadWrite)); }