using System; using System.IO; namespace SvdCli.Storage.Implements { public class RawImageStorage : ISvdStorage { private readonly string _imageFilePath; private FileStream _fileStream; private bool _sparse; public string ProductId { get; } = "Svd RawImage Disk"; public string ProductVersion { get; } = "1.0"; public uint BlockSize { get; } = 512; public uint MaxTransferLength { get; } = 64 * CapacityUnits.KiloByte; public bool SupportTrim { get; } public ulong BlockCount { get; } public bool WriteProtect { get; } public RawImageStorage(string imageFilePath, bool readOnly = false) { _imageFilePath = imageFilePath; WriteProtect = readOnly; SupportTrim = !readOnly; BlockCount = (ulong)new FileInfo(_imageFilePath).Length / BlockSize; } public void Init() { if (null != _fileStream) return; var access = WriteProtect ? FileAccess.Read : FileAccess.ReadWrite; _fileStream = new FileStream(_imageFilePath, FileMode.Open, access, FileShare.None, (int)MaxTransferLength); if (false == WriteProtect) _sparse = _fileStream.SetSparse(); } public void Exit() { if (null == _fileStream) return; if (false == WriteProtect) { lock (_fileStream) { _fileStream.Flush(true); } } lock (_fileStream) { _fileStream.Close(); _fileStream = null; } } public void ReadBlocks(byte[] buffer, ulong blockIndex, uint blockCount) { lock (_fileStream) { _fileStream.Position = (long)(blockIndex * BlockSize); var length = (int)(blockCount * BlockSize); var offset = 0; while (length > 0) { var read = _fileStream.Read(buffer, offset, length); length -= read; offset += read; } } } public void WriteBlocks(byte[] buffer, ulong blockIndex, uint blockCount) { lock (_fileStream) { _fileStream.Position = (long)(blockIndex * BlockSize); _fileStream.Write(buffer, 0, (int)(blockCount * BlockSize)); } } public int Read(byte[] buffer, long offset, int index, int count) { lock (_fileStream) { _fileStream.Position = offset; return _fileStream.Read(buffer, index, count); } } public void Write(byte[] buffer, long offset, int index, int count) { lock (_fileStream) { _fileStream.Position = offset; _fileStream.Write(buffer, index, count); } } public void Flush() { lock (_fileStream) _fileStream.Flush(true); } public void Trim(params TrimDescriptor[] descriptors) { lock (_fileStream) { foreach (var trim in descriptors) { if (_sparse && _fileStream.Trim(trim.Offset, trim.Length)) continue; _fileStream.Position = trim.Offset; var totalLength = (int)trim.Length; var buffer = new byte[Math.Min(64 * 1024, totalLength)]; while (0 < totalLength) { _fileStream.Write(buffer, 0, buffer.Length); totalLength -= buffer.Length; } } } } } }