Add a basic SaveDataFileSystemCreator

This commit is contained in:
Alex Barney 2019-10-01 16:31:21 -05:00
parent 5011a57d3e
commit d7f3e94577
13 changed files with 188 additions and 64 deletions

View file

@ -189,7 +189,7 @@ namespace LibHac.Fs
rc = operation();
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, textGenerator(), caller);
OutputAccessLog(rc, startTime, endTime, handle, textGenerator(), caller);
}
else
{

View file

@ -2,8 +2,9 @@
{
public interface IAttributeFileSystem : IFileSystem
{
NxFileAttributes GetFileAttributes(string path);
void SetFileAttributes(string path, NxFileAttributes attributes);
Result CreateDirectory(string path, NxFileAttributes archiveAttribute);
Result GetFileAttributes(string path, out NxFileAttributes attributes);
Result SetFileAttributes(string path, NxFileAttributes attributes);
long GetFileSize(string path);
}
}

View file

@ -27,6 +27,7 @@
public static Result InvalidIndirectStorageSource => new Result(ModuleFs, 4023);
public static Result Result4302 => new Result(ModuleFs, 4302);
public static Result InvalidSaveDataEntryType => new Result(ModuleFs, 4303);
public static Result InvalidSaveDataHeader => new Result(ModuleFs, 4315);
public static Result Result4362 => new Result(ModuleFs, 4362);
public static Result Result4363 => new Result(ModuleFs, 4363);

View file

@ -5,6 +5,11 @@ namespace LibHac.Fs
{
public static class SaveData
{
public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId)
{
return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.EmptyId);
}
public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName,
SaveDataSpaceId spaceId, ulong saveDataId, UserId userId)
{
@ -67,19 +72,19 @@ namespace LibHac.Fs
public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, ulong ownerId, long size,
long journalSize, uint flags)
{
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, new UserId(0, 0), ownerId, size, journalSize, flags);
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags);
}
public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, long size,
long journalSize, uint flags)
{
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, new UserId(0, 0), 0, size, journalSize, flags);
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, 0, size, journalSize, flags);
}
public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId,
ulong ownerId, long size, long journalSize, uint flags)
{
return CreateSystemSaveData(fs, spaceId, saveDataId, new UserId(0, 0), ownerId, size, journalSize, flags);
return CreateSystemSaveData(fs, spaceId, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags);
}
public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId)

View file

@ -7,6 +7,8 @@ namespace LibHac.Fs
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct UserId : IEquatable<UserId>, IComparable<UserId>, IComparable
{
public static readonly UserId EmptyId = new UserId(0, 0);
public readonly Id128 Id;
public UserId(ulong high, ulong low)

View file

@ -26,6 +26,7 @@ namespace LibHac.FsService.Creators
var creators = new FileSystemCreators();
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(keyset);
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keyset);
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem);
creators.SdFileSystemCreator = new EmulatedSdFileSystemCreator(rootFileSystem);

View file

@ -0,0 +1,70 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.FsSystem.Save;
namespace LibHac.FsService.Creators
{
public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
{
private Keyset Keyset { get; }
public SaveDataFileSystemCreator(Keyset keyset)
{
Keyset = keyset;
}
public Result CreateFile(out IFile file, IFileSystem sourceFileSystem, ulong saveDataId, OpenMode openMode)
{
throw new NotImplementedException();
}
public Result Create(out IFileSystem fileSystem, out ISaveDataExtraDataAccessor extraDataAccessor,
IFileSystem sourceFileSystem, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac,
SaveDataType type, ITimeStampGenerator timeStampGenerator)
{
fileSystem = default;
extraDataAccessor = default;
string saveDataPath = $"/{saveDataId:x16}";
Result rc = sourceFileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath);
if (rc.IsFailure())
{
return rc == ResultFs.PathNotFound ? ResultFs.TargetNotFound : rc;
}
switch (entryType)
{
case DirectoryEntryType.Directory:
if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log();
var subDirFs = new SubdirectoryFileSystem(sourceFileSystem, saveDataPath);
fileSystem = new DirectorySaveDataFileSystem(subDirFs);
// Todo: Dummy ISaveDataExtraDataAccessor
return Result.Success;
case DirectoryEntryType.File:
rc = sourceFileSystem.OpenFile(out IFile saveDataFile, saveDataPath, OpenMode.ReadWrite);
if (rc.IsFailure()) return rc;
var saveDataStorage = new FileStorage(saveDataFile);
fileSystem = new SaveDataFileSystem(Keyset, saveDataStorage, IntegrityCheckLevel.ErrorOnInvalid, true);
// Todo: ISaveDataExtraDataAccessor
return Result.Success;
default:
throw new ArgumentOutOfRangeException();
}
}
public void SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed)
{
throw new NotImplementedException();
}
}
}

View file

@ -163,7 +163,7 @@ namespace LibHac.FsService
if (saveFsResult.IsSuccess()) return Result.Success;
if (saveFsResult == ResultFs.PathNotFound || saveFsResult == ResultFs.TargetNotFound) return saveFsResult;
if (saveFsResult != ResultFs.PathNotFound && saveFsResult != ResultFs.TargetNotFound) return saveFsResult;
if (saveDataId != SaveIndexerId)
{

View file

@ -54,14 +54,20 @@ namespace LibHac.FsSystem
#if CROSS_PLATFORM
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return HasConcatenationFileAttribute(BaseFileSystem.GetFileAttributes(path));
Result rc = BaseFileSystem.GetFileAttributes(path, out NxFileAttributes attributes);
if (rc.IsFailure()) return false;
return HasConcatenationFileAttribute(attributes);
}
else
{
return IsConcatenationFileHeuristic(path);
}
#else
return HasConcatenationFileAttribute(BaseFileSystem.GetFileAttributes(path));
Result rc = BaseFileSystem.GetFileAttributes(path, out NxFileAttributes attributes);
if (rc.IsFailure()) return false;
return HasConcatenationFileAttribute(attributes);
#endif
}
@ -93,11 +99,9 @@ namespace LibHac.FsSystem
return (attributes & NxFileAttributes.Directory) != 0 && (attributes & NxFileAttributes.Archive) != 0;
}
private void SetConcatenationFileAttribute(string path)
private Result SetConcatenationFileAttribute(string path)
{
NxFileAttributes attributes = BaseFileSystem.GetFileAttributes(path);
attributes |= NxFileAttributes.Archive;
BaseFileSystem.SetFileAttributes(path, attributes);
return BaseFileSystem.SetFileAttributes(path, NxFileAttributes.Archive);
}
public Result CreateDirectory(string path)
@ -134,11 +138,9 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
Result rc = BaseFileSystem.CreateDirectory(path);
Result rc = BaseFileSystem.CreateDirectory(path, NxFileAttributes.Archive);
if (rc.IsFailure()) return rc;
SetConcatenationFileAttribute(path);
long remaining = size;
for (int i = 0; remaining > 0; i++)
@ -320,9 +322,7 @@ namespace LibHac.FsSystem
{
if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log();
SetConcatenationFileAttribute(path);
return Result.Success;
return SetConcatenationFileAttribute(path);
}
private int GetSubFileCount(string dirPath)

View file

@ -213,7 +213,7 @@ namespace LibHac.FsSystem
rc = BaseFs.CreateDirectory(dest);
if (rc.IsFailure()) return rc;
return this.CopyDirectory(this, src, dest);
return BaseFs.CopyDirectory(BaseFs, src, dest);
}
internal void NotifyCloseWritableFile()

View file

@ -182,10 +182,18 @@ namespace LibHac.FsSystem
return (NxFileAttributes)(((int)attributes >> 4) & 3);
}
public static FileAttributes ToFatAttributes(this NxFileAttributes attributes)
{
return (FileAttributes)(((int)attributes & 3) << 4);
}
public static FileAttributes ApplyNxAttributes(this FileAttributes attributes, NxFileAttributes nxAttributes)
{
var nxAttributeBits = (FileAttributes)(((int)nxAttributes & 3) << 4);
return attributes | nxAttributeBits;
// The only 2 bits from FileAttributes that are used in NxFileAttributes
const int mask = 3 << 4;
FileAttributes oldAttributes = attributes & (FileAttributes)mask;
return oldAttributes | nxAttributes.ToFatAttributes();
}
public static void SetConcatenationFileAttribute(this IFileSystem fs, string path)

View file

@ -34,21 +34,46 @@ namespace LibHac.FsSystem
return PathTools.Combine(BasePath, path);
}
public NxFileAttributes GetFileAttributes(string path)
public Result GetFileAttributes(string path, out NxFileAttributes attributes)
{
path = PathTools.Normalize(path);
return File.GetAttributes(ResolveLocalPath(path)).ToNxAttributes();
string localPath = ResolveLocalPath(PathTools.Normalize(path));
FileInfo info = GetFileInfo(localPath);
if (info.Attributes == (FileAttributes)(-1))
{
attributes = default;
return ResultFs.PathNotFound.Log();
}
attributes = info.Attributes.ToNxAttributes();
return Result.Success;
}
public void SetFileAttributes(string path, NxFileAttributes attributes)
public Result SetFileAttributes(string path, NxFileAttributes attributes)
{
path = PathTools.Normalize(path);
string localPath = ResolveLocalPath(path);
string localPath = ResolveLocalPath(PathTools.Normalize(path));
FileAttributes attributesOld = File.GetAttributes(localPath);
FileInfo info = GetFileInfo(localPath);
if (info.Attributes == (FileAttributes)(-1))
{
return ResultFs.PathNotFound.Log();
}
FileAttributes attributesOld = info.Attributes;
FileAttributes attributesNew = attributesOld.ApplyNxAttributes(attributes);
File.SetAttributes(localPath, attributesNew);
try
{
info.Attributes = attributesNew;
}
catch (IOException)
{
return ResultFs.PathNotFound.Log();
}
return Result.Success;
}
public long GetFileSize(string path)
@ -60,6 +85,11 @@ namespace LibHac.FsSystem
}
public Result CreateDirectory(string path)
{
return CreateDirectory(path, NxFileAttributes.None);
}
public Result CreateDirectory(string path, NxFileAttributes archiveAttribute)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
@ -75,7 +105,7 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
return CreateDirInternal(dir);
return CreateDirInternal(dir, archiveAttribute);
}
public Result CreateFile(string path, long size, CreateFileOptions options)
@ -394,11 +424,17 @@ namespace LibHac.FsSystem
return Result.Success;
}
private static Result CreateDirInternal(DirectoryInfo dir)
private static Result CreateDirInternal(DirectoryInfo dir, NxFileAttributes attributes)
{
try
{
dir.Create();
dir.Refresh();
if (attributes.HasFlag(NxFileAttributes.Archive))
{
dir.Attributes |= FileAttributes.Archive;
}
}
catch (DirectoryNotFoundException)
{

View file

@ -21,81 +21,81 @@ namespace LibHac.FsSystem
public Result CreateDirectory(string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.CreateDirectory(ResolveFullPath(path));
return ParentFileSystem.CreateDirectory(fullPath);
}
public Result CreateFile(string path, long size, CreateFileOptions options)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.CreateFile(ResolveFullPath(path), size, options);
return ParentFileSystem.CreateFile(fullPath, size, options);
}
public Result DeleteDirectory(string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.DeleteDirectory(ResolveFullPath(path));
return ParentFileSystem.DeleteDirectory(fullPath);
}
public Result DeleteDirectoryRecursively(string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path));
return ParentFileSystem.DeleteDirectoryRecursively(fullPath);
}
public Result CleanDirectoryRecursively(string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path));
return ParentFileSystem.CleanDirectoryRecursively(fullPath);
}
public Result DeleteFile(string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.DeleteFile(ResolveFullPath(path));
return ParentFileSystem.DeleteFile(fullPath);
}
public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.OpenDirectory(out directory, ResolveFullPath(path), mode);
return ParentFileSystem.OpenDirectory(out directory, fullPath, mode);
}
public Result OpenFile(out IFile file, string path, OpenMode mode)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.OpenFile(out file, ResolveFullPath(path), mode);
return ParentFileSystem.OpenFile(out file, fullPath, mode);
}
public Result RenameDirectory(string oldPath, string newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath));
string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath));
return ParentFileSystem.RenameDirectory(oldPath, newPath);
return ParentFileSystem.RenameDirectory(fullOldPath, fullNewPath);
}
public Result RenameFile(string oldPath, string newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
string fullOldPath = ResolveFullPath(PathTools.Normalize(oldPath));
string fullNewPath = ResolveFullPath(PathTools.Normalize(newPath));
return ParentFileSystem.RenameFile(oldPath, newPath);
return ParentFileSystem.RenameFile(fullOldPath, fullNewPath);
}
public Result GetEntryType(out DirectoryEntryType entryType, string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.GetEntryType(out entryType, ResolveFullPath(path));
return ParentFileSystem.GetEntryType(out entryType, fullPath);
}
public Result Commit()
@ -105,30 +105,30 @@ namespace LibHac.FsSystem
public Result GetFreeSpaceSize(out long freeSpace, string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.GetFreeSpaceSize(out freeSpace, ResolveFullPath(path));
return ParentFileSystem.GetFreeSpaceSize(out freeSpace, fullPath);
}
public Result GetTotalSpaceSize(out long totalSpace, string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.GetTotalSpaceSize(out totalSpace, ResolveFullPath(path));
return ParentFileSystem.GetTotalSpaceSize(out totalSpace, fullPath);
}
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, ResolveFullPath(path));
return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, fullPath);
}
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
{
path = PathTools.Normalize(path);
string fullPath = ResolveFullPath(PathTools.Normalize(path));
return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, ResolveFullPath(path));
return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, fullPath);
}
}
}