mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement NpdmVerificationFileSystem
This commit is contained in:
parent
4a7b67bf5a
commit
dd2b9fe2ca
4 changed files with 115 additions and 108 deletions
|
@ -76,9 +76,9 @@ public class ReadOnlyFileSystem : IFileSystem
|
|||
{
|
||||
private SharedRef<IFileSystem> _baseFileSystem;
|
||||
|
||||
public ReadOnlyFileSystem(ref SharedRef<IFileSystem> baseFileSystem)
|
||||
public ReadOnlyFileSystem(ref readonly SharedRef<IFileSystem> baseFileSystem)
|
||||
{
|
||||
_baseFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem);
|
||||
_baseFileSystem = SharedRef<IFileSystem>.CreateCopy(in baseFileSystem);
|
||||
|
||||
Assert.SdkRequires(_baseFileSystem.HasValue);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
|
||||
|
@ -12,14 +13,20 @@ public struct NpdmHash
|
|||
private byte _data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="IFile"/>. When reading, calculates a hash of the entire file and compares it to the file's
|
||||
/// original hash to ensure the file hasn't been modified.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class NpdmVerificationFile : IFile
|
||||
{
|
||||
private NpdmHash _hash;
|
||||
private readonly NpdmHash _hash;
|
||||
private UniqueRef<IFile> _baseFile;
|
||||
|
||||
public NpdmVerificationFile(ref UniqueRef<IFile> baseFile, NpdmHash hash)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_hash = hash;
|
||||
_baseFile = UniqueRef<IFile>.Create(ref baseFile);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
|
@ -30,143 +37,143 @@ public class NpdmVerificationFile : IFile
|
|||
|
||||
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
UnsafeHelpers.SkipParamInit(out bytesRead);
|
||||
|
||||
Result res = DryRead(out long readableSize, offset, destination.Length, in option, OpenMode.Read);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
byte[] hashData;
|
||||
byte[] npdmData = null;
|
||||
|
||||
res = ReadAndCalculateNpdmHash();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (!CryptoUtil.IsSameBytes(hashData.AsSpan(), _hash, Unsafe.SizeOf<NpdmHash>()))
|
||||
return ResultFs.InvalidNspdVerificationData.Log();
|
||||
|
||||
npdmData.AsSpan((int)offset, (int)readableSize).CopyTo(destination);
|
||||
return Result.Success;
|
||||
|
||||
Result ReadAndCalculateNpdmHash()
|
||||
{
|
||||
hashData = new byte[0x20];
|
||||
Result res2 = _baseFile.Get.GetSize(out long npdmDataSize);
|
||||
if (res2.IsFailure()) return res2.Miss();
|
||||
|
||||
npdmData = new byte[npdmDataSize];
|
||||
res2 = _baseFile.Get.Read(out long npdmReadSize, 0, npdmData, ReadOption.None);
|
||||
if (res2.IsFailure()) return res2.Miss();
|
||||
|
||||
Sha256.GenerateSha256Hash(npdmData.AsSpan(0, (int)npdmReadSize), hashData);
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option) =>
|
||||
_baseFile.Get.Write(offset, source, in option).Ret();
|
||||
|
||||
protected override Result DoFlush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoFlush() => _baseFile.Get.Flush().Ret();
|
||||
protected override Result DoSetSize(long size) => _baseFile.Get.SetSize(size).Ret();
|
||||
protected override Result DoGetSize(out long size) => _baseFile.Get.GetSize(out size).Ret();
|
||||
|
||||
protected override Result DoSetSize(long size)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Result DoGetSize(out long size)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||
ReadOnlySpan<byte> inBuffer) =>
|
||||
_baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer).Ret();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a code <see cref="IFileSystem"/>. Contains the hash of the code filesystem's .npdm file. When opening the npdm
|
||||
/// file, a <see cref="NpdmVerificationFile"/> is used to ensure that the npdm file hasn't been modified.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class NpdmVerificationFileSystem : IFileSystem
|
||||
{
|
||||
private NpdmHash _hash;
|
||||
private ReadOnlyFileSystem _baseFileSystem;
|
||||
private static ReadOnlySpan<byte> NpdmFilePath => "/main.npdm"u8;
|
||||
|
||||
public NpdmVerificationFileSystem(in SharedRef<IFileSystem> baseFileSystem, NpdmHash hash)
|
||||
private readonly NpdmHash _hash;
|
||||
private readonly ReadOnlyFileSystem _baseFileSystem;
|
||||
|
||||
public NpdmVerificationFileSystem(ref readonly SharedRef<IFileSystem> baseFileSystem, NpdmHash hash)
|
||||
{
|
||||
|
||||
_hash = hash;
|
||||
_baseFileSystem = new ReadOnlyFileSystem(in baseFileSystem);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_baseFileSystem.Dispose();
|
||||
_baseFileSystem?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, ref readonly Path path, OpenMode mode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using var file = new UniqueRef<IFile>();
|
||||
Result res = _baseFileSystem.OpenFile(ref file.Ref, in path, mode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (path != NpdmFilePath)
|
||||
{
|
||||
outFile.Set(ref file.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
using var npdmFile = new UniqueRef<IFile>(new NpdmVerificationFile(ref file.Ref, _hash));
|
||||
|
||||
outFile.Set(ref npdmFile.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option) =>
|
||||
_baseFileSystem.CreateFile(in path, size, option).Ret();
|
||||
|
||||
protected override Result DoDeleteFile(ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoDeleteFile(ref readonly Path path) =>
|
||||
_baseFileSystem.DeleteFile(in path).Ret();
|
||||
|
||||
protected override Result DoCreateDirectory(ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoCreateDirectory(ref readonly Path path) =>
|
||||
_baseFileSystem.CreateDirectory(in path).Ret();
|
||||
|
||||
protected override Result DoDeleteDirectory(ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoDeleteDirectory(ref readonly Path path) =>
|
||||
_baseFileSystem.DeleteDirectory(in path).Ret();
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path) =>
|
||||
_baseFileSystem.DeleteDirectoryRecursively(in path).Ret();
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoCleanDirectoryRecursively(ref readonly Path path) =>
|
||||
_baseFileSystem.CleanDirectoryRecursively(in path).Ret();
|
||||
|
||||
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath) =>
|
||||
_baseFileSystem.RenameFile(in currentPath, in newPath).Ret();
|
||||
|
||||
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath) =>
|
||||
_baseFileSystem.RenameDirectory(in currentPath, in newPath).Ret();
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path) =>
|
||||
_baseFileSystem.GetEntryType(out entryType, in path).Ret();
|
||||
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path) =>
|
||||
_baseFileSystem.GetFreeSpaceSize(out freeSpace, in path).Ret();
|
||||
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path) =>
|
||||
_baseFileSystem.GetFreeSpaceSize(out totalSpace, in path).Ret();
|
||||
|
||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path, OpenDirectoryMode mode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path, OpenDirectoryMode mode) =>
|
||||
_baseFileSystem.OpenDirectory(ref outDirectory, in path, mode).Ret();
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoCommit() =>
|
||||
_baseFileSystem.Commit().Ret();
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoCommitProvisionally(long counter) =>
|
||||
_baseFileSystem.CommitProvisionally(counter).Ret();
|
||||
|
||||
protected override Result DoRollback()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoRollback() =>
|
||||
_baseFileSystem.Rollback().Ret();
|
||||
|
||||
protected override Result DoFlush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoFlush() =>
|
||||
_baseFileSystem.Flush().Ret();
|
||||
|
||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, ref readonly Path path) =>
|
||||
_baseFileSystem.GetFileTimeStampRaw(out timeStamp, in path).Ret();
|
||||
|
||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, ref readonly Path path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, ref readonly Path path) =>
|
||||
_baseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, in path).Ret();
|
||||
}
|
|
@ -312,7 +312,7 @@ public class NcaFileSystemServiceImpl : IDisposable
|
|||
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var readOnlyFileSystem = new SharedRef<IFileSystem>(new ReadOnlyFileSystem(ref hostFileSystem.Ref));
|
||||
using var readOnlyFileSystem = new SharedRef<IFileSystem>(new ReadOnlyFileSystem(in hostFileSystem));
|
||||
outFileSystem.SetByMove(ref readOnlyFileSystem.Ref);
|
||||
|
||||
return Result.Success;
|
||||
|
@ -444,7 +444,7 @@ public class NcaFileSystemServiceImpl : IDisposable
|
|||
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var readOnlyFileSystem = new SharedRef<ReadOnlyFileSystem>(new ReadOnlyFileSystem(ref hostFileSystem.Ref));
|
||||
using var readOnlyFileSystem = new SharedRef<ReadOnlyFileSystem>(new ReadOnlyFileSystem(in hostFileSystem));
|
||||
|
||||
outFileSystem.SetByMove(ref readOnlyFileSystem.Ref);
|
||||
return Result.Success;
|
||||
|
|
|
@ -321,7 +321,7 @@ public class SaveDataFileSystemServiceImpl : IDisposable
|
|||
if (openReadOnly)
|
||||
{
|
||||
using SharedRef<IFileSystem> tempFs = SharedRef<IFileSystem>.CreateMove(ref registerFs.Ref);
|
||||
using var readOnlyFileSystem = new SharedRef<ReadOnlyFileSystem>(new ReadOnlyFileSystem(ref tempFs.Ref));
|
||||
using var readOnlyFileSystem = new SharedRef<ReadOnlyFileSystem>(new ReadOnlyFileSystem(in tempFs));
|
||||
|
||||
if (!readOnlyFileSystem.HasValue)
|
||||
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemServiceImplB.Log();
|
||||
|
|
Loading…
Reference in a new issue