public void FsTrim() { if (Type != IntegrityStorageType.Save) { return; } Span <byte> digest = stackalloc byte[DigestSize]; for (int i = 0; i < SectorCount; i++) { long hashPos = i * DigestSize; HashStorage.Read(digest, hashPos); if (!Util.IsEmpty(digest)) { continue; } int dataOffset = i * SectorSize; BaseStorage.Fill(SaveDataFileSystem.TrimFillValue, dataOffset, SectorSize); } }
private void ReadImpl(Span <byte> destination, long offset, IntegrityCheckLevel integrityCheckLevel) { int count = destination.Length; if (count < 0 || count > SectorSize) { throw new ArgumentOutOfRangeException(nameof(destination), "Length is invalid."); } long blockIndex = offset / SectorSize; if (BlockValidities[blockIndex] == Validity.Invalid && integrityCheckLevel == IntegrityCheckLevel.ErrorOnInvalid) { // Todo: Differentiate between the top and lower layers ThrowHelper.ThrowResult(ResultFs.InvalidHashInIvfc, "Hash error!"); } bool needsHashCheck = integrityCheckLevel != IntegrityCheckLevel.None && BlockValidities[blockIndex] == Validity.Unchecked; if (Type != IntegrityStorageType.Save && !needsHashCheck) { BaseStorage.Read(destination, offset); return; } Span <byte> hashBuffer = stackalloc byte[DigestSize]; long hashPos = blockIndex * DigestSize; HashStorage.Read(hashBuffer, hashPos); if (Type == IntegrityStorageType.Save) { if (Util.IsEmpty(hashBuffer)) { destination.Clear(); BlockValidities[blockIndex] = Validity.Valid; return; } if (!needsHashCheck) { BaseStorage.Read(destination, offset); return; } } byte[] dataBuffer = ArrayPool <byte> .Shared.Rent(SectorSize); try { BaseStorage.Read(destination, offset); destination.CopyTo(dataBuffer); if (BlockValidities[blockIndex] != Validity.Unchecked) { return; } int bytesToHash = SectorSize; if (count < SectorSize) { // Pad out unused portion of block Array.Clear(dataBuffer, count, SectorSize - count); // Partition FS hashes don't pad out an incomplete block if (Type == IntegrityStorageType.PartitionFs) { bytesToHash = count; } } byte[] hash = DoHash(dataBuffer, 0, bytesToHash); Validity validity = Util.SpansEqual(hashBuffer, hash) ? Validity.Valid : Validity.Invalid; BlockValidities[blockIndex] = validity; if (validity == Validity.Invalid && integrityCheckLevel == IntegrityCheckLevel.ErrorOnInvalid) { ThrowHelper.ThrowResult(ResultFs.InvalidHashInIvfc, "Hash error!"); } } finally { ArrayPool <byte> .Shared.Return(dataBuffer); } }
private void ReadImpl(Span <byte> destination, long offset, IntegrityCheckLevel integrityCheckLevel) { int count = destination.Length; if (count < 0 || count > SectorSize) { throw new ArgumentOutOfRangeException(nameof(destination), "Length is invalid."); } Span <byte> hashBuffer = stackalloc byte[DigestSize]; long blockIndex = offset / SectorSize; long hashPos = blockIndex * DigestSize; if (BlockValidities[blockIndex] == Validity.Invalid && integrityCheckLevel == IntegrityCheckLevel.ErrorOnInvalid) { throw new InvalidDataException("Hash error!"); } HashStorage.Read(hashBuffer, hashPos); if (Type == IntegrityStorageType.Save && Util.IsEmpty(hashBuffer)) { destination.Clear(); BlockValidities[blockIndex] = Validity.Valid; return; } byte[] dataBuffer = ArrayPool <byte> .Shared.Rent(SectorSize); try { BaseStorage.Read(dataBuffer, offset, count, 0); dataBuffer.AsSpan(0, count).CopyTo(destination); if (integrityCheckLevel == IntegrityCheckLevel.None) { return; } if (BlockValidities[blockIndex] != Validity.Unchecked) { return; } int bytesToHash = SectorSize; if (count < SectorSize) { // Pad out unused portion of block Array.Clear(dataBuffer, count, SectorSize - count); // Partition FS hashes don't pad out an incomplete block if (Type == IntegrityStorageType.PartitionFs) { bytesToHash = count; } } byte[] hash = DoHash(dataBuffer, 0, bytesToHash); Validity validity = Util.SpansEqual(hashBuffer, hash) ? Validity.Valid : Validity.Invalid; BlockValidities[blockIndex] = validity; if (validity == Validity.Invalid && integrityCheckLevel == IntegrityCheckLevel.ErrorOnInvalid) { throw new InvalidDataException("Hash error!"); } } finally { ArrayPool <byte> .Shared.Return(dataBuffer); } }