mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add BaseFileSystemService
This commit is contained in:
parent
122e83defe
commit
be55aa7e9c
13 changed files with 388 additions and 20 deletions
|
@ -205,6 +205,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
|||
2,4812,,IncompleteBlockInZeroBitmapHashStorageFile,
|
||||
|
||||
2,5000,5999,Unexpected,
|
||||
2,5121,,UnexpectedFatFileSystemSectorCount,
|
||||
2,5307,,UnexpectedErrorInHostFileFlush,
|
||||
2,5308,,UnexpectedErrorInHostFileGetSize,
|
||||
2,5309,,UnknownHostFileSystemError,
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 203.
|
|
@ -305,6 +305,8 @@ namespace LibHac.Fs
|
|||
|
||||
/// <summary>Error code: 2002-5000; Range: 5000-5999; Inner value: 0x271002</summary>
|
||||
public static Result.Base Unexpected { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 5000, 5999); }
|
||||
/// <summary>Error code: 2002-5121; Inner value: 0x280202</summary>
|
||||
public static Result.Base UnexpectedFatFileSystemSectorCount => new Result.Base(ModuleFs, 5121);
|
||||
/// <summary>Error code: 2002-5307; Inner value: 0x297602</summary>
|
||||
public static Result.Base UnexpectedErrorInHostFileFlush => new Result.Base(ModuleFs, 5307);
|
||||
/// <summary>Error code: 2002-5308; Inner value: 0x297802</summary>
|
||||
|
|
205
src/LibHac/FsSrv/BaseFileSystemService.cs
Normal file
205
src/LibHac/FsSrv/BaseFileSystemService.cs
Normal file
|
@ -0,0 +1,205 @@
|
|||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Sf;
|
||||
|
||||
namespace LibHac.FsSrv
|
||||
{
|
||||
public readonly struct BaseFileSystemService
|
||||
{
|
||||
private readonly BaseFileSystemServiceImpl _serviceImpl;
|
||||
private readonly ulong _processId;
|
||||
|
||||
public BaseFileSystemService(BaseFileSystemServiceImpl serviceImpl, ulong processId)
|
||||
{
|
||||
_serviceImpl = serviceImpl;
|
||||
_processId = processId;
|
||||
}
|
||||
|
||||
public Result OpenBisFileSystem(out IFileSystem fileSystem, in FspPath rootPath, BisPartitionId partitionId)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Get the permissions the caller needs
|
||||
AccessibilityType requiredAccess = partitionId switch
|
||||
{
|
||||
BisPartitionId.CalibrationFile => AccessibilityType.MountBisCalibrationFile,
|
||||
BisPartitionId.SafeMode => AccessibilityType.MountBisSafeMode,
|
||||
BisPartitionId.User => AccessibilityType.MountBisUser,
|
||||
BisPartitionId.System => AccessibilityType.MountBisSystem,
|
||||
BisPartitionId.SystemProperPartition => AccessibilityType.MountBisSystemProperPartition,
|
||||
_ => AccessibilityType.NotMount
|
||||
};
|
||||
|
||||
// Reject opening invalid partitions
|
||||
if (requiredAccess == AccessibilityType.NotMount)
|
||||
return ResultFs.InvalidAlignment.Log();
|
||||
|
||||
// Verify the caller has the required permissions
|
||||
Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(requiredAccess);
|
||||
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
// Normalize the path
|
||||
var normalizer = new PathNormalizer(rootPath, PathNormalizer.Option.AcceptEmpty);
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
rc = _serviceImpl.OpenBisFileSystem(out IFileSystem bisFs, normalizer.Path, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fileSystem = bisFs;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreatePaddingFile(long size)
|
||||
{
|
||||
// File size must be non-negative
|
||||
if (size < 0)
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
// Caller must have the FillBis permission
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!programInfo.AccessControl.CanCall(OperationType.FillBis))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.CreatePaddingFile(size);
|
||||
}
|
||||
|
||||
public Result DeleteAllPaddingFiles()
|
||||
{
|
||||
// Caller must have the FillBis permission
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!programInfo.AccessControl.CanCall(OperationType.FillBis))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.DeleteAllPaddingFiles();
|
||||
}
|
||||
|
||||
public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle,
|
||||
GameCardPartition partitionId)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountGameCard).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = _serviceImpl.OpenGameCardFileSystem(out IFileSystem gcFs, handle, partitionId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fileSystem = gcFs;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSdCardFileSystem(out IFileSystem fileSystem)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountSdCard);
|
||||
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = _serviceImpl.OpenSdCardProxyFileSystem(out IFileSystem sdCardFs);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fileSystem = sdCardFs;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result FormatSdCardFileSystem()
|
||||
{
|
||||
// Caller must have the FormatSdCard permission
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!programInfo.AccessControl.CanCall(OperationType.FormatSdCard))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
return _serviceImpl.FormatSdCardProxyFileSystem();
|
||||
}
|
||||
|
||||
public Result FormatSdCardDryRun()
|
||||
{
|
||||
// No permissions are needed to call this method
|
||||
|
||||
return _serviceImpl.FormatSdCardProxyFileSystem();
|
||||
}
|
||||
|
||||
public Result IsExFatSupported(out bool isSupported)
|
||||
{
|
||||
// No permissions are needed to call this method
|
||||
|
||||
isSupported = _serviceImpl.IsExFatSupported();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenImageDirectoryFileSystem(out IFileSystem fileSystem, ImageDirectoryId directoryId)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
// Caller must have the MountImageAndVideoStorage permission
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Accessibility accessibility =
|
||||
programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountImageAndVideoStorage);
|
||||
|
||||
if (!accessibility.CanRead || !accessibility.CanWrite)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
// Get the base file system ID
|
||||
int id;
|
||||
switch (directoryId)
|
||||
{
|
||||
case ImageDirectoryId.Nand: id = 0; break;
|
||||
case ImageDirectoryId.SdCard: id = 1; break;
|
||||
default:
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
|
||||
rc = _serviceImpl.OpenBaseFileSystem(out IFileSystem imageFs, id);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
fileSystem = imageFs;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenBisWiper(out IWiper bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
|
||||
{
|
||||
bisWiper = default;
|
||||
|
||||
// Caller must have the OpenBisWiper permission
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!programInfo.AccessControl.CanCall(OperationType.OpenBisWiper))
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
|
||||
rc = _serviceImpl.OpenBisWiper(out IWiper wiper, transferMemoryHandle, transferMemorySize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bisWiper = wiper;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result GetProgramInfo(out ProgramInfo programInfo)
|
||||
{
|
||||
return _serviceImpl.GetProgramInfo(out programInfo, _processId);
|
||||
}
|
||||
}
|
||||
}
|
113
src/LibHac/FsSrv/BaseFileSystemServiceImpl.cs
Normal file
113
src/LibHac/FsSrv/BaseFileSystemServiceImpl.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv.Creators;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Sf;
|
||||
|
||||
namespace LibHac.FsSrv
|
||||
{
|
||||
public class BaseFileSystemServiceImpl
|
||||
{
|
||||
private Configuration _config;
|
||||
|
||||
public delegate Result BisWiperCreator(out IWiper wiper, NativeHandle transferMemoryHandle,
|
||||
ulong transferMemorySize);
|
||||
|
||||
public BaseFileSystemServiceImpl(in Configuration configuration)
|
||||
{
|
||||
_config = configuration;
|
||||
}
|
||||
|
||||
public struct Configuration
|
||||
{
|
||||
public IBuiltInStorageFileSystemCreator BisFileSystemCreator;
|
||||
public IGameCardFileSystemCreator GameCardFileSystemCreator;
|
||||
public ISdCardProxyFileSystemCreator SdCardFileSystemCreator;
|
||||
// CurrentTimeFunction
|
||||
// FatFileSystemCacheManager
|
||||
// AlbumDirectoryFileSystemManager
|
||||
public BisWiperCreator BisWiperCreator;
|
||||
|
||||
// Note: The program registry service is global as of FS 10.0.0
|
||||
public ProgramRegistryImpl ProgramRegistry;
|
||||
}
|
||||
|
||||
public Result OpenBaseFileSystem(out IFileSystem fileSystem, int fileSystemId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenBisFileSystem(out IFileSystem fileSystem, U8Span rootPath, BisPartitionId partitionId)
|
||||
{
|
||||
return _config.BisFileSystemCreator.Create(out fileSystem, rootPath.ToString(), partitionId);
|
||||
}
|
||||
|
||||
public Result CreatePaddingFile(long size)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result DeleteAllPaddingFiles()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result OpenGameCardFileSystem(out IFileSystem fileSystem, GameCardHandle handle,
|
||||
GameCardPartition partitionId)
|
||||
{
|
||||
Result rc;
|
||||
int tries = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rc = _config.GameCardFileSystemCreator.Create(out fileSystem, handle, partitionId);
|
||||
|
||||
if (!ResultFs.DataCorrupted.Includes(rc))
|
||||
break;
|
||||
|
||||
tries++;
|
||||
} while (tries < 2);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
public Result OpenSdCardProxyFileSystem(out IFileSystem fileSystem)
|
||||
{
|
||||
return OpenSdCardProxyFileSystem(out fileSystem, false);
|
||||
}
|
||||
|
||||
public Result OpenSdCardProxyFileSystem(out IFileSystem fileSystem, bool isCaseSensitive)
|
||||
{
|
||||
return _config.SdCardFileSystemCreator.Create(out fileSystem, isCaseSensitive);
|
||||
}
|
||||
|
||||
public Result FormatSdCardProxyFileSystem()
|
||||
{
|
||||
return _config.SdCardFileSystemCreator.Format();
|
||||
}
|
||||
|
||||
public Result FormatSdCardDryRun()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsExFatSupported()
|
||||
{
|
||||
// Returning false should probably be fine
|
||||
return false;
|
||||
}
|
||||
|
||||
public Result OpenBisWiper(out IWiper wiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
|
||||
{
|
||||
return _config.BisWiperCreator(out wiper, transferMemoryHandle, transferMemorySize);
|
||||
}
|
||||
|
||||
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
|
||||
{
|
||||
return _config.ProgramRegistry.GetProgramInfo(out programInfo, processId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using LibHac.Fs.Fsa;
|
|||
|
||||
namespace LibHac.FsSrv.Creators
|
||||
{
|
||||
public class EmulatedSdFileSystemCreator : ISdFileSystemCreator
|
||||
public class EmulatedSdCardFileSystemCreator : ISdCardProxyFileSystemCreator
|
||||
{
|
||||
private const string DefaultPath = "/sdcard";
|
||||
|
||||
|
@ -14,20 +14,20 @@ namespace LibHac.FsSrv.Creators
|
|||
|
||||
private IFileSystem SdCardFileSystem { get; set; }
|
||||
|
||||
public EmulatedSdFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem)
|
||||
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem)
|
||||
{
|
||||
SdCard = sdCard;
|
||||
RootFileSystem = rootFileSystem;
|
||||
}
|
||||
|
||||
public EmulatedSdFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem, string path)
|
||||
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem, string path)
|
||||
{
|
||||
SdCard = sdCard;
|
||||
RootFileSystem = rootFileSystem;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public Result Create(out IFileSystem fileSystem)
|
||||
public Result Create(out IFileSystem fileSystem, bool isCaseSensitive)
|
||||
{
|
||||
fileSystem = default;
|
||||
|
||||
|
@ -61,7 +61,12 @@ namespace LibHac.FsSrv.Creators
|
|||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Format(bool closeOpenEntries)
|
||||
public Result Format(bool removeFromFatFsCache)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result Format()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
|
@ -17,6 +17,6 @@
|
|||
public IEncryptedFileSystemCreator EncryptedFileSystemCreator { get; set; }
|
||||
public IMemoryStorageCreator MemoryStorageCreator { get; set; }
|
||||
public IBuiltInStorageFileSystemCreator BuiltInStorageFileSystemCreator { get; set; }
|
||||
public ISdFileSystemCreator SdFileSystemCreator { get; set; }
|
||||
public ISdCardProxyFileSystemCreator SdCardFileSystemCreator { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
23
src/LibHac/FsSrv/Creators/ISdCardProxyFileSystemCreator.cs
Normal file
23
src/LibHac/FsSrv/Creators/ISdCardProxyFileSystemCreator.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using LibHac.Fs.Fsa;
|
||||
|
||||
namespace LibHac.FsSrv.Creators
|
||||
{
|
||||
public interface ISdCardProxyFileSystemCreator
|
||||
{
|
||||
Result Create(out IFileSystem fileSystem, bool isCaseSensitive);
|
||||
|
||||
/// <summary>
|
||||
/// Formats the SD card.
|
||||
/// </summary>
|
||||
/// <param name="removeFromFatFsCache">Should the SD card file system be removed from the
|
||||
/// FAT file system cache?</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
Result Format(bool removeFromFatFsCache);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically closes all open proxy file system entries and formats the SD card.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
Result Format();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using LibHac.Fs.Fsa;
|
||||
|
||||
namespace LibHac.FsSrv.Creators
|
||||
{
|
||||
public interface ISdFileSystemCreator
|
||||
{
|
||||
Result Create(out IFileSystem fileSystem);
|
||||
Result Format(bool closeOpenEntries);
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ namespace LibHac.FsSrv
|
|||
creators.GameCardFileSystemCreator = new EmulatedGameCardFsCreator(gcStorageCreator, gameCard);
|
||||
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
|
||||
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem);
|
||||
creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(sdCard, rootFileSystem);
|
||||
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, rootFileSystem);
|
||||
|
||||
var deviceOperator = new EmulatedDeviceOperator(gameCard, sdCard);
|
||||
|
||||
|
|
|
@ -627,7 +627,7 @@ namespace LibHac.FsSrv
|
|||
|
||||
public Result OpenSdCardFileSystem(out IFileSystem fileSystem)
|
||||
{
|
||||
return FsCreators.SdFileSystemCreator.Create(out fileSystem);
|
||||
return FsCreators.SdCardFileSystemCreator.Create(out fileSystem, false);
|
||||
}
|
||||
|
||||
public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId)
|
||||
|
@ -707,7 +707,7 @@ namespace LibHac.FsSrv
|
|||
{
|
||||
case CustomStorageId.SdCard:
|
||||
{
|
||||
Result rc = FsCreators.SdFileSystemCreator.Create(out IFileSystem sdFs);
|
||||
Result rc = FsCreators.SdCardFileSystemCreator.Create(out IFileSystem sdFs, false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
string customStorageDir = CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.SdCard);
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace LibHac.FsSrv
|
|||
/// storage location and file system permissions. This allows FS to resolve the program ID and
|
||||
/// verify the permissions of any process calling it.
|
||||
/// <br/>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
|
||||
internal class ProgramRegistryImpl : IProgramRegistry
|
||||
public class ProgramRegistryImpl : IProgramRegistry
|
||||
{
|
||||
private ulong _processId;
|
||||
|
||||
|
|
8
src/LibHac/FsSrv/Sf/IWiper.cs
Normal file
8
src/LibHac/FsSrv/Sf/IWiper.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace LibHac.FsSrv.Sf
|
||||
{
|
||||
public interface IWiper
|
||||
{
|
||||
public Result Startup(out long spaceToWipe);
|
||||
public Result Process(out long remainingSpaceToWipe);
|
||||
}
|
||||
}
|
21
src/LibHac/Sf/NativeHandle.cs
Normal file
21
src/LibHac/Sf/NativeHandle.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace LibHac.Sf
|
||||
{
|
||||
// How should this be handled? Using a C# struct would be more accurate, but C#
|
||||
// doesn't have copy constructors or any way to prevent a struct from being copied.
|
||||
public class NativeHandle
|
||||
{
|
||||
public uint Handle { get; private set; }
|
||||
public bool IsManaged { get; private set; }
|
||||
|
||||
public NativeHandle(uint handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
public NativeHandle(uint handle, bool isManaged)
|
||||
{
|
||||
Handle = handle;
|
||||
IsManaged = isManaged;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue