private static void CreateExtent(Stream extentStream, long size, ExtentType type, long descriptorLength, out long descriptorStart) { if (type == ExtentType.Flat || type == ExtentType.Vmfs) { extentStream.SetLength(size); descriptorStart = 0; return; } if (type == ExtentType.Sparse) { CreateSparseExtent(extentStream, size, descriptorLength, out descriptorStart); } else if (type == ExtentType.VmfsSparse) { ServerSparseExtentHeader header = CreateServerSparseExtentHeader(size); extentStream.Position = 0; extentStream.Write(header.GetBytes(), 0, 4 * Sizes.Sector); byte[] blankGlobalDirectory = new byte[header.NumGdEntries * 4]; extentStream.Write(blankGlobalDirectory, 0, blankGlobalDirectory.Length); descriptorStart = 0; } else { throw new NotImplementedException($"Extent type '{ExtentDescriptor.FormatExtentType(type)}' not implemented"); } }
public DiskExtent(ExtentDescriptor descriptor, long diskOffset, FileLocator fileLocator, FileAccess access) { _descriptor = descriptor; _diskOffset = diskOffset; _fileLocator = fileLocator; _access = access; }
/// <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 && _diskType != DiskCreateType.MonolithicSparse) { throw new NotImplementedException("Only MonolithicSparse, 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))); } else if (_diskType == DiskCreateType.MonolithicSparse) { ExtentDescriptor extent = new ExtentDescriptor(ExtentAccess.ReadWrite, Content.Length / 512, ExtentType.Sparse, baseName + ".vmdk", 0); baseDescriptor.Extents.Add(extent); fileSpecs.Add(new DiskImageFileSpecification(baseName + ".vmdk", new MonolithicSparseExtentBuilder(Content, baseDescriptor))); } return(fileSpecs.ToArray()); }
private SparseStream OpenExtent(ExtentDescriptor extent, long extentStart, SparseStream parent, Ownership ownsParent) { FileAccess access = FileAccess.Read; FileShare share = FileShare.Read; if (extent.Access == ExtentAccess.ReadWrite && _access != FileAccess.Read) { access = FileAccess.ReadWrite; share = FileShare.None; } if (extent.Type != ExtentType.Sparse && extent.Type != ExtentType.VmfsSparse) { if (ownsParent == Ownership.Dispose && parent != null) { parent.Dispose(); } } switch (extent.Type) { case ExtentType.Flat: case ExtentType.Vmfs: return(SparseStream.FromStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose)); case ExtentType.Zero: return(new ZeroStream(extent.SizeInSectors * Sizes.Sector)); case ExtentType.Sparse: return(new HostedSparseExtentStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose, extentStart, parent, ownsParent)); case ExtentType.VmfsSparse: return(new ServerSparseExtentStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose, extentStart, parent, ownsParent)); default: throw new NotSupportedException(); } }
private void Load(Stream source) { if (source.Length - source.Position > MaxSize) { throw new IOException(string.Format(CultureInfo.InvariantCulture, "Invalid VMDK descriptor file, more than {0} bytes in length", MaxSize)); } StreamReader reader = new StreamReader(source); string line = reader.ReadLine(); while (line != null) { line = line.Trim('\0'); int commentPos = line.IndexOf('#'); if (commentPos >= 0) { line = line.Substring(0, commentPos); } if (line.Length > 0) { if (line.StartsWith("RW", StringComparison.Ordinal) || line.StartsWith("RDONLY", StringComparison.Ordinal) || line.StartsWith("NOACCESS", StringComparison.Ordinal)) { Extents.Add(ExtentDescriptor.Parse(line)); } else { DescriptorFileEntry entry = DescriptorFileEntry.Parse(line); if (entry.Key.StartsWith("ddb.", StringComparison.Ordinal)) { _diskDataBase.Add(entry); } else { _header.Add(entry); } } } line = reader.ReadLine(); } }
public static ExtentDescriptor Parse(string descriptor) { string[] elems = SplitQuotedString(descriptor); if (elems.Length < 4) { throw new IOException(string.Format(CultureInfo.InvariantCulture, "Invalid extent descriptor: {0}", descriptor)); } ExtentDescriptor result = new ExtentDescriptor(); result._access = ParseAccess(elems[0]); result._sizeInSectors = long.Parse(elems[1], CultureInfo.InvariantCulture); result._type = ParseType(elems[2]); result._fileName = elems[3].Trim('\"'); if (elems.Length > 4) { result._offset = long.Parse(elems[4], CultureInfo.InvariantCulture); } return(result); }
private SparseStream OpenExtent(ExtentDescriptor extent, long extentStart, SparseStream parent, Ownership ownsParent) { FileAccess access = FileAccess.Read; FileShare share = FileShare.Read; if(extent.Access == ExtentAccess.ReadWrite && _access != FileAccess.Read) { access = FileAccess.ReadWrite; share = FileShare.None; } if (extent.Type != ExtentType.Sparse && extent.Type != ExtentType.VmfsSparse) { if (ownsParent == Ownership.Dispose && parent != null) { parent.Dispose(); } } switch (extent.Type) { case ExtentType.Flat: case ExtentType.Vmfs: return SparseStream.FromStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose); case ExtentType.Zero: return new ZeroStream(extent.SizeInSectors * Utilities.SectorSize); case ExtentType.Sparse: return new HostedSparseExtentStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose, extentStart, parent, ownsParent); case ExtentType.VmfsSparse: return new ServerSparseExtentStream( _fileLocator.Open(extent.FileName, FileMode.Open, access, share), Ownership.Dispose, extentStart, parent, ownsParent); default: throw new NotSupportedException(); } }
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); }
public DiskExtent(ExtentDescriptor descriptor, long diskOffset, Stream monolithicStream) { _descriptor = descriptor; _diskOffset = diskOffset; _monolithicStream = monolithicStream; }
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)); }
public static ExtentDescriptor Parse(string descriptor) { string[] elems = SplitQuotedString(descriptor); if (elems.Length < 4) { throw new IOException(string.Format(CultureInfo.InvariantCulture, "Invalid extent descriptor: {0}", descriptor)); } ExtentDescriptor result = new ExtentDescriptor(); result._access = ParseAccess(elems[0]); result._sizeInSectors = long.Parse(elems[1], CultureInfo.InvariantCulture); result._type = ParseType(elems[2]); result._fileName = elems[3].Trim('\"'); if (elems.Length > 4) { result._offset = long.Parse(elems[4], CultureInfo.InvariantCulture); } return result; }
/// <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 && _diskType != DiskCreateType.MonolithicSparse) { throw new NotImplementedException("Only MonolithicSparse, 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))); } else if (_diskType == DiskCreateType.MonolithicSparse) { ExtentDescriptor extent = new ExtentDescriptor(ExtentAccess.ReadWrite, Content.Length / 512, ExtentType.Sparse, baseName + ".vmdk", 0); baseDescriptor.Extents.Add(extent); fileSpecs.Add(new DiskImageFileSpecification(baseName + ".vmdk", new MonolithicSparseExtentBuilder(Content, baseDescriptor))); } return fileSpecs.ToArray(); }