mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement DeleteSaveDataFileSystem
This commit is contained in:
parent
92049bf9b7
commit
e74bda1a68
9 changed files with 310 additions and 14 deletions
|
@ -83,6 +83,15 @@ namespace LibHac.Fs
|
|||
ExtensionInfo = 2
|
||||
}
|
||||
|
||||
public enum SaveDataState : byte
|
||||
{
|
||||
Normal = 0,
|
||||
Creating = 1,
|
||||
State2 = 2,
|
||||
MarkedForDeletion = 3,
|
||||
State4 = 4,
|
||||
}
|
||||
|
||||
public enum ImageDirectoryId
|
||||
{
|
||||
Nand = 0,
|
||||
|
|
|
@ -137,4 +137,19 @@ namespace LibHac.Fs
|
|||
[FieldOffset(0x24)] public SaveDataSpaceId SpaceId;
|
||||
[FieldOffset(0x25)] public bool Field25;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x60)]
|
||||
public struct SaveDataInfo
|
||||
{
|
||||
[FieldOffset(0x00)] public ulong SaveDataId;
|
||||
[FieldOffset(0x08)] public SaveDataSpaceId SpaceId;
|
||||
[FieldOffset(0x09)] public SaveDataType Type;
|
||||
[FieldOffset(0x10)] public UserId UserId;
|
||||
[FieldOffset(0x20)] public ulong SaveDataIdFromKey;
|
||||
[FieldOffset(0x28)] public TitleId TitleId;
|
||||
[FieldOffset(0x30)] public long Size;
|
||||
[FieldOffset(0x38)] public short Index;
|
||||
[FieldOffset(0x3A)] public byte Rank;
|
||||
[FieldOffset(0x3B)] public SaveDataState State;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ namespace LibHac.FsService.Creators
|
|||
switch (entryType)
|
||||
{
|
||||
case DirectoryEntryType.Directory:
|
||||
if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log();
|
||||
// Actual FS does this check
|
||||
// if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log();
|
||||
|
||||
var subDirFs = new SubdirectoryFileSystem(sourceFileSystem, saveDataPath);
|
||||
|
||||
|
|
|
@ -106,17 +106,148 @@ namespace LibHac.FsService
|
|||
|
||||
public Result DeleteSaveDataFileSystem(ulong saveDataId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return DeleteSaveDataFileSystemImpl(SaveDataSpaceId.System, saveDataId);
|
||||
}
|
||||
|
||||
private Result DeleteSaveDataFileSystemImpl(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
SaveDataIndexerReader reader = default;
|
||||
|
||||
try
|
||||
{
|
||||
Result rc = FsServer.SaveDataIndexerManager.GetSaveDataIndexer(out reader, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (saveDataId == FileSystemServer.SaveIndexerId)
|
||||
{
|
||||
// missing: This save can only be deleted by the FS process itself
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spaceId != SaveDataSpaceId.ProperSystem && spaceId != SaveDataSpaceId.Safe)
|
||||
{
|
||||
rc = reader.Indexer.GetBySaveDataId(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
spaceId = value.SpaceId;
|
||||
}
|
||||
|
||||
rc = reader.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (key.Type == SaveDataType.SystemSaveData || key.Type == SaveDataType.BcatSystemStorage)
|
||||
{
|
||||
// Check if permissions allow deleting system save data
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if permissions allow deleting save data
|
||||
}
|
||||
|
||||
reader.Indexer.SetState(saveDataId, SaveDataState.Creating);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
reader.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
// missing: Check extra data flags for this value. Bit 3
|
||||
bool doSecureDelete = false;
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
rc = DeleteSaveDataFileSystemImpl2(spaceId, saveDataId, doSecureDelete);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (saveDataId != FileSystemServer.SaveIndexerId)
|
||||
{
|
||||
rc = reader.Indexer.Delete(saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = reader.Indexer.Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Result DeleteSaveDataFileSystemImpl2(SaveDataSpaceId spaceId, ulong saveDataId, bool doSecureDelete)
|
||||
{
|
||||
Result rc = FsProxyCore.DeleteSaveDataMetaFiles(saveDataId, spaceId);
|
||||
if (rc.IsFailure() && rc != ResultFs.PathNotFound)
|
||||
return rc;
|
||||
|
||||
rc = FsProxyCore.DeleteSaveDataFileSystem(spaceId, saveDataId, doSecureDelete);
|
||||
if (rc.IsFailure() && rc != ResultFs.PathNotFound)
|
||||
return rc;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return DeleteSaveDataFileSystemBySaveDataSpaceIdImpl(spaceId, saveDataId);
|
||||
}
|
||||
|
||||
public Result DeleteSaveDataFileSystemBySaveDataSpaceIdImpl(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
if (saveDataId != FileSystemServer.SaveIndexerId)
|
||||
{
|
||||
SaveDataIndexerReader reader = default;
|
||||
|
||||
try
|
||||
{
|
||||
Result rc = FsServer.SaveDataIndexerManager.GetSaveDataIndexer(out reader, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = reader.Indexer.GetBySaveDataId(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (value.SpaceId != GetSpaceIdForIndexer(spaceId))
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return DeleteSaveDataFileSystemImpl(spaceId, saveDataId);
|
||||
}
|
||||
|
||||
public Result GetSaveDataInfo(out SaveDataInfo info, SaveDataSpaceId spaceId, ref SaveDataAttribute attribute)
|
||||
{
|
||||
info = default;
|
||||
|
||||
SaveDataIndexerReader reader = default;
|
||||
|
||||
try
|
||||
{
|
||||
Result rc = FsServer.SaveDataIndexerManager.GetSaveDataIndexer(out reader, spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = reader.Indexer.Get(out SaveDataIndexerValue value, ref attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexer.GetSaveDataInfo(out info, ref attribute, ref value);
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, ref SaveDataAttribute attribute)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result rs = GetSaveDataInfo(out SaveDataInfo info, spaceId, ref attribute);
|
||||
if (rs.IsFailure()) return rs;
|
||||
|
||||
return DeleteSaveDataFileSystemBySaveDataSpaceIdImpl(spaceId, info.SaveDataId);
|
||||
}
|
||||
|
||||
public Result UpdateSaveDataMacForDebug(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
|
@ -178,7 +309,7 @@ namespace LibHac.FsService
|
|||
return ResultFs.PathAlreadyExists.LogConverted(rc);
|
||||
}
|
||||
|
||||
rc = reader.Indexer.SetState(saveDataId, 1);
|
||||
rc = reader.Indexer.SetState(saveDataId, SaveDataState.Creating);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataSpaceId indexerSpaceId = GetSpaceIdForIndexer(createInfo.SpaceId);
|
||||
|
@ -208,12 +339,12 @@ namespace LibHac.FsService
|
|||
metaCreateInfo.Size);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if(metaCreateInfo.Type == SaveMetaType.Thumbnail)
|
||||
if (metaCreateInfo.Type == SaveMetaType.Thumbnail)
|
||||
{
|
||||
rc = FsProxyCore.OpenSaveDataMetaFile(out IFile metaFile, saveDataId, createInfo.SpaceId,
|
||||
metaCreateInfo.Type);
|
||||
|
||||
using(metaFile)
|
||||
using (metaFile)
|
||||
{
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
|
@ -282,7 +413,6 @@ namespace LibHac.FsService
|
|||
|
||||
public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute attribute, ref SaveDataCreateInfo createInfo)
|
||||
{
|
||||
|
||||
if (!IsSystemSaveDataId(attribute.SaveDataId))
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
|
||||
|
@ -340,7 +470,7 @@ namespace LibHac.FsService
|
|||
if (indexerValue.SpaceId != indexerSpaceId)
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
||||
if (indexerValue.State == 4)
|
||||
if (indexerValue.State == SaveDataState.State4)
|
||||
return ResultFs.Result6906.Log();
|
||||
|
||||
saveDataId = indexerValue.SaveDataId;
|
||||
|
|
|
@ -334,6 +334,23 @@ namespace LibHac.FsService
|
|||
return metaDirFs.OpenFile(out file, metaFilePath, OpenMode.ReadWrite);
|
||||
}
|
||||
|
||||
public Result DeleteSaveDataMetaFiles(ulong saveDataId, SaveDataSpaceId spaceId)
|
||||
{
|
||||
Result rc = OpenSaveDataDirectoryImpl(out IFileSystem metaDirFs, spaceId, "/saveMeta", false);
|
||||
|
||||
using (metaDirFs)
|
||||
{
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = metaDirFs.DeleteDirectoryRecursively($"/{saveDataId:x16}");
|
||||
|
||||
if (rc.IsFailure() && rc != ResultFs.PathNotFound)
|
||||
return rc;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public Result CreateSaveDataMetaFile(ulong saveDataId, SaveDataSpaceId spaceId, SaveMetaType type, long size)
|
||||
{
|
||||
string metaDirPath = $"/saveMeta/{saveDataId:x16}";
|
||||
|
@ -360,6 +377,38 @@ namespace LibHac.FsService
|
|||
return fileSystem.EnsureDirectoryExists(GetSaveDataIdPath(saveDataId));
|
||||
}
|
||||
|
||||
public Result DeleteSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, bool doSecureDelete)
|
||||
{
|
||||
Result rc = OpenSaveDataDirectory(out IFileSystem fileSystem, spaceId, string.Empty, false);
|
||||
|
||||
using (fileSystem)
|
||||
{
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
string saveDataPath = GetSaveDataIdPath(saveDataId);
|
||||
|
||||
rc = fileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (entryType == DirectoryEntryType.Directory)
|
||||
{
|
||||
rc = fileSystem.DeleteDirectoryRecursively(saveDataPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (doSecureDelete)
|
||||
{
|
||||
// Overwrite file with garbage before deleting
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
rc = fileSystem.DeleteFile(saveDataPath);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode)
|
||||
{
|
||||
LogMode = mode;
|
||||
|
|
|
@ -9,9 +9,11 @@ namespace LibHac.FsService
|
|||
Result Get(out SaveDataIndexerValue value, ref SaveDataAttribute key);
|
||||
Result AddSystemSaveData(ref SaveDataAttribute key);
|
||||
bool IsFull();
|
||||
Result Delete(ulong saveDataId);
|
||||
Result SetSpaceId(ulong saveDataId, SaveDataSpaceId spaceId);
|
||||
Result SetSize(ulong saveDataId, long size);
|
||||
Result SetState(ulong saveDataId, byte state);
|
||||
Result SetState(ulong saveDataId, SaveDataState state);
|
||||
Result GetKey(out SaveDataAttribute key, ulong saveDataId);
|
||||
Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId);
|
||||
}
|
||||
}
|
|
@ -32,6 +32,23 @@ namespace LibHac.FsService
|
|||
SpaceId = spaceId;
|
||||
}
|
||||
|
||||
public static void GetSaveDataInfo(out SaveDataInfo info, ref SaveDataAttribute key, ref SaveDataIndexerValue value)
|
||||
{
|
||||
info = new SaveDataInfo
|
||||
{
|
||||
SaveDataId = value.SaveDataId,
|
||||
SpaceId = value.SpaceId,
|
||||
Type = key.Type,
|
||||
UserId = key.UserId,
|
||||
SaveDataIdFromKey = key.SaveDataId,
|
||||
TitleId = key.TitleId,
|
||||
Size = value.Size,
|
||||
Index = key.Index,
|
||||
Rank = key.Rank,
|
||||
State = value.State
|
||||
};
|
||||
}
|
||||
|
||||
public Result Commit()
|
||||
{
|
||||
lock (Locker)
|
||||
|
@ -192,10 +209,35 @@ namespace LibHac.FsService
|
|||
return false;
|
||||
}
|
||||
|
||||
public Result Delete(ulong saveDataId)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!TryGetBySaveDataIdInternal(out SaveDataAttribute key, out _, saveDataId))
|
||||
{
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
|
||||
return KvDatabase.Delete(ref key);
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetSpaceId(ulong saveDataId, SaveDataSpaceId spaceId)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!TryGetBySaveDataIdInternal(out SaveDataAttribute key, out SaveDataIndexerValue value, saveDataId))
|
||||
{
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
@ -211,6 +253,12 @@ namespace LibHac.FsService
|
|||
{
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!TryGetBySaveDataIdInternal(out SaveDataAttribute key, out SaveDataIndexerValue value, saveDataId))
|
||||
{
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
@ -222,10 +270,16 @@ namespace LibHac.FsService
|
|||
}
|
||||
}
|
||||
|
||||
public Result SetState(ulong saveDataId, byte state)
|
||||
public Result SetState(ulong saveDataId, SaveDataState state)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!TryGetBySaveDataIdInternal(out SaveDataAttribute key, out SaveDataIndexerValue value, saveDataId))
|
||||
{
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
@ -237,10 +291,39 @@ namespace LibHac.FsService
|
|||
}
|
||||
}
|
||||
|
||||
public Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId)
|
||||
public Result GetKey(out SaveDataAttribute key, ulong saveDataId)
|
||||
{
|
||||
key = default;
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (TryGetBySaveDataIdInternal(out key, out _, saveDataId))
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId)
|
||||
{
|
||||
value = default;
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
Result rc = Initialize();
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = EnsureKvDatabaseLoaded(false);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (TryGetBySaveDataIdInternal(out _, out value, saveDataId))
|
||||
{
|
||||
return Result.Success;
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace LibHac.FsService
|
|||
[FieldOffset(0x08)] public long Size;
|
||||
[FieldOffset(0x10)] public ulong Field10;
|
||||
[FieldOffset(0x18)] public SaveDataSpaceId SpaceId;
|
||||
[FieldOffset(0x19)] public byte State;
|
||||
[FieldOffset(0x19)] public SaveDataState State;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace LibHac.Kvdb
|
|||
{
|
||||
public class KeyValueDatabase<TKey> where TKey : unmanaged, IComparable<TKey>, IEquatable<TKey>
|
||||
{
|
||||
public Dictionary<TKey, byte[]> KvDict { get; } = new Dictionary<TKey, byte[]>();
|
||||
private Dictionary<TKey, byte[]> KvDict { get; } = new Dictionary<TKey, byte[]>();
|
||||
|
||||
private FileSystemClient FsClient { get; }
|
||||
private string FileName { get; }
|
||||
|
@ -51,6 +51,13 @@ namespace LibHac.Kvdb
|
|||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Delete(ref TKey key)
|
||||
{
|
||||
bool deleted = KvDict.Remove(key);
|
||||
|
||||
return deleted ? Result.Success : ResultKvdb.KeyNotFound.Log();
|
||||
}
|
||||
|
||||
public Dictionary<TKey, byte[]>.Enumerator GetEnumerator()
|
||||
{
|
||||
return KvDict.GetEnumerator();
|
||||
|
|
Loading…
Reference in a new issue