Example #1
0
        public bool VirtualToLogicalDriveOffset(ulong virtualOffset, out ulong logicalOffset)
        {
            logicalOffset = 0;

            if (virtualOffset >= Header.DriveSize)
            {
                throw new InvalidOperationException(
                          $"Virtual offset 0x{virtualOffset:X} is outside drivedata length 0x{Header.DriveSize:X}");
            }
            if (Header.Type > XvdType.Dynamic)
            {
                throw new NotSupportedException($"Xvd type {Header.Type} is unhandled");
            }


            if (Header.Type == XvdType.Dynamic)
            {
                var dataStartOffset  = virtualOffset + XvdMath.PageNumberToOffset(Header.NumberOfMetadataPages);
                var pageNumber       = XvdMath.OffsetToPageNumber(dataStartOffset);
                var inBlockOffset    = XvdMath.InBlockOffset(dataStartOffset);
                var firstDynamicPage = XvdMath.QueryFirstDynamicPage(Header.NumberOfMetadataPages);

                if (pageNumber >= firstDynamicPage)
                {
                    var   firstDynamicPageBytes = XvdMath.PageNumberToOffset(firstDynamicPage);
                    var   blockNumber           = XvdMath.OffsetToBlockNumber(dataStartOffset - firstDynamicPageBytes);
                    ulong allocatedBlock        = ReadBat(blockNumber);
                    if (allocatedBlock == INVALID_SECTOR)
                    {
                        return(false);
                    }

                    dataStartOffset = XvdMath.PageNumberToOffset(allocatedBlock) + inBlockOffset;
                    pageNumber      = XvdMath.OffsetToPageNumber(dataStartOffset);
                }

                var dataBackingBlockNum = XvdMath.ComputeDataBackingPageNumber(Header.Type,
                                                                               HashTreeLevels,
                                                                               HashTreePageCount,
                                                                               pageNumber);
                logicalOffset  = XvdMath.PageNumberToOffset(dataBackingBlockNum);
                logicalOffset += XvdMath.InPageOffset(dataStartOffset);
                logicalOffset += XvdMath.PageNumberToOffset(Header.EmbeddedXvdPageCount);
                logicalOffset += Header.MutableDataLength;
                logicalOffset += XVD_HEADER_INCL_SIGNATURE_SIZE;
                logicalOffset += PAGE_SIZE;
            }
            else
            { // Xvd type fixed
                logicalOffset  = virtualOffset;
                logicalOffset += XvdMath.PageNumberToOffset(Header.EmbeddedXvdPageCount);
                logicalOffset += Header.MutableDataLength;
                logicalOffset += XvdMath.PageNumberToOffset(Header.NumberOfMetadataPages);
                logicalOffset += XVD_HEADER_INCL_SIGNATURE_SIZE;
                logicalOffset += PAGE_SIZE;
            }

            return(true);
        }
Example #2
0
        byte[] ReadDynamic(int count)
        {
            int positionInBuffer = 0;
            int bytesRemaining   = count;

            byte[] destBuffer = new byte[count];

            while (positionInBuffer < count)
            {
                byte[] data = new byte[0];
                if (Position < StaticDataLength)
                {
                    // Read a chunk from non-dynamic area, next iteration will read dynamic data
                    int maxReadLength = (int)(StaticDataLength - Position);
                    int length        = bytesRemaining > maxReadLength ? maxReadLength : bytesRemaining;
                    data = InternalRead(length);
                }
                else
                {
                    // Lookup block allocation table for real data offset
                    var   targetVirtualOffset = (ulong)(Position - StaticDataLength);
                    ulong blockNumber         = XvdMath.OffsetToBlockNumber(targetVirtualOffset);
                    long  inBlockOffset       = (long)XvdMath.InBlockOffset(targetVirtualOffset);
                    int   maxReadLength       = (int)(XvdFile.BLOCK_SIZE - inBlockOffset);
                    int   length = bytesRemaining > maxReadLength ? maxReadLength : bytesRemaining;

                    var targetPage = _xvdFile.ReadBat(blockNumber);
                    if (targetPage == XvdFile.INVALID_SECTOR)
                    {
                        data = new byte[length];
                        // Advance stream position cause we are not actually reading data
                        Position += length;
                    }
                    else
                    {
                        long targetPhysicalOffset = DynamicBaseOffset
                                                    + (long)XvdMath.PageNumberToOffset(targetPage)
                                                    + inBlockOffset;

                        data = InternalReadAbsolute(targetPhysicalOffset, length);
                    }
                }

                Array.Copy(data, 0, destBuffer, positionInBuffer, data.Length);
                positionInBuffer += data.Length;
                bytesRemaining   -= data.Length;
            }

            return(destBuffer);
        }