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;
|
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);
|
Assert.SdkRequires(_baseFileSystem.HasValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
|
using LibHac.Crypto;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
|
|
||||||
|
@ -12,14 +13,20 @@ public struct NpdmHash
|
||||||
private byte _data;
|
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
|
public class NpdmVerificationFile : IFile
|
||||||
{
|
{
|
||||||
private NpdmHash _hash;
|
private readonly NpdmHash _hash;
|
||||||
private UniqueRef<IFile> _baseFile;
|
private UniqueRef<IFile> _baseFile;
|
||||||
|
|
||||||
public NpdmVerificationFile(ref UniqueRef<IFile> baseFile, NpdmHash hash)
|
public NpdmVerificationFile(ref UniqueRef<IFile> baseFile, NpdmHash hash)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_hash = hash;
|
||||||
|
_baseFile = UniqueRef<IFile>.Create(ref baseFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
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)
|
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)
|
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option) =>
|
||||||
{
|
_baseFile.Get.Write(offset, source, in option).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoFlush()
|
protected override Result DoFlush() => _baseFile.Get.Flush().Ret();
|
||||||
{
|
protected override Result DoSetSize(long size) => _baseFile.Get.SetSize(size).Ret();
|
||||||
throw new NotImplementedException();
|
protected override Result DoGetSize(out long size) => _baseFile.Get.GetSize(out size).Ret();
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoSetSize(long size)
|
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
|
||||||
{
|
ReadOnlySpan<byte> inBuffer) =>
|
||||||
throw new NotImplementedException();
|
_baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer).Ret();
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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
|
public class NpdmVerificationFileSystem : IFileSystem
|
||||||
{
|
{
|
||||||
private NpdmHash _hash;
|
private static ReadOnlySpan<byte> NpdmFilePath => "/main.npdm"u8;
|
||||||
private ReadOnlyFileSystem _baseFileSystem;
|
|
||||||
|
|
||||||
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()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
_baseFileSystem.Dispose();
|
_baseFileSystem?.Dispose();
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, ref readonly Path path, OpenMode mode)
|
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)
|
protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option) =>
|
||||||
{
|
_baseFileSystem.CreateFile(in path, size, option).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoDeleteFile(ref readonly Path path)
|
protected override Result DoDeleteFile(ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.DeleteFile(in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoCreateDirectory(ref readonly Path path)
|
protected override Result DoCreateDirectory(ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.CreateDirectory(in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoDeleteDirectory(ref readonly Path path)
|
protected override Result DoDeleteDirectory(ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.DeleteDirectory(in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path)
|
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.DeleteDirectoryRecursively(in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoCleanDirectoryRecursively(ref readonly Path path)
|
protected override Result DoCleanDirectoryRecursively(ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.CleanDirectoryRecursively(in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath)
|
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath) =>
|
||||||
{
|
_baseFileSystem.RenameFile(in currentPath, in newPath).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath)
|
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath) =>
|
||||||
{
|
_baseFileSystem.RenameDirectory(in currentPath, in newPath).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path)
|
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.GetEntryType(out entryType, in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path)
|
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.GetFreeSpaceSize(out freeSpace, in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path)
|
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.GetFreeSpaceSize(out totalSpace, in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path, OpenDirectoryMode mode)
|
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path, OpenDirectoryMode mode) =>
|
||||||
{
|
_baseFileSystem.OpenDirectory(ref outDirectory, in path, mode).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoCommit()
|
protected override Result DoCommit() =>
|
||||||
{
|
_baseFileSystem.Commit().Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoCommitProvisionally(long counter)
|
protected override Result DoCommitProvisionally(long counter) =>
|
||||||
{
|
_baseFileSystem.CommitProvisionally(counter).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoRollback()
|
protected override Result DoRollback() =>
|
||||||
{
|
_baseFileSystem.Rollback().Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoFlush()
|
protected override Result DoFlush() =>
|
||||||
{
|
_baseFileSystem.Flush().Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, ref readonly Path path)
|
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.GetFileTimeStampRaw(out timeStamp, in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, ref readonly Path path)
|
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, ref readonly Path path) =>
|
||||||
{
|
_baseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, in path).Ret();
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -312,7 +312,7 @@ public class NcaFileSystemServiceImpl : IDisposable
|
||||||
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
||||||
if (res.IsFailure()) return res.Miss();
|
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);
|
outFileSystem.SetByMove(ref readOnlyFileSystem.Ref);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -444,7 +444,7 @@ public class NcaFileSystemServiceImpl : IDisposable
|
||||||
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
res = ParseDirWithPathCaseNormalizationOnCaseSensitiveHostOrLocalFs(ref hostFileSystem.Ref, in directoryPath, mountInfo.FsType);
|
||||||
if (res.IsFailure()) return res.Miss();
|
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);
|
outFileSystem.SetByMove(ref readOnlyFileSystem.Ref);
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
|
@ -321,7 +321,7 @@ public class SaveDataFileSystemServiceImpl : IDisposable
|
||||||
if (openReadOnly)
|
if (openReadOnly)
|
||||||
{
|
{
|
||||||
using SharedRef<IFileSystem> tempFs = SharedRef<IFileSystem>.CreateMove(ref registerFs.Ref);
|
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)
|
if (!readOnlyFileSystem.HasValue)
|
||||||
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemServiceImplB.Log();
|
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemServiceImplB.Log();
|
||||||
|
|
Loading…
Reference in a new issue