Exemple #1
0
        private void CreateVhdx(bool allowKeepDebug, long length)
        {
            var diskStream = CreateVhdxStream(allowKeepDebug);

            Disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, length, 128 << 20);
            var gpt = GuidPartitionTable.Initialize(Disk);

            gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null);
            var  volume         = VolumeManager.GetPhysicalVolumes(Disk).First();
            uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512);
            var  clusterCount   = 1 << 25;
            var  clusterSize    = length / clusterCount;
            var  clusterBits    = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2));

            if (clusterBits > 18)
            {
                clusterBits = 18;
            }
            else if (clusterBits < 11)
            {
                clusterBits = 11;
            }
            FileSystem = ExFatEntryFilesystem.Format(volume.Open(),
                                                     new ExFatFormatOptions {
                SectorsPerCluster = (1u << clusterBits) / bytesPerSector
            });
        }
Exemple #2
0
        public static void Main4(string[] args)
        {
            string label     = "Zap!";
            long   capacity  = 2L << 40;
            int    blockSize = 4 << 20;

            using (var diskStream = File.Create("big.vhdx"))
                using (var disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, capacity, blockSize))
                {
                    var gpt = GuidPartitionTable.Initialize(disk);
                    gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null);
                    var  volume         = VolumeManager.GetPhysicalVolumes(disk).First();
                    uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512);
                    var  clusterCount   = 1 << 25;// uint.MaxValue - 16;
                    var  clusterSize    = capacity / clusterCount;
                    var  clusterBits    = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2));
                    if (clusterBits > 18)
                    {
                        clusterBits = 18;
                    }
                    //clusterBits = 20;
                    using (var fs = ExFatFileSystem.Format(volume, new ExFatFormatOptions {
                        SectorsPerCluster = (1u << clusterBits) / bytesPerSector
                    }, label: label))
                    { }
                }
        }
        public void Initialize()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                Assert.Equal(0, table.Count);
            }
        }
Exemple #4
0
        private static void CreateVirtualDisk(string filePath, int size)
        {
            using (FileStream fsStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                using (VirtualDisk disk = DiscUtils.Vhd.Disk.InitializeDynamic(fsStream, DiscUtils.Streams.Ownership.Dispose, size * 1024 * 1024))
                {
                    GuidPartitionTable.Initialize(disk, WellKnownPartitionType.WindowsNtfs);

                    PhysicalVolumeInfo volume = VolumeManager.GetPhysicalVolumes(disk)[0];

                    NtfsFileSystem.Format(volume, "CryptoBox");
                }
        }
        public void CreateSmallWholeDisk()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                int idx = table.Create(WellKnownPartitionType.WindowsFat, true);

                // Make sure the partition fills from first to last usable.
                Assert.Equal(table.FirstUsableSector, table[idx].FirstSector);
                Assert.Equal(table.LastUsableSector, table[idx].LastSector);
            }
        }
        public void CreateBySize()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                int idx = table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false);

                // Make sure the partition is within 10% of the size requested.
                Assert.True((2 * 1024 * 2) * 0.9 < table[idx].SectorCount);

                Assert.Equal(table.FirstUsableSector, table[idx].FirstSector);
            }
        }
        public void CreateLargeWholeDisk()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                int idx = table.Create(WellKnownPartitionType.WindowsFat, true);

                Assert.Equal(2, table.Partitions.Count);
                Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType);
                Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512);

                // Make sure the partition fills from first to last usable, allowing for MicrosoftReserved sector.
                Assert.Equal(table[0].LastSector + 1, table[idx].FirstSector);
                Assert.Equal(table.LastUsableSector, table[idx].LastSector);
            }
        }
        public void CreateBySizeInGap()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 300 * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                table.Create(10 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false);

                table.Create((20 * 1024 * 1024) / 512, ((30 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition");

                table.Create((60 * 1024 * 1024) / 512, ((70 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition");

                int idx = table.Create(20 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false);
                Assert.Equal(((30 * 1024 * 1024) / 512), table[idx].FirstSector);
                Assert.Equal(((50 * 1024 * 1024) / 512) - 1, table[idx].LastSector);
            }
        }
        public void Delete()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 10 * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                Assert.Equal(0, table.Create(1 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false));
                Assert.Equal(1, table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false));
                Assert.Equal(2, table.Create(3 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false));

                long[] sectorCount = new long[] { table[0].SectorCount, table[1].SectorCount, table[2].SectorCount };

                table.Delete(1);

                Assert.Equal(2, table.Count);
                Assert.Equal(sectorCount[2], table[1].SectorCount);
            }
        }
        public void DeviceValue_Gpt()
        {
            SparseMemoryStream ms = new SparseMemoryStream();

            ms.SetLength(80 * 1024 * 1024);
            GuidPartitionTable gpt = GuidPartitionTable.Initialize(ms, Geometry.FromCapacity(ms.Length));

            gpt.Create(WellKnownPartitionType.WindowsNtfs, true);
            VolumeManager volMgr = new VolumeManager(ms);

            RegistryHive hive = RegistryHive.Create(new MemoryStream());
            Store        s    = Store.Initialize(hive.Root);
            BcdObject    obj  = s.CreateInherit(InheritType.AnyObject);

            Element el = obj.AddElement(WellKnownElement.LibraryApplicationDevice, ElementValue.ForDevice(Guid.Empty, volMgr.GetPhysicalVolumes()[0]));

            el = obj.GetElement(WellKnownElement.LibraryApplicationDevice);

            Assert.IsNotNullOrEmpty(el.Value.ToString());
        }
        public void CreateAlignedWholeDisk()
        {
            MemoryStream ms = new MemoryStream();

            using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024))
            {
                GuidPartitionTable table = GuidPartitionTable.Initialize(disk);

                int idx = table.CreateAligned(WellKnownPartitionType.WindowsFat, true, 1024 * 1024);

                Assert.Equal(2, table.Partitions.Count);
                Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType);
                Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512);

                // Make sure the partition is aligned
                Assert.Equal(0, table[idx].FirstSector % 2048);
                Assert.Equal(0, (table[idx].LastSector + 1) % 2048);

                // Ensure partition fills most of the disk
                Assert.True((table[idx].SectorCount * 512) > disk.Capacity * 0.9);
            }
        }
Exemple #12
0
        private static int StartInternal()
        {
            if (!GuidPartitionTable.Detect(mSourceStream))
            {
                throw new InvalidDataException(
                          "Source does not contain a supported partitioning scheme");
            }

            Logger.Debug("Detecting disc geometry of source...");
            var geometry = GuidPartitionTable.DetectGeometry(mSourceStream);

            Logger.Debug("Reading GPT partition table from source...");
            var partitionTable = new GuidPartitionTable(mSourceStream, geometry);

            if (partitionTable.Count <= 0)
            {
                return(SUCCESS); // nothing to clone here
            }
            // adjust source length
            if (FixedLengthStream.IsFixedDiskStream(mSourceStream))
            {
                mSourceStream.SetLength(geometry.Capacity);
            }

            Geometry destGeometry = null;

            if (FixedLengthStream.IsFixedDiskStream(mDestinationStream))
            {
                // If we write to a disk, we need our own geometry for that destination
                destGeometry = Geometry.FromCapacity(mDestinationStream.Length,
                                                     geometry.BytesPerSector);
            }
            else
            {
                // If we are just writing to a file, we take the most exact copy we get
                destGeometry = geometry;
            }

            // Set the new size of the destination stream
            Logger.Verbose("Updating length of destination: {0} -> {1}",
                           mDestinationStream.Length, destGeometry.Capacity);
            mDestinationStream.SetLength(destGeometry.Capacity);

            if (mFullClone)
            {
                Logger.Warn("Starting full clone...");
                CloneStream(0, 0, mSourceStream, mDestinationStream);
                return(SUCCESS);
            }

            Logger.Debug("Initializing new GPT partition table on destination...");
            var destPartitionTable = GuidPartitionTable.Initialize(mDestinationStream,
                                                                   destGeometry);

            var availableSpace = destGeometry.Capacity;
            var usedSpace      = 0L;

            // correct available space by remove unusable sectors
            // heading sectors
            availableSpace -= (destPartitionTable.FirstUsableSector
                               * destGeometry.BytesPerSector);

            // ending sectors
            availableSpace -= ((destGeometry.TotalSectorsLong
                                - destPartitionTable.FirstUsableSector
                                - destPartitionTable.LastUsableSector)
                               * destGeometry.BytesPerSector);

            // 1. calculate unresizeable space if we are required too
            if (destGeometry.Capacity < geometry.Capacity)
            {
                Logger.Info("Calculating space for new destination partitions...");

                var unresizeableSpace = 0L;
                for (int i = 0; i < partitionTable.Count; i++)
                {
                    var srcPartition       = (GuidPartitionInfo)partitionTable[i];
                    var srcPartitionStream = srcPartition.Open();
                    var srcPartitionType   = GetWellKnownPartitionType(srcPartition);
                    var srcPartitionSize   = srcPartition.SectorCount *
                                             geometry.BytesPerSector;

                    var isResizeable = true;

                    // If the file system is not support, we have to perform
                    // a byte-for-byte cloning and cannot resize this partition
                    if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream))
                    {
                        Logger.Verbose("Partition{0}: contains no or unsupported file system");
                        isResizeable = false;
                    }

                    // If we have a critical partition, we shouldn't resize that either
                    if (!IsSupportedPartitionType(srcPartitionType))
                    {
                        Logger.Verbose("Partition{0}: unsupported partition type");
                        isResizeable = false;
                    }

                    // if caller want to do a byte-for-byte clone, mark every partition
                    // as unresizeable
                    if (mForceExactCloning)
                    {
                        isResizeable = false;
                    }

                    Logger.Debug("Partition #{0} on source: isResizeable={1}", i,
                                 isResizeable);

                    if (!isResizeable)
                    {
                        // if it's not resizeable, account the space and continue
                        unresizeableSpace += srcPartitionSize;
                        Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " +
                                     "(total unresizable {2}/used {3})", i,
                                     srcPartitionSize, unresizeableSpace, usedSpace);
                    }
                    else
                    {
                        // if it is resizeable, we have to report how much space we need
                        var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream);
                        usedSpace += srcPartitionFS.UsedSpace;

                        Logger.Debug("Partition #{0} on source: resizeable, space is {1} " +
                                     "(total unresizable {2}/used {3})", i,
                                     usedSpace, unresizeableSpace, usedSpace);
                    }
                }

                // reduce the dynamically available space ...
                availableSpace -= unresizeableSpace;

                // ... and assert it
                if (availableSpace < 0)
                {
                    throw new InvalidOperationException("Cannot clone, destination is " +
                                                        String.Format("{0:#,##0}", -availableSpace) + " Bytes too small");
                }

                // assert the used space too
                if (availableSpace - usedSpace < 0)
                {
                    throw new InvalidOperationException("Cannot clone, destination is " +
                                                        String.Format("{0:#,##0}", availableSpace - usedSpace) +
                                                        " Bytes too small");
                }
            }
            else
            {
                Logger.Info("Destination can contain source, no need to resize partitions!");
            }

            // 2. calculate the size for each new partition
            var destPartitionSizes = new long[partitionTable.Count];

            for (int i = 0; i < partitionTable.Count; i++)
            {
                var srcPartition       = (GuidPartitionInfo)partitionTable[i];
                var srcPartitionStream = srcPartition.Open();
                var srcPartitionType   = GetWellKnownPartitionType(srcPartition);
                var srcPartitionSize   = srcPartition.SectorCount *
                                         geometry.BytesPerSector;

                // if the destination can take more data, skip every check
                if (geometry.Capacity <= destGeometry.Capacity)
                {
                    Logger.Debug("Partition{0}: Destination can contain full partition, continue...", i);

                    destPartitionSizes[i] = srcPartitionSize;
                    availableSpace       -= srcPartitionSize;
                    continue;
                }

                var isResizeable = true;

                // If the device-systme is not support, we have to perform
                // a byte-for-byte cloning and cannot resize this partition
                if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream))
                {
                    isResizeable = false;
                }

                // If we have a critical partition, we shouldn't resize that either
                if (!IsSupportedPartitionType(srcPartitionType))
                {
                    isResizeable = false;
                }

                // if caller want to do a byte-for-byte clone, mark every partition
                // as unresizeable
                if (mForceExactCloning)
                {
                    isResizeable = false;
                }

                Logger.Debug("Partition #{0} on source: isResizeable={1}", i,
                             isResizeable);

                // If our friend is not resizeable, set size and stop processing it
                if (!isResizeable)
                {
                    destPartitionSizes[i] = srcPartitionSize;
                    Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " +
                                 "(total available {2}/used {3})", i,
                                 usedSpace, availableSpace, usedSpace);

                    // DO NOT ALIGN <availableSpace> HERE!!!
                    // Has already been done in step 1
                    continue;
                }

                //
                // OK. If we are here, a resizeable partition awaits processing
                //
                var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream);

                // First we need to check if we need to reqsize the current partition.
                // For that, calculate the space that is left for future partitions. If the
                // result is OK (less or equal to the available size), we can skip
                // resizing the the current one.
                // Make sure to remove the factor of this partition from usedSpace first
                if (((usedSpace - srcPartitionFS.UsedSpace) + srcPartitionSize) <= availableSpace)
                {
                    // update usedSpace
                    usedSpace -= srcPartitionFS.UsedSpace;

                    // align availableSpace
                    availableSpace -= srcPartitionSize;

                    // we are good to skip resizing this one. assign size and early exit
                    destPartitionSizes[i] = srcPartitionSize;
                    Logger.Debug(
                        "Partition #{0} on source: resizeable, space is {1}, size is {2} " +
                        "(total available {3}/used {4})", i,
                        srcPartitionFS.UsedSpace, srcPartitionSize, availableSpace, usedSpace);

                    continue;
                }

                // So this partition is too large, let's resize it to the biggest size possible
                var maxPartitionSize = Math.Max(
                    // Occupied space is the absolute minimal space we need
                    srcPartitionFS.UsedSpace,

                    // This is the largest space possible. Take the still available space
                    // and remove still required space, while also remove the factor for
                    // the current partition
                    availableSpace - (usedSpace - srcPartitionFS.UsedSpace)
                    );

                Logger.Debug(
                    "Partition #{0} on source: resizeable, max. space is {1} " +
                    "(total available {2}/used {3})", i,
                    maxPartitionSize, availableSpace, usedSpace);

                // update usedSpace
                usedSpace -= srcPartitionFS.UsedSpace;

                // align availableSpace
                availableSpace -= maxPartitionSize;

                destPartitionSizes[i] = maxPartitionSize;
            }

            // a last assert of the available space, just to be sure
            if (availableSpace < 0)
            {
                throw new InvalidOperationException("Cannot clone, destination is " +
                                                    String.Format("{0:#.##0}", -availableSpace) + " Bytes too small");
            }

            // 2. create the new partitions with the aligned sizes
            for (int i = 0; i < partitionTable.Count; i++)
            {
                var srcPartition       = (GuidPartitionInfo)partitionTable[i];
                var srcPartitionStream = srcPartition.Open();
                var srcPartitionType   = GetWellKnownPartitionType(srcPartition);

                // manueal type adjusting
                if (NtfsFileSystem.Detect(srcPartitionStream))
                {
                    srcPartitionType = WellKnownPartitionType.WindowsNtfs;
                }
                else if (FatFileSystem.Detect(srcPartitionStream))
                {
                    srcPartitionType = WellKnownPartitionType.WindowsFat;
                }

                var destPartitionSize = destPartitionSizes[i];

                Logger.Debug("Creating partition table: #{0}; {1}/{2}@0x{3}-{4}", i,
                             srcPartition.Name, srcPartition.Identity,
                             srcPartition.FirstSector.ToString("X2"), destPartitionSize);
                destPartitionTable.Create(
                    destPartitionSize,
                    srcPartitionType,
                    true //doesn't matter on GPT tables
                    );
            }

            // 3. make sure the count of partitions is the same
            if (partitionTable.Count != destPartitionTable.Count)
            {
                throw new InvalidOperationException(
                          "Failed to create proper GUID partition table");
            }

            // 4. do the real cloning
            for (int i = 0; i < destPartitionTable.Count; i++)
            {
                var srcPartition       = (GuidPartitionInfo)partitionTable[i];
                var srcPartitionStream = srcPartition.Open();
                var srcPartitionType   = GetWellKnownPartitionType(srcPartition);

                var destPartition       = (GuidPartitionInfo)destPartitionTable[i];
                var destPartitionStream = destPartition.Open();
                var destPartitionSize   = destPartitionSizes[i];

                var requiresExactCloning = false;

                // To support all possible file-systems, perform a byte-for-byte
                // cloning if the file-system is not supported by us.
                if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream))
                {
                    requiresExactCloning = true;
                }

                // If we have a critical partition, we should skip that one too
                if (srcPartitionType == WellKnownPartitionType.BiosBoot ||
                    srcPartitionType == WellKnownPartitionType.EfiSystem ||
                    srcPartitionType == WellKnownPartitionType.MicrosoftReserved)
                {
                    requiresExactCloning = true;
                }

                // if caller want to do a byte-for-byte clone, let's enable it
                if (mForceExactCloning)
                {
                    requiresExactCloning = true;
                }

                if (requiresExactCloning)
                {
                    var taskId = (mTaskIdCounter++);
                    Logger.Info("[{0}/{1}] cp-fs  : {2}/{3}@0x{4}", i, taskId,
                                srcPartition.Name, srcPartition.Identity,
                                srcPartition.FirstSector.ToString("X2"));

                    CloneStream(i, taskId, srcPartitionStream, destPartitionStream);
                }
                else
                {
                    var srcPartitionFS       = DiscHandler.GetFileSystem(srcPartitionStream);
                    var srcPartitionBootCode = srcPartitionFS.ReadBootCode();

                    var destPartitionFS = DiscHandler.FormatFileSystemWithTemplate(
                        srcPartitionStream, destPartitionStream, destPartition.FirstSector,
                        destPartition.SectorCount, destPartitionSize
                        );

                    // Tracks all NTFS file IDs for hard link recognition
                    // <Source FS File ID, Destination FS File ID>
                    var ntfsHardlinkTracker = new Dictionary <uint, uint>();

                    // last clone each single with here
                    Action <DiscDirectoryInfo, DiscDirectoryInfo> cloneSrcFsToDestFs = null;
                    cloneSrcFsToDestFs = new Action <DiscDirectoryInfo, DiscDirectoryInfo>(
                        (sourceDir, destDir) =>
                    {
                        // recursive enumeration. save to create directory without checks for
                        // parent directories.
                        var taskId = (mTaskIdCounter++);
                        Logger.Info("[{0}/{1}] mk-dir : {2}", i, taskId, destDir.FullName);

                        destDir.Create();

                        // copy files if there are any
                        foreach (var sourceFile in sourceDir.GetFiles())
                        {
                            var skipCopying = false;
                            taskId          = (mTaskIdCounter++);

                            var sourceFileStream = sourceFile.Open(FileMode.Open,
                                                                   FileAccess.Read);

                            var destFileName = Path.Combine(destDir.FullName, sourceFile.Name);
                            Logger.Info("[{0}/{1}] mk-file: {2}", i, taskId,
                                        destFileName);

                            var destFileStream = destPartitionFS.OpenFile(
                                destFileName,
                                FileMode.Create, FileAccess.Write);
                            var destFile = new DiscFileInfo(destPartitionFS, destFileName);

                            // NTFS hard link handling
                            if (destPartitionFS is NtfsFileSystem)
                            {
                                var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS;
                                var ntfsDestFS   = (NtfsFileSystem)destPartitionFS;

                                var sourceFileNtfsEntry = ntfsSourceFS.GetDirectoryEntry(
                                    sourceFile.FullName);
                                var sourceFileNtfsRef = ntfsSourceFS.GetFile(
                                    sourceFileNtfsEntry.Reference);

                                var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry(
                                    destFile.FullName);
                                var destFileNtfsRef = ntfsDestFS.GetFile(
                                    destFileNtfsEntry.Reference);

                                var sourceFileNtfsId = sourceFileNtfsRef.IndexInMft;

                                // check if this files was already processed once
                                if (ntfsHardlinkTracker.ContainsKey(sourceFileNtfsId))
                                {
                                    var trackedDestFileNtfsRef = ntfsDestFS.GetFile(
                                        ntfsHardlinkTracker[sourceFileNtfsId]);

                                    // if we have a hardlink-match, close the old stream
                                    // and delete the file
                                    destFileStream.Close();
                                    destFile.Delete();

                                    // then create the hardlink and mention that we don't
                                    // want/need to copy the content anymore
                                    Logger.Info("[{0}/{1}] mk-lnk : {2} => {3}", i, taskId,
                                                sourceFileNtfsRef.Names[0], destFile.FullName);

                                    ntfsDestFS.CreateHardLink(
                                        trackedDestFileNtfsRef.DirectoryEntry,
                                        destFile.FullName);
                                    skipCopying = true;
                                }
                                else
                                {
                                    Logger.Verbose("[{0}/{1}] rg-lnk : {2}#{3} -> {4}#{5}", i, taskId,
                                                   sourceFileNtfsRef.Names[0], sourceFileNtfsRef.IndexInMft,
                                                   destFileNtfsRef.Names[0], destFileNtfsRef.IndexInMft);

                                    // if not, track it
                                    ntfsHardlinkTracker.Add(sourceFileNtfsRef.IndexInMft,
                                                            destFileNtfsRef.IndexInMft);
                                }
                            }

                            if (!skipCopying)
                            {
                                Logger.Info("[{0}/{1}] cp-file: {2}", i, taskId, destFile.FullName);
                                CloneStream(i, taskId, sourceFileStream, destFileStream);
                            }

                            // clone basic file informationsdestFile
                            Logger.Verbose("[{0}/{1}] cp-meta: {2}", i, taskId, destFile.FullName);
                            destFile.Attributes        = sourceFile.Attributes;
                            destFile.CreationTime      = sourceFile.CreationTime;
                            destFile.CreationTimeUtc   = sourceFile.CreationTimeUtc;
                            destFile.IsReadOnly        = sourceFile.IsReadOnly;
                            destFile.LastAccessTime    = sourceFile.LastAccessTime;
                            destFile.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc;
                            destFile.LastWriteTime     = sourceFile.LastWriteTime;
                            destFile.LastWriteTimeUtc  = sourceFile.LastWriteTimeUtc;

                            // file-system based cloning
                            if (destPartitionFS is NtfsFileSystem)
                            {
                                Logger.Verbose("[{0}/{1}] cp-fsec: {2}", i, taskId, destFile.FullName);
                                var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS;
                                var ntfsDestFS   = (NtfsFileSystem)destPartitionFS;

                                var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry(
                                    destFile.FullName);
                                var destFileNtfsRef = ntfsDestFS.GetFile(
                                    destFileNtfsEntry.Reference);

                                // clone security descriptors
                                var sourceNtfsSecurity = ntfsSourceFS.GetSecurity(
                                    sourceFile.FullName);
                                ntfsDestFS.SetSecurity(destFile.FullName, sourceNtfsSecurity);

                                // clone short names if destination file is not a hard link
                                if (destFileNtfsEntry.Details.FileNameNamespace !=
                                    FileNameNamespace.Posix || !destFileNtfsRef.HasWin32OrDosName)
                                {
                                    Logger.Verbose("[{0}/{1}] cp-shrt: {2}", i, taskId, destFile.FullName);
                                    var sourceNtfsShortName = ntfsSourceFS.GetShortName(
                                        sourceFile.FullName);

                                    if (sourceNtfsShortName != null)
                                    {
                                        ntfsSourceFS.SetShortName(destFile.FullName,
                                                                  sourceNtfsShortName);
                                    }
                                }
                            }
                        }

                        // advance recursion into directories
                        foreach (var sourceDirectory in sourceDir.GetDirectories())
                        {
                            if (srcPartitionFS is FatFileSystem)
                            {
                                // Don't copy SYSTEM~1 on FAT. Just don't do it...
                                if (sourceDirectory.Name.Equals("SYSTEM~1"))
                                {
                                    continue;
                                }
                            }

                            cloneSrcFsToDestFs(sourceDirectory,
                                               new DiscDirectoryInfo(
                                                   destPartitionFS,
                                                   Path.Combine(destDir.FullName, sourceDirectory.Name)
                                                   )
                                               );
                        }
                    });

                    cloneSrcFsToDestFs(srcPartitionFS.Root, destPartitionFS.Root);
                }
            }

            return(SUCCESS);
        }
Exemple #13
0
        protected override void ProcessRecord()
        {
            PSObject    diskObject = null;
            VirtualDisk disk       = null;

            if (InputObject != null)
            {
                diskObject = InputObject;
                disk       = diskObject.BaseObject as VirtualDisk;
            }
            if (disk == null && string.IsNullOrEmpty(LiteralPath))
            {
                WriteError(new ErrorRecord(
                               new ArgumentException("No disk specified"),
                               "NoDiskSpecified",
                               ErrorCategory.InvalidArgument,
                               null));
                return;
            }

            if (disk == null)
            {
                diskObject = SessionState.InvokeProvider.Item.Get(LiteralPath)[0];
                VirtualDisk vdisk = diskObject.BaseObject as VirtualDisk;

                if (vdisk == null)
                {
                    WriteError(new ErrorRecord(
                                   new ArgumentException("Path specified is not a virtual disk"),
                                   "BadDiskSpecified",
                                   ErrorCategory.InvalidArgument,
                                   null));
                    return;
                }

                disk = vdisk;
            }

            PartitionTable pt = null;

            if (VolumeManager == VolumeManagerType.Bios)
            {
                pt = BiosPartitionTable.Initialize(disk);
            }
            else
            {
                pt = GuidPartitionTable.Initialize(disk);
            }

            if (Signature != 0)
            {
                disk.Signature = Signature;
            }
            else
            {
                disk.Signature = new Random().Next();
            }

            // Changed volume layout, force a rescan
            var drive = diskObject.Properties["PSDrive"].Value as VirtualDiskPSDriveInfo;

            if (drive != null)
            {
                drive.RescanVolumes();
            }


            WriteObject(disk);
        }