Finish OpenFileSystemWithId enough to work with most content

This commit is contained in:
Alex Barney 2020-03-10 15:07:06 -07:00
parent 281fc8aac3
commit 036e048208
9 changed files with 219 additions and 18 deletions

View file

@ -81,6 +81,8 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
2,4464,,AllocationTableIteratedRangeEntry, 2,4464,,AllocationTableIteratedRangeEntry,
2,4501,4599,NcaCorrupted, 2,4501,4599,NcaCorrupted,
2,4512,,InvalidNcaFsType,
2,4527,,InvalidNcaProgramId,
2,4601,4639,IntegrityVerificationStorageCorrupted, 2,4601,4639,IntegrityVerificationStorageCorrupted,
2,4602,,InvalidIvfcMagic, 2,4602,,InvalidIvfcMagic,

1 Module,DescriptionStart,DescriptionEnd,Name,Summary
81 2,4645,,InvalidHashedPartitionFileSystemMagic, 2,4643,,InvalidPartitionFileSystemHash,
82 2,4646,,InvalidPartitionFileSystemEntryNameOffset, 2,4644,,InvalidPartitionFileSystemMagic,
83 2,4661,4679,BuiltInStorageCorrupted, 2,4645,,InvalidHashedPartitionFileSystemMagic,
84 2,4646,,InvalidPartitionFileSystemEntryNameOffset,
85 2,4661,4679,BuiltInStorageCorrupted,
86 2,4662,,InvalidGptPartitionSignature,
87 2,4681,4699,FatFileSystemCorrupted,
88 2,4701,4719,HostFileSystemCorrupted,

View file

@ -6,10 +6,10 @@ namespace LibHac.Fs
{ {
public class FileStorage2 : StorageBase public class FileStorage2 : StorageBase
{ {
private const long InvalidSize = -1; protected const long InvalidSize = -1;
private IFile BaseFile { get; set; } private IFile BaseFile { get; set; }
private long FileSize { get; set; } protected long FileSize { get; set; }
public FileStorage2(IFile baseFile) public FileStorage2(IFile baseFile)
{ {

View file

@ -9,7 +9,10 @@ namespace LibHac.Fs
private IFileSystem BaseFileSystem { get; set; } private IFileSystem BaseFileSystem { get; set; }
private IFile BaseFile { get; set; } private IFile BaseFile { get; set; }
private FileStorageBasedFileSystem() { } private FileStorageBasedFileSystem()
{
FileSize = InvalidSize;
}
public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, U8Span path, public static Result CreateNew(out FileStorageBasedFileSystem created, IFileSystem baseFileSystem, U8Span path,
OpenMode mode) OpenMode mode)

View file

@ -171,6 +171,10 @@ namespace LibHac.Fs
/// <summary>Error code: 2002-4501; Range: 4501-4599; Inner value: 0x232a02</summary> /// <summary>Error code: 2002-4501; Range: 4501-4599; Inner value: 0x232a02</summary>
public static Result.Base NcaCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4501, 4599); } public static Result.Base NcaCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4501, 4599); }
/// <summary>Error code: 2002-4512; Inner value: 0x234002</summary>
public static Result.Base InvalidNcaFsType => new Result.Base(ModuleFs, 4512);
/// <summary>Error code: 2002-4527; Inner value: 0x235e02</summary>
public static Result.Base InvalidNcaProgramId => new Result.Base(ModuleFs, 4527);
/// <summary>Error code: 2002-4601; Range: 4601-4639; Inner value: 0x23f202</summary> /// <summary>Error code: 2002-4601; Range: 4601-4639; Inner value: 0x23f202</summary>
public static Result.Base IntegrityVerificationStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4601, 4639); } public static Result.Base IntegrityVerificationStorageCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4601, 4639); }

View file

@ -1,13 +1,15 @@
using System; using LibHac.Fs;
using LibHac.Fs; using LibHac.FsSystem.RomFs;
namespace LibHac.FsService.Creators namespace LibHac.FsService.Creators
{ {
public class RomFileSystemCreator : IRomFileSystemCreator public class RomFileSystemCreator : IRomFileSystemCreator
{ {
// todo: Implement properly
public Result Create(out IFileSystem fileSystem, IStorage romFsStorage) public Result Create(out IFileSystem fileSystem, IStorage romFsStorage)
{ {
throw new NotImplementedException(); fileSystem = new RomFsFileSystem(romFsStorage);
return Result.Success;
} }
} }
} }

View file

@ -1,14 +1,46 @@
using System; using System;
using LibHac.Fs; using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.FsSystem.Detail;
using LibHac.FsSystem.NcaUtils; using LibHac.FsSystem.NcaUtils;
namespace LibHac.FsService.Creators namespace LibHac.FsService.Creators
{ {
public class StorageOnNcaCreator : IStorageOnNcaCreator public class StorageOnNcaCreator : IStorageOnNcaCreator
{ {
private bool IsEnabledProgramVerification { get; set; }
private Keyset Keyset { get; }
public StorageOnNcaCreator(Keyset keyset)
{
Keyset = keyset;
}
// todo: Implement NcaReader and other Nca classes
public Result Create(out IStorage storage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs) public Result Create(out IStorage storage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs)
{ {
throw new NotImplementedException(); storage = default;
fsHeader = default;
Result rc = OpenStorage(out IStorage storageTemp, nca, fsIndex);
if (rc.IsFailure()) return rc;
if (isCodeFs)
{
using (var codeFs = new PartitionFileSystemCore<StandardEntry>())
{
rc = codeFs.Initialize(storageTemp);
if (rc.IsFailure()) return rc;
rc = VerifyAcidSignature(codeFs, nca);
if (rc.IsFailure()) return rc;
}
}
storage = storageTemp;
fsHeader = nca.Header.GetFsHeader(fsIndex);
return Result.Success;
} }
public Result CreateWithPatch(out IStorage storage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs) public Result CreateWithPatch(out IStorage storage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs)
@ -18,12 +50,25 @@ namespace LibHac.FsService.Creators
public Result OpenNca(out Nca nca, IStorage ncaStorage) public Result OpenNca(out Nca nca, IStorage ncaStorage)
{ {
throw new NotImplementedException(); nca = new Nca(Keyset, ncaStorage);
return Result.Success;
} }
public Result VerifyAcidSignature(IFileSystem codeFileSystem, Nca nca) public Result VerifyAcidSignature(IFileSystem codeFileSystem, Nca nca)
{ {
throw new NotImplementedException(); // todo
return Result.Success;
}
private Result OpenStorage(out IStorage storage, Nca nca, int fsIndex)
{
storage = default;
if (!nca.SectionExists(fsIndex))
return ResultFs.PartitionNotFound.Log();
storage = nca.OpenStorage(fsIndex, IntegrityCheckLevel.ErrorOnInvalid);
return Result.Success;
} }
} }
} }

View file

@ -20,7 +20,7 @@ namespace LibHac.FsService
creators.RomFileSystemCreator = new RomFileSystemCreator(); creators.RomFileSystemCreator = new RomFileSystemCreator();
creators.PartitionFileSystemCreator = new PartitionFileSystemCreator(); creators.PartitionFileSystemCreator = new PartitionFileSystemCreator();
creators.StorageOnNcaCreator = new StorageOnNcaCreator(); creators.StorageOnNcaCreator = new StorageOnNcaCreator(keyset);
creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator(); creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator();
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset); creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset);

View file

@ -40,11 +40,22 @@ namespace LibHac.FsService
bool canMountSystemDataPrivate = false; bool canMountSystemDataPrivate = false;
Result rc = PathTools.Normalize(out U8Span normalizedPath, path); var normalizer = new PathNormalizer(path, GetPathNormalizerOptions(path));
if (rc.IsFailure()) return rc; if (normalizer.Result.IsFailure()) return normalizer.Result;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse // ReSharper disable once ConditionIsAlwaysTrueOrFalse
return FsProxyCore.OpenFileSystem(out fileSystem, normalizedPath, type, canMountSystemDataPrivate, titleId); return FsProxyCore.OpenFileSystem(out fileSystem, normalizer.Path, type, canMountSystemDataPrivate, titleId);
}
private PathNormalizer.Option GetPathNormalizerOptions(U8Span path)
{
int hostMountLength = StringUtils.GetLength(CommonMountNames.HostRootFileSystemMountName,
PathTools.MountNameLengthMax);
bool isHostPath = StringUtils.Compare(path, CommonMountNames.HostRootFileSystemMountName, hostMountLength) == 0;
PathNormalizer.Option hostOption = isHostPath ? PathNormalizer.Option.PreserveUnc : PathNormalizer.Option.None;
return PathNormalizer.Option.HasMountName | PathNormalizer.Option.PreserveTailSeparator | hostOption;
} }
public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemProxyType type) public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemProxyType type)

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
@ -96,9 +97,19 @@ namespace LibHac.FsService
rc = TryOpenNca(ref path2, out Nca nca, baseFileSystem, openTitleId); rc = TryOpenNca(ref path2, out Nca nca, baseFileSystem, openTitleId);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
rc = OpenNcaStorage(out IStorage ncaSectionStorage, nca, out NcaFormatType fsType, type,
mountNameInfo.IsGameCard, canMountSystemDataPrivate);
if (rc.IsFailure()) return rc;
switch (fsType)
throw new NotImplementedException(); {
case NcaFormatType.Romfs:
return FsCreators.RomFileSystemCreator.Create(out fileSystem, ncaSectionStorage);
case NcaFormatType.Pfs0:
return FsCreators.PartitionFileSystemCreator.Create(out fileSystem, ncaSectionStorage);
default:
return ResultFs.InvalidNcaFsType.Log();
}
} }
/// <summary> /// <summary>
@ -340,9 +351,132 @@ namespace LibHac.FsService
return rc; return rc;
} }
private Result TryOpenNca(ref U8Span path, out Nca nca, IFileSystem baseFileSystem, TitleId titleId) private Result TryOpenNca(ref U8Span path, out Nca nca, IFileSystem baseFileSystem, TitleId programId)
{ {
throw new NotImplementedException(); nca = default;
Result rc = FileStorageBasedFileSystem.CreateNew(out FileStorageBasedFileSystem ncaFileStorage,
baseFileSystem, path, OpenMode.Read);
if (rc.IsFailure()) return rc;
rc = FsCreators.StorageOnNcaCreator.OpenNca(out Nca ncaTemp, ncaFileStorage);
if (rc.IsFailure()) return rc;
if (programId.Value == ulong.MaxValue)
{
ulong ncaProgramId = ncaTemp.Header.TitleId;
if (ncaProgramId != ulong.MaxValue && programId.Value != ncaProgramId)
{
return ResultFs.InvalidNcaProgramId.Log();
}
}
nca = ncaTemp;
return Result.Success;
}
private Result OpenNcaStorage(out IStorage ncaStorage, Nca nca, out NcaFormatType fsType,
FileSystemProxyType fsProxyType, bool isGameCard, bool canMountSystemDataPrivate)
{
ncaStorage = default;
fsType = default;
NcaContentType contentType = nca.Header.ContentType;
switch (fsProxyType)
{
case FileSystemProxyType.Code:
case FileSystemProxyType.Rom:
case FileSystemProxyType.Logo:
case FileSystemProxyType.RegisteredUpdate:
if (contentType != NcaContentType.Program)
return ResultFs.PreconditionViolation.Log();
break;
case FileSystemProxyType.Control:
if (contentType != NcaContentType.Control)
return ResultFs.PreconditionViolation.Log();
break;
case FileSystemProxyType.Manual:
if (contentType != NcaContentType.Manual)
return ResultFs.PreconditionViolation.Log();
break;
case FileSystemProxyType.Meta:
if (contentType != NcaContentType.Meta)
return ResultFs.PreconditionViolation.Log();
break;
case FileSystemProxyType.Data:
if (contentType != NcaContentType.Data && contentType != NcaContentType.PublicData)
return ResultFs.PreconditionViolation.Log();
if (contentType == NcaContentType.Data && !canMountSystemDataPrivate)
return ResultFs.PermissionDenied.Log();
break;
default:
return ResultFs.InvalidArgument.Log();
}
if (nca.Header.DistributionType == DistributionType.GameCard && !isGameCard)
return ResultFs.PermissionDenied.Log();
Result rc = SetNcaExternalKey(nca);
if (rc.IsFailure()) return rc;
rc = GetNcaSectionIndex(out int sectionIndex, fsProxyType);
if (rc.IsFailure()) return rc;
rc = FsCreators.StorageOnNcaCreator.Create(out ncaStorage, out NcaFsHeader fsHeader, nca,
sectionIndex, fsProxyType == FileSystemProxyType.Code);
if (rc.IsFailure()) return rc;
fsType = fsHeader.FormatType;
return Result.Success;
}
private Result SetNcaExternalKey(Nca nca)
{
var rightsId = new RightsId(nca.Header.RightsId);
var zero = new RightsId(0, 0);
if (Crypto.CryptoUtil.IsSameBytes(rightsId.AsBytes(), zero.AsBytes(), Unsafe.SizeOf<RightsId>()))
return Result.Success;
Result rc = ExternalKeys.Get(rightsId, out AccessKey accessKey);
if (rc.IsFailure()) return rc;
// todo: Set key in nca reader
return Result.Success;
}
private Result GetNcaSectionIndex(out int index, FileSystemProxyType fspType)
{
switch (fspType)
{
case FileSystemProxyType.Code:
case FileSystemProxyType.Control:
case FileSystemProxyType.Manual:
case FileSystemProxyType.Meta:
case FileSystemProxyType.Data:
index = 0;
return Result.Success;
case FileSystemProxyType.Rom:
case FileSystemProxyType.RegisteredUpdate:
index = 1;
return Result.Success;
case FileSystemProxyType.Logo:
index = 2;
return Result.Success;
default:
index = default;
return ResultFs.InvalidArgument.Log();
}
} }
public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId) public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId)