Пример #1
0
 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);
             }
         }
     }
 }
Пример #2
0
        public HostedSparseExtentStream(Stream file, Ownership ownsFile, long diskOffset, SparseStream parentDiskStream, Ownership ownsParentDiskStream)
        {
            _fileStream           = file;
            _ownsFileStream       = ownsFile;
            _diskOffset           = diskOffset;
            _parentDiskStream     = parentDiskStream;
            _ownsParentDiskStream = ownsParentDiskStream;

            file.Position = 0;
            byte[] headerSector = Utilities.ReadFully(file, Sizes.Sector);
            _hostedHeader = HostedSparseExtentHeader.Read(headerSector, 0);
            if (_hostedHeader.GdOffset == -1)
            {
                // Fall back to secondary copy that (should) be at the end of the stream, just before the end-of-stream sector marker
                file.Position = file.Length - Sizes.OneKiB;
                headerSector  = Utilities.ReadFully(file, Sizes.Sector);
                _hostedHeader = HostedSparseExtentHeader.Read(headerSector, 0);

                if (_hostedHeader.MagicNumber != HostedSparseExtentHeader.VmdkMagicNumber)
                {
                    throw new IOException("Unable to locate valid VMDK header or footer");
                }
            }

            _header = _hostedHeader;

            if (_hostedHeader.CompressAlgorithm != 0 && _hostedHeader.CompressAlgorithm != 1)
            {
                throw new NotSupportedException("Only uncompressed and DEFLATE compressed disks supported");
            }

            _gtCoverage = _header.NumGTEsPerGT * _header.GrainSize * Sizes.Sector;

            LoadGlobalDirectory();
        }
Пример #3
0
        private static void CreateSparseExtent(Stream extentStream, long size, long descriptorLength, out long descriptorStart)
        {
            // Figure out grain size and number of grain tables, and adjust actual extent size to be a multiple
            // of grain size
            const int GtesPerGt      = 512;
            long      grainSize      = 128;
            int       numGrainTables = (int)Utilities.Ceil(size, grainSize * GtesPerGt * Sizes.Sector);

            descriptorLength = Utilities.RoundUp(descriptorLength, Sizes.Sector);
            descriptorStart  = 0;
            if (descriptorLength != 0)
            {
                descriptorStart = 1;
            }

            long redundantGrainDirStart  = Math.Max(descriptorStart, 1) + Utilities.Ceil(descriptorLength, Sizes.Sector);
            long redundantGrainDirLength = numGrainTables * 4;

            long redundantGrainTablesStart  = redundantGrainDirStart + Utilities.Ceil(redundantGrainDirLength, Sizes.Sector);
            long redundantGrainTablesLength = numGrainTables * Utilities.RoundUp(GtesPerGt * 4, Sizes.Sector);

            long grainDirStart  = redundantGrainTablesStart + Utilities.Ceil(redundantGrainTablesLength, Sizes.Sector);
            long grainDirLength = numGrainTables * 4;

            long grainTablesStart  = grainDirStart + Utilities.Ceil(grainDirLength, Sizes.Sector);
            long grainTablesLength = numGrainTables * Utilities.RoundUp(GtesPerGt * 4, Sizes.Sector);

            long dataStart = Utilities.RoundUp(grainTablesStart + Utilities.Ceil(grainTablesLength, Sizes.Sector), grainSize);

            // Generate the header, and write it
            HostedSparseExtentHeader header = new HostedSparseExtentHeader();

            header.Flags            = HostedSparseExtentFlags.ValidLineDetectionTest | HostedSparseExtentFlags.RedundantGrainTable;
            header.Capacity         = Utilities.RoundUp(size, grainSize * Sizes.Sector) / Sizes.Sector;
            header.GrainSize        = grainSize;
            header.DescriptorOffset = descriptorStart;
            header.DescriptorSize   = descriptorLength / Sizes.Sector;
            header.NumGTEsPerGT     = GtesPerGt;
            header.RgdOffset        = redundantGrainDirStart;
            header.GdOffset         = grainDirStart;
            header.Overhead         = dataStart;

            extentStream.Position = 0;
            extentStream.Write(header.GetBytes(), 0, Sizes.Sector);

            // Zero-out the descriptor space
            if (descriptorLength > 0)
            {
                byte[] descriptor = new byte[descriptorLength];
                extentStream.Position = descriptorStart * Sizes.Sector;
                extentStream.Write(descriptor, 0, descriptor.Length);
            }

            // Generate the redundant grain dir, and write it
            byte[] grainDir = new byte[numGrainTables * 4];
            for (int i = 0; i < numGrainTables; ++i)
            {
                Utilities.WriteBytesLittleEndian((uint)(redundantGrainTablesStart + (i * Utilities.Ceil(GtesPerGt * 4, Sizes.Sector))), grainDir, i * 4);
            }

            extentStream.Position = redundantGrainDirStart * Sizes.Sector;
            extentStream.Write(grainDir, 0, grainDir.Length);

            // Write out the blank grain tables
            byte[] grainTable = new byte[GtesPerGt * 4];
            for (int i = 0; i < numGrainTables; ++i)
            {
                extentStream.Position = (redundantGrainTablesStart * Sizes.Sector) + (i * Utilities.RoundUp(GtesPerGt * 4, Sizes.Sector));
                extentStream.Write(grainTable, 0, grainTable.Length);
            }

            // Generate the main grain dir, and write it
            for (int i = 0; i < numGrainTables; ++i)
            {
                Utilities.WriteBytesLittleEndian((uint)(grainTablesStart + (i * Utilities.Ceil(GtesPerGt * 4, Sizes.Sector))), grainDir, i * 4);
            }

            extentStream.Position = grainDirStart * Sizes.Sector;
            extentStream.Write(grainDir, 0, grainDir.Length);

            // Write out the blank grain tables
            for (int i = 0; i < numGrainTables; ++i)
            {
                extentStream.Position = (grainTablesStart * Sizes.Sector) + (i * Utilities.RoundUp(GtesPerGt * 4, Sizes.Sector));
                extentStream.Write(grainTable, 0, grainTable.Length);
            }

            // Make sure stream is correct length
            if (extentStream.Length != dataStart * Sizes.Sector)
            {
                extentStream.SetLength(dataStart * Sizes.Sector);
            }
        }