// // 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.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using DiscUtils.CoreCompat; using DiscUtils.Raw; using DiscUtils.Streams; namespace DiscUtils.Partitions { /// /// Base class for classes which represent a disk partitioning scheme. /// /// After modifying the table, by creating or deleting a partition assume that any /// previously stored partition indexes of higher value are no longer valid. Re-enumerate /// the partitions to discover the next index-to-partition mapping. public abstract class PartitionTable { private static List _factories; /// /// Gets the number of User partitions on the disk. /// public int Count { get { return Partitions.Count; } } /// /// Gets the GUID that uniquely identifies this disk, if supported (else returns null). /// public abstract Guid DiskGuid { get; } private static List Factories { get { if (_factories == null) { List factories = new List(); foreach (Type type in ReflectionHelper.GetAssembly(typeof(VolumeManager)).GetTypes()) { foreach (PartitionTableFactoryAttribute attr in ReflectionHelper.GetCustomAttributes(type, typeof(PartitionTableFactoryAttribute), false)) { factories.Add((PartitionTableFactory)Activator.CreateInstance(type)); } } _factories = factories; } return _factories; } } /// /// Gets information about a particular User partition. /// /// The index of the partition. /// Information about the partition. public PartitionInfo this[int index] { get { return Partitions[index]; } } /// /// Gets the list of partitions that contain user data (i.e. non-system / empty). /// public abstract ReadOnlyCollection Partitions { get; } /// /// Determines if a disk is partitioned with a known partitioning scheme. /// /// The content of the disk to check. /// true if the disk is partitioned, else false. public static bool IsPartitioned(Stream content) { foreach (PartitionTableFactory partTableFactory in Factories) { if (partTableFactory.DetectIsPartitioned(content)) { return true; } } return false; } /// /// Determines if a disk is partitioned with a known partitioning scheme. /// /// The disk to check. /// true if the disk is partitioned, else false. public static bool IsPartitioned(VirtualDisk disk) { return IsPartitioned(disk.Content); } /// /// Gets all of the partition tables found on a disk. /// /// The disk to inspect. /// It is rare for a disk to have multiple partition tables, but theoretically /// possible. public static IList GetPartitionTables(VirtualDisk disk) { List tables = new List(); foreach (PartitionTableFactory factory in Factories) { PartitionTable table = factory.DetectPartitionTable(disk); if (table != null) { tables.Add(table); } } return tables; } /// /// Gets all of the partition tables found on a disk. /// /// The content of the disk to inspect. /// It is rare for a disk to have multiple partition tables, but theoretically /// possible. public static IList GetPartitionTables(Stream contentStream) { return GetPartitionTables(new Disk(contentStream, Ownership.None)); } /// /// Creates a new partition that encompasses the entire disk. /// /// The partition type. /// Whether the partition is active (bootable). /// The index of the partition. /// The partition table must be empty before this method is called, /// otherwise IOException is thrown. public abstract int Create(WellKnownPartitionType type, bool active); /// /// Creates a new partition with a target size. /// /// The target size (in bytes). /// The partition type. /// Whether the partition is active (bootable). /// The index of the new partition. public abstract int Create(long size, WellKnownPartitionType type, bool active); /// /// Creates a new aligned partition that encompasses the entire disk. /// /// The partition type. /// Whether the partition is active (bootable). /// The alignment (in byte). /// The index of the partition. /// The partition table must be empty before this method is called, /// otherwise IOException is thrown. /// /// Traditionally partitions were aligned to the physical structure of the underlying disk, /// however with modern storage greater efficiency is acheived by aligning partitions on /// large values that are a power of two. /// public abstract int CreateAligned(WellKnownPartitionType type, bool active, int alignment); /// /// Creates a new aligned partition with a target size. /// /// The target size (in bytes). /// The partition type. /// Whether the partition is active (bootable). /// The alignment (in byte). /// The index of the new partition. /// /// Traditionally partitions were aligned to the physical structure of the underlying disk, /// however with modern storage greater efficiency is achieved by aligning partitions on /// large values that are a power of two. /// public abstract int CreateAligned(long size, WellKnownPartitionType type, bool active, int alignment); /// /// Deletes a partition at a given index. /// /// The index of the partition. public abstract void Delete(int index); } }