diff --git a/src/LibHac/Fs/Common/FileStorage.cs b/src/LibHac/Fs/Common/FileStorage.cs
index a12fce38..e6667c1c 100644
--- a/src/LibHac/Fs/Common/FileStorage.cs
+++ b/src/LibHac/Fs/Common/FileStorage.cs
@@ -11,7 +11,7 @@ namespace LibHac.Fs;
///
/// Allows interacting with an via an interface.
///
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public class FileStorage : IStorage
{
private const long InvalidSize = -1;
@@ -60,8 +60,8 @@ public class FileStorage : IStorage
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, destination.Length, _fileSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, destination.Length, _fileSize);
+ if (rc.IsFailure()) return rc.Miss();
return _baseFile.Read(out _, offset, destination, ReadOption.None);
}
@@ -74,8 +74,8 @@ public class FileStorage : IStorage
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, source.Length, _fileSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, source.Length, _fileSize);
+ if (rc.IsFailure()) return rc.Miss();
return _baseFile.Write(offset, source, WriteOption.None);
}
@@ -104,35 +104,37 @@ public class FileStorage : IStorage
public override Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer)
{
- if (operationId == OperationId.InvalidateCache)
+ switch (operationId)
{
- Result rc = _baseFile.OperateRange(OperationId.InvalidateCache, offset, size);
- if (rc.IsFailure()) return rc.Miss();
-
- return Result.Success;
- }
-
- if (operationId == OperationId.QueryRange)
- {
- if (size == 0)
+ case OperationId.InvalidateCache:
{
- if (outBuffer.Length != Unsafe.SizeOf())
- return ResultFs.InvalidSize.Log();
+ Result rc = _baseFile.OperateRange(OperationId.InvalidateCache, offset, size);
+ if (rc.IsFailure()) return rc.Miss();
- SpanHelpers.AsStruct(outBuffer).Clear();
return Result.Success;
}
+ case OperationId.QueryRange:
+ {
+ if (size == 0)
+ {
+ if (outBuffer.Length != Unsafe.SizeOf())
+ return ResultFs.InvalidSize.Log();
- Result rc = UpdateSize();
- if (rc.IsFailure()) return rc.Miss();
+ SpanHelpers.AsStruct(outBuffer).Clear();
+ return Result.Success;
+ }
- if (!CheckOffsetAndSize(offset, size))
- return ResultFs.OutOfRange.Log();
+ Result rc = UpdateSize();
+ if (rc.IsFailure()) return rc.Miss();
- return _baseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
+ rc = CheckOffsetAndSize(offset, size);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return _baseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
+ }
+ default:
+ return ResultFs.UnsupportedOperateRangeForFileStorage.Log();
}
-
- return ResultFs.UnsupportedOperateRangeForFileStorage.Log();
}
private Result UpdateSize()
@@ -153,7 +155,7 @@ public class FileStorage : IStorage
/// interface. The opened file will automatically be closed when the
/// is disposed.
///
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public class FileStorageBasedFileSystem : FileStorage
{
private SharedRef _baseFileSystem;
@@ -196,7 +198,7 @@ public class FileStorageBasedFileSystem : FileStorage
/// Provides an interface for interacting with an opened file from a mounted file system.
/// The caller may choose whether or not the file will be closed when the is disposed.
///
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public class FileHandleStorage : IStorage
{
private const long InvalidSize = -1;
@@ -230,7 +232,7 @@ public class FileHandleStorage : IStorage
_handle = handle;
_closeFile = closeFile;
_size = InvalidSize;
- _mutex.Initialize();
+ _mutex = new SdkMutexType();
}
public override void Dispose()
@@ -255,8 +257,8 @@ public class FileHandleStorage : IStorage
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, destination.Length, _size))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, destination.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
return _fsClient.ReadFile(_handle, offset, destination, ReadOption.None);
}
@@ -271,8 +273,8 @@ public class FileHandleStorage : IStorage
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, source.Length, _size))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, source.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
return _fsClient.WriteFile(_handle, offset, source, WriteOption.None);
}
diff --git a/src/LibHac/Fs/IStorage.cs b/src/LibHac/Fs/IStorage.cs
index 8dd6c702..02b93c3a 100644
--- a/src/LibHac/Fs/IStorage.cs
+++ b/src/LibHac/Fs/IStorage.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
+using LibHac.Util;
namespace LibHac.Fs;
@@ -7,12 +8,7 @@ namespace LibHac.Fs;
///
/// Provides an interface for reading and writing a sequence of bytes.
///
-///
-/// The official IStorage makes the Read etc. methods abstract and doesn't
-/// have DoRead etc. methods. We're using them here so we can make sure
-/// the object isn't disposed before calling the method implementation.
-///
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public abstract class IStorage : IDisposable
{
public virtual void Dispose() { }
@@ -78,20 +74,70 @@ public abstract class IStorage : IDisposable
return OperateRange(Span.Empty, operationId, offset, size, ReadOnlySpan.Empty);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool CheckAccessRange(long offset, long size, long totalSize)
+ public static Result CheckAccessRange(long offset, long size, long totalSize)
{
- return offset >= 0 &&
- size >= 0 &&
- size <= totalSize &&
- offset <= totalSize - size;
+ if (offset < 0)
+ return ResultFs.InvalidOffset.Log();
+
+ if (size < 0)
+ return ResultFs.InvalidSize.Log();
+
+ if (!IntUtil.CanAddWithoutOverflow(offset, size))
+ return ResultFs.OutOfRange.Log();
+
+ if (size + offset > totalSize)
+ return ResultFs.OutOfRange.Log();
+
+ return Result.Success;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool CheckOffsetAndSize(long offset, long size)
+ public static Result CheckAccessRange(long offset, ulong size, long totalSize)
{
- return offset >= 0 &&
- size >= 0 &&
- offset <= offset + size;
+ Result rc = CheckAccessRange(offset, unchecked((long)size), totalSize);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+
+ public static Result CheckOffsetAndSize(long offset, long size)
+ {
+ if (offset < 0)
+ return ResultFs.InvalidOffset.Log();
+
+ if (size < 0)
+ return ResultFs.InvalidSize.Log();
+
+ if (!IntUtil.CanAddWithoutOverflow(offset, size))
+ return ResultFs.OutOfRange.Log();
+
+ return Result.Success;
+ }
+
+ public static Result CheckOffsetAndSize(long offset, ulong size)
+ {
+ Result rc = CheckOffsetAndSize(offset, unchecked((long)size));
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+
+ public static Result CheckOffsetAndSizeWithResult(long offset, long size, Result resultOnFailure)
+ {
+ Result rc = CheckOffsetAndSize(offset, size);
+
+ if (rc.IsFailure())
+ return resultOnFailure.Log();
+
+ return Result.Success;
+ }
+
+ public static Result CheckOffsetAndSizeWithResult(long offset, ulong size, Result resultOnFailure)
+ {
+ Result rc = CheckOffsetAndSize(offset, size);
+
+ if (rc.IsFailure())
+ return resultOnFailure.Log();
+
+ return Result.Success;
}
}
\ No newline at end of file
diff --git a/src/LibHac/Fs/MemoryStorage.cs b/src/LibHac/Fs/MemoryStorage.cs
index f9cdf523..0e4bf511 100644
--- a/src/LibHac/Fs/MemoryStorage.cs
+++ b/src/LibHac/Fs/MemoryStorage.cs
@@ -7,7 +7,7 @@ namespace LibHac.Fs;
///
/// Allows interacting with a array via the interface.
///
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public class MemoryStorage : IStorage
{
private byte[] _storageBuffer;
@@ -22,8 +22,8 @@ public class MemoryStorage : IStorage
if (destination.Length == 0)
return Result.Success;
- if (!CheckAccessRange(offset, destination.Length, _storageBuffer.Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, _storageBuffer.Length);
+ if (rc.IsFailure()) return rc.Miss();
_storageBuffer.AsSpan((int)offset, destination.Length).CopyTo(destination);
@@ -35,8 +35,8 @@ public class MemoryStorage : IStorage
if (source.Length == 0)
return Result.Success;
- if (!CheckAccessRange(offset, source.Length, _storageBuffer.Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, _storageBuffer.Length);
+ if (rc.IsFailure()) return rc.Miss();
source.CopyTo(_storageBuffer.AsSpan((int)offset));
diff --git a/src/LibHac/Fs/SubStorage.cs b/src/LibHac/Fs/SubStorage.cs
index 72394195..e6f23741 100644
--- a/src/LibHac/Fs/SubStorage.cs
+++ b/src/LibHac/Fs/SubStorage.cs
@@ -8,16 +8,17 @@ namespace LibHac.Fs;
/// Presents a subsection of a base IStorage as a new IStorage.
///
///
-/// A SubStorage presents a sub-range of an IStorage as a separate IStorage.
+/// A SubStorage presents a sub-range of an IStorage as a separate IStorage.
///
-/// The SubStorage doesn't check if the offset and size provided are actually in the base storage.
+/// The SubStorage doesn't check if the offset and size provided are actually in the base storage.
/// GetSize will return the size given to the SubStorage at initialization and will not query
-/// the base storage's size.
+/// the base storage's size.
///
-/// A SubStorage is non-resizable by default. may be used to mark
+/// A SubStorage is non-resizable by default. may be used to mark
/// the SubStorage as resizable. The SubStorage may only be resized if the end of the SubStorage
/// is located at the end of the base storage. When resizing the SubStorage, the base storage
-/// will be resized to the appropriate length.
+/// will be resized to the appropriate length.
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
///
public class SubStorage : IStorage
{
@@ -158,10 +159,13 @@ public class SubStorage : IStorage
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (destination.Length == 0) return Result.Success;
- if (!CheckAccessRange(offset, destination.Length, _size))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
- return BaseStorage.Read(_offset + offset, destination);
+ rc = BaseStorage.Read(_offset + offset, destination);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public override Result Write(long offset, ReadOnlySpan source)
@@ -169,26 +173,34 @@ public class SubStorage : IStorage
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (source.Length == 0) return Result.Success;
- if (!CheckAccessRange(offset, source.Length, _size))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
- return BaseStorage.Write(_offset + offset, source);
+ rc = BaseStorage.Write(_offset + offset, source);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public override Result Flush()
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
- return BaseStorage.Flush();
+ Result rc = BaseStorage.Flush();
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public override Result SetSize(long size)
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (!_isResizable) return ResultFs.UnsupportedSetSizeForNotResizableSubStorage.Log();
- if (!CheckOffsetAndSize(_offset, size)) return ResultFs.InvalidSize.Log();
- Result rc = BaseStorage.GetSize(out long currentSize);
+ Result rc = CheckOffsetAndSize(_offset, size);
+ if (rc.IsFailure()) return rc.Miss();
+
+ rc = BaseStorage.GetSize(out long currentSize);
if (rc.IsFailure()) return rc;
if (currentSize != _offset + _size)
@@ -222,7 +234,9 @@ public class SubStorage : IStorage
if (operationId != OperationId.InvalidateCache)
{
if (size == 0) return Result.Success;
- if (!CheckOffsetAndSize(_offset, size)) return ResultFs.OutOfRange.Log();
+
+ Result rc = CheckOffsetAndSize(_offset, size);
+ if (rc.IsFailure()) return rc.Miss();
}
return BaseStorage.OperateRange(outBuffer, operationId, _offset + offset, size, inBuffer);
diff --git a/src/LibHac/Fs/ValueSubStorage.cs b/src/LibHac/Fs/ValueSubStorage.cs
index 4605acf8..7cabaf9c 100644
--- a/src/LibHac/Fs/ValueSubStorage.cs
+++ b/src/LibHac/Fs/ValueSubStorage.cs
@@ -112,10 +112,13 @@ public struct ValueSubStorage : IDisposable
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (destination.Length == 0) return Result.Success;
- if (!IStorage.CheckAccessRange(offset, destination.Length, _size))
- return ResultFs.OutOfRange.Log();
+ Result rc = IStorage.CheckAccessRange(offset, destination.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
- return _baseStorage.Read(_offset + offset, destination);
+ rc = _baseStorage.Read(_offset + offset, destination);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public readonly Result Write(long offset, ReadOnlySpan source)
@@ -123,26 +126,34 @@ public struct ValueSubStorage : IDisposable
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (source.Length == 0) return Result.Success;
- if (!IStorage.CheckAccessRange(offset, source.Length, _size))
- return ResultFs.OutOfRange.Log();
+ Result rc = IStorage.CheckAccessRange(offset, source.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
- return _baseStorage.Write(_offset + offset, source);
+ rc = _baseStorage.Write(_offset + offset, source);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public readonly Result Flush()
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
- return _baseStorage.Flush();
+ Result rc = _baseStorage.Flush();
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
}
public Result SetSize(long size)
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (!_isResizable) return ResultFs.UnsupportedSetSizeForNotResizableSubStorage.Log();
- if (!IStorage.CheckOffsetAndSize(_offset, size)) return ResultFs.InvalidSize.Log();
- Result rc = _baseStorage.GetSize(out long currentSize);
+ Result rc = IStorage.CheckOffsetAndSize(_offset, size);
+ if (rc.IsFailure()) return rc;
+
+ rc = _baseStorage.GetSize(out long currentSize);
if (rc.IsFailure()) return rc;
if (currentSize != _offset + _size)
@@ -181,7 +192,9 @@ public struct ValueSubStorage : IDisposable
if (operationId != OperationId.InvalidateCache)
{
if (size == 0) return Result.Success;
- if (!IStorage.CheckOffsetAndSize(_offset, size)) return ResultFs.OutOfRange.Log();
+
+ Result rc = IStorage.CheckOffsetAndSize(_offset, size);
+ if (rc.IsFailure()) return rc.Miss();
}
return _baseStorage.OperateRange(outBuffer, operationId, _offset + offset, size, inBuffer);
diff --git a/src/LibHac/FsSystem/AlignmentMatchingStorage.cs b/src/LibHac/FsSystem/AlignmentMatchingStorage.cs
index a1aa15ff..bd2e239c 100644
--- a/src/LibHac/FsSystem/AlignmentMatchingStorage.cs
+++ b/src/LibHac/FsSystem/AlignmentMatchingStorage.cs
@@ -23,7 +23,7 @@ public interface IAlignmentMatchingStorageSize { }
/// This class uses a work buffer on the stack to avoid allocations. Because of this the data alignment
/// must be kept small; no larger than 0x200. The class
/// should be used for data alignment sizes larger than this.
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
[SkipLocalsInit]
public class AlignmentMatchingStorage : IStorage
where TDataAlignment : struct, IAlignmentMatchingStorageSize
@@ -80,8 +80,8 @@ public class AlignmentMatchingStorage : IStora
Result rc = GetSize(out long totalSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, destination.Length, totalSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, destination.Length, totalSize);
+ if (rc.IsFailure()) return rc.Miss();
return AlignmentMatchingStorageImpl.Read(_baseStorage, workBuffer, DataAlign, BufferAlign, offset, destination);
}
@@ -96,8 +96,8 @@ public class AlignmentMatchingStorage : IStora
Result rc = GetSize(out long totalSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, source.Length, totalSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, source.Length, totalSize);
+ if (rc.IsFailure()) return rc.Miss();
return AlignmentMatchingStorageImpl.Write(_baseStorage, workBuffer, DataAlign, BufferAlign, offset, source);
}
@@ -146,8 +146,8 @@ public class AlignmentMatchingStorage : IStora
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckOffsetAndSize(offset, size))
- return ResultFs.OutOfRange.Log();
+ rc = CheckOffsetAndSize(offset, size);
+ if (rc.IsFailure()) return rc.Miss();
long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, DataAlign);
@@ -166,7 +166,7 @@ public class AlignmentMatchingStorage : IStora
/// the beginning or end of the requested range. For data alignment sizes of 0x200 or smaller
/// should be used instead
/// to avoid these allocations.
-/// Based on FS 13.1.0 (nnSdk 13.4.0)
+/// Based on FS 14.1.0 (nnSdk 14.3.0)
public class AlignmentMatchingStoragePooledBuffer : IStorage
where TBufferAlignment : struct, IAlignmentMatchingStorageSize
{
@@ -220,8 +220,8 @@ public class AlignmentMatchingStoragePooledBuffer : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, destination.Length, baseStorageSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, destination.Length, baseStorageSize);
+ if (rc.IsFailure()) return rc.Miss();
using var pooledBuffer = new PooledBuffer();
pooledBuffer.AllocateParticularlyLarge((int)_dataAlignment, (int)_dataAlignment);
@@ -238,8 +238,8 @@ public class AlignmentMatchingStoragePooledBuffer : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, source.Length, baseStorageSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, source.Length, baseStorageSize);
+ if (rc.IsFailure()) return rc.Miss();
using var pooledBuffer = new PooledBuffer();
pooledBuffer.AllocateParticularlyLarge((int)_dataAlignment, (int)_dataAlignment);
@@ -292,8 +292,8 @@ public class AlignmentMatchingStoragePooledBuffer : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckOffsetAndSize(offset, size))
- return ResultFs.OutOfRange.Log();
+ rc = CheckOffsetAndSize(offset, size);
+ if (rc.IsFailure()) return rc.Miss();
long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, _dataAlignment);
@@ -362,8 +362,8 @@ public class AlignmentMatchingStorageInBulkRead : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, destination.Length, baseStorageSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, destination.Length, baseStorageSize);
+ if (rc.IsFailure()) return rc.Miss();
// Calculate the aligned offsets of the requested region.
long offsetEnd = offset + destination.Length;
@@ -453,8 +453,8 @@ public class AlignmentMatchingStorageInBulkRead : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckAccessRange(offset, source.Length, baseStorageSize))
- return ResultFs.OutOfRange.Log();
+ rc = CheckAccessRange(offset, source.Length, baseStorageSize);
+ if (rc.IsFailure()) return rc.Miss();
using var pooledBuffer = new PooledBuffer((int)_dataAlignment, (int)_dataAlignment);
@@ -505,8 +505,8 @@ public class AlignmentMatchingStorageInBulkRead : IStorage
Result rc = GetSize(out long baseStorageSize);
if (rc.IsFailure()) return rc.Miss();
- if (!CheckOffsetAndSize(offset, size))
- return ResultFs.OutOfRange.Log();
+ rc = CheckOffsetAndSize(offset, size);
+ if (rc.IsFailure()) return rc.Miss();
long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, _dataAlignment);
diff --git a/src/LibHac/Tools/FsSystem/AesCbcStorage.cs b/src/LibHac/Tools/FsSystem/AesCbcStorage.cs
index 8045d2f6..48fbd552 100644
--- a/src/LibHac/Tools/FsSystem/AesCbcStorage.cs
+++ b/src/LibHac/Tools/FsSystem/AesCbcStorage.cs
@@ -28,10 +28,10 @@ public class AesCbcStorage : SectorStorage
public override Result Read(long offset, Span destination)
{
- if (!CheckAccessRange(offset, destination.Length, _size))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, _size);
+ if (rc.IsFailure()) return rc.Miss();
- Result rc = base.Read(offset, destination);
+ rc = base.Read(offset, destination);
if (rc.IsFailure()) return rc;
rc = GetDecryptor(out ICipher cipher, offset);
diff --git a/src/LibHac/Tools/FsSystem/CachedStorage.cs b/src/LibHac/Tools/FsSystem/CachedStorage.cs
index 89de720d..cf5f140c 100644
--- a/src/LibHac/Tools/FsSystem/CachedStorage.cs
+++ b/src/LibHac/Tools/FsSystem/CachedStorage.cs
@@ -39,8 +39,8 @@ public class CachedStorage : IStorage
long inOffset = offset;
int outOffset = 0;
- if (!CheckAccessRange(offset, destination.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
lock (Blocks)
{
@@ -69,8 +69,8 @@ public class CachedStorage : IStorage
long inOffset = offset;
int outOffset = 0;
- if (!CheckAccessRange(offset, source.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
lock (Blocks)
{
diff --git a/src/LibHac/Tools/FsSystem/ConcatenationStorage.cs b/src/LibHac/Tools/FsSystem/ConcatenationStorage.cs
index cbb8102d..10d722fc 100644
--- a/src/LibHac/Tools/FsSystem/ConcatenationStorage.cs
+++ b/src/LibHac/Tools/FsSystem/ConcatenationStorage.cs
@@ -34,8 +34,8 @@ public class ConcatenationStorage : IStorage
int outPos = 0;
int remaining = destination.Length;
- if (!CheckAccessRange(offset, destination.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
int sourceIndex = FindSource(inPos);
@@ -47,7 +47,7 @@ public class ConcatenationStorage : IStorage
int bytesToRead = (int)Math.Min(entryRemain, remaining);
- Result rc = entry.Storage.Read(entryPos, destination.Slice(outPos, bytesToRead));
+ rc = entry.Storage.Read(entryPos, destination.Slice(outPos, bytesToRead));
if (rc.IsFailure()) return rc;
outPos += bytesToRead;
@@ -65,8 +65,8 @@ public class ConcatenationStorage : IStorage
int outPos = 0;
int remaining = source.Length;
- if (!CheckAccessRange(offset, source.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
int sourceIndex = FindSource(inPos);
@@ -78,7 +78,7 @@ public class ConcatenationStorage : IStorage
int bytesToWrite = (int)Math.Min(entryRemain, remaining);
- Result rc = entry.Storage.Write(entryPos, source.Slice(outPos, bytesToWrite));
+ rc = entry.Storage.Write(entryPos, source.Slice(outPos, bytesToWrite));
if (rc.IsFailure()) return rc;
outPos += bytesToWrite;
diff --git a/src/LibHac/Tools/FsSystem/Save/DuplexStorage.cs b/src/LibHac/Tools/FsSystem/Save/DuplexStorage.cs
index af0e4d32..6b535543 100644
--- a/src/LibHac/Tools/FsSystem/Save/DuplexStorage.cs
+++ b/src/LibHac/Tools/FsSystem/Save/DuplexStorage.cs
@@ -33,8 +33,8 @@ public class DuplexStorage : IStorage
int outPos = 0;
int remaining = destination.Length;
- if (!CheckAccessRange(offset, destination.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
while (remaining > 0)
{
@@ -45,7 +45,7 @@ public class DuplexStorage : IStorage
IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA;
- Result rc = data.Read(inPos, destination.Slice(outPos, bytesToRead));
+ rc = data.Read(inPos, destination.Slice(outPos, bytesToRead));
if (rc.IsFailure()) return rc;
outPos += bytesToRead;
@@ -62,8 +62,8 @@ public class DuplexStorage : IStorage
int outPos = 0;
int remaining = source.Length;
- if (!CheckAccessRange(offset, source.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
while (remaining > 0)
{
@@ -74,7 +74,7 @@ public class DuplexStorage : IStorage
IStorage data = Bitmap.Bitmap[blockNum] ? DataB : DataA;
- Result rc = data.Write(inPos, source.Slice(outPos, bytesToWrite));
+ rc = data.Write(inPos, source.Slice(outPos, bytesToWrite));
if (rc.IsFailure()) return rc;
outPos += bytesToWrite;
diff --git a/src/LibHac/Tools/FsSystem/Save/JournalStorage.cs b/src/LibHac/Tools/FsSystem/Save/JournalStorage.cs
index 7d681963..4e3774a9 100644
--- a/src/LibHac/Tools/FsSystem/Save/JournalStorage.cs
+++ b/src/LibHac/Tools/FsSystem/Save/JournalStorage.cs
@@ -40,8 +40,8 @@ public class JournalStorage : IStorage
int outPos = 0;
int remaining = destination.Length;
- if (!CheckAccessRange(offset, destination.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, destination.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
while (remaining > 0)
{
@@ -52,7 +52,7 @@ public class JournalStorage : IStorage
int bytesToRead = Math.Min(remaining, BlockSize - blockPos);
- Result rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead));
+ rc = BaseStorage.Read(physicalOffset, destination.Slice(outPos, bytesToRead));
if (rc.IsFailure()) return rc;
outPos += bytesToRead;
@@ -69,8 +69,8 @@ public class JournalStorage : IStorage
int outPos = 0;
int remaining = source.Length;
- if (!CheckAccessRange(offset, source.Length, Length))
- return ResultFs.OutOfRange.Log();
+ Result rc = CheckAccessRange(offset, source.Length, Length);
+ if (rc.IsFailure()) return rc.Miss();
while (remaining > 0)
{
@@ -81,7 +81,7 @@ public class JournalStorage : IStorage
int bytesToWrite = Math.Min(remaining, BlockSize - blockPos);
- Result rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite));
+ rc = BaseStorage.Write(physicalOffset, source.Slice(outPos, bytesToWrite));
if (rc.IsFailure()) return rc;
outPos += bytesToWrite;
diff --git a/src/LibHac/Util/IntUtil.cs b/src/LibHac/Util/IntUtil.cs
new file mode 100644
index 00000000..c0582580
--- /dev/null
+++ b/src/LibHac/Util/IntUtil.cs
@@ -0,0 +1,37 @@
+namespace LibHac.Util;
+
+public static class IntUtil
+{
+ // Todo: Use generic math once C# 11 is out
+ public static bool IsIntValueRepresentableAsLong(ulong value)
+ {
+ return value <= long.MaxValue;
+ }
+
+ public static bool IsIntValueRepresentableAsULong(long value)
+ {
+ return value >= 0;
+ }
+
+ public static bool IsIntValueRepresentableAsUInt(long value)
+ {
+ return value >= uint.MinValue && value <= uint.MaxValue;
+ }
+
+ public static bool CanAddWithoutOverflow(long x, long y)
+ {
+ if (y >= 0)
+ {
+ return x <= long.MaxValue - y;
+ }
+ else
+ {
+ return x >= unchecked(long.MinValue - y);
+ }
+ }
+
+ public static bool CanAddWithoutOverflow(ulong x, ulong y)
+ {
+ return x <= ulong.MaxValue - y;
+ }
+}
\ No newline at end of file