// // Copyright (c) 2008-2011, Kenneth Bell // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // using System; using System.Globalization; using DiscUtils.Partitions; using DiscUtils.Streams; namespace DiscUtils { /// /// Information about a physical disk volume, which may be a partition or an entire disk. /// public sealed class PhysicalVolumeInfo : VolumeInfo { private readonly VirtualDisk _disk; private readonly string _diskId; private readonly SparseStreamOpenDelegate _streamOpener; /// /// Initializes a new instance of the PhysicalVolumeInfo class. /// /// The containing disk's identity. /// The disk containing the partition. /// Information about the partition. /// Use this constructor to represent a (BIOS or GPT) partition. internal PhysicalVolumeInfo( string diskId, VirtualDisk disk, PartitionInfo partitionInfo) { _diskId = diskId; _disk = disk; _streamOpener = partitionInfo.Open; VolumeType = partitionInfo.VolumeType; Partition = partitionInfo; } /// /// Initializes a new instance of the PhysicalVolumeInfo class. /// /// The identity of the disk. /// The disk itself. /// Use this constructor to represent an entire disk as a single volume. internal PhysicalVolumeInfo( string diskId, VirtualDisk disk) { _diskId = diskId; _disk = disk; _streamOpener = delegate { return new SubStream(disk.Content, Ownership.None, 0, disk.Capacity); }; VolumeType = PhysicalVolumeType.EntireDisk; } /// /// Gets the disk geometry of the underlying storage medium (as used in BIOS calls), may be null. /// public override Geometry BiosGeometry { get { return _disk.BiosGeometry; } } /// /// Gets the one-byte BIOS type for this volume, which indicates the content. /// public override byte BiosType { get { return Partition == null ? (byte)0 : Partition.BiosType; } } /// /// Gets the unique identity of the disk containing the volume, if known. /// public Guid DiskIdentity { get { return VolumeType != PhysicalVolumeType.EntireDisk ? _disk.Partitions.DiskGuid : Guid.Empty; } } /// /// Gets the signature of the disk containing the volume (only valid for partition-type volumes). /// public int DiskSignature { get { return VolumeType != PhysicalVolumeType.EntireDisk ? _disk.Signature : 0; } } /// /// Gets the stable identity for this physical volume. /// /// The stability of the identity depends the disk structure. /// In some cases the identity may include a simple index, when no other information /// is available. Best practice is to add disks to the Volume Manager in a stable /// order, if the stability of this identity is paramount. public override string Identity { get { if (VolumeType == PhysicalVolumeType.GptPartition) { return "VPG" + PartitionIdentity.ToString("B"); } string partId; switch (VolumeType) { case PhysicalVolumeType.EntireDisk: partId = "PD"; break; case PhysicalVolumeType.BiosPartition: case PhysicalVolumeType.ApplePartition: partId = "PO" + (Partition.FirstSector * _disk.SectorSize).ToString("X", CultureInfo.InvariantCulture); break; default: partId = "P*"; break; } return "VPD:" + _diskId + ":" + partId; } } /// /// Gets the size of the volume, in bytes. /// public override long Length { get { return Partition == null ? _disk.Capacity : Partition.SectorCount * _disk.SectorSize; } } /// /// Gets the underlying partition (if any). /// public PartitionInfo Partition { get; } /// /// Gets the unique identity of the physical partition, if known. /// public Guid PartitionIdentity { get { GuidPartitionInfo gpi = Partition as GuidPartitionInfo; if (gpi != null) { return gpi.Identity; } return Guid.Empty; } } /// /// Gets the disk geometry of the underlying storage medium, if any (may be null). /// public override Geometry PhysicalGeometry { get { return _disk.Geometry; } } /// /// Gets the offset of this volume in the underlying storage medium, if any (may be Zero). /// public override long PhysicalStartSector { get { return VolumeType == PhysicalVolumeType.EntireDisk ? 0 : Partition.FirstSector; } } /// /// Gets the type of the volume. /// public PhysicalVolumeType VolumeType { get; } /// /// Opens the volume, providing access to its contents. /// /// A stream that can be used to access the volume. public override SparseStream Open() { return _streamOpener(); } } }