From 9c0e6030e5fa405d87f539f8f3bf878259295d71 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 12 Apr 2019 22:52:33 -0400 Subject: [PATCH] Add DeleteFile to savedata --- src/LibHac/IO/Save/AllocationTable.cs | 44 +++++++++++++-- .../IO/Save/HierarchicalSaveFileTable.cs | 53 ++++++++++++++++++- src/LibHac/IO/Save/SaveDataFileSystemCore.cs | 14 ++++- src/LibHac/IO/Save/SaveFsEntries.cs | 2 +- src/LibHac/IO/Save/SaveFsList.cs | 25 +++++++++ 5 files changed, 129 insertions(+), 9 deletions(-) diff --git a/src/LibHac/IO/Save/AllocationTable.cs b/src/LibHac/IO/Save/AllocationTable.cs index 7b3d3b4d..e560b6c7 100644 --- a/src/LibHac/IO/Save/AllocationTable.cs +++ b/src/LibHac/IO/Save/AllocationTable.cs @@ -62,13 +62,23 @@ namespace LibHac.IO.Save public int GetFreeListBlockIndex() { - AllocationTableEntry freeList = ReadEntry(FreeListEntryIndex); - return EntryIndexToBlock(freeList.GetNext()); + return EntryIndexToBlock(GetFreeListEntryIndex()); } public void SetFreeListBlockIndex(int headBlockIndex) { - var freeList = new AllocationTableEntry() { Next = BlockToEntryIndex(headBlockIndex) }; + SetFreeListEntryIndex(BlockToEntryIndex(headBlockIndex)); + } + + public int GetFreeListEntryIndex() + { + AllocationTableEntry freeList = ReadEntry(FreeListEntryIndex); + return freeList.GetNext(); + } + + public void SetFreeListEntryIndex(int headBlockIndex) + { + var freeList = new AllocationTableEntry { Next = headBlockIndex }; WriteEntry(FreeListEntryIndex, freeList); } @@ -89,11 +99,35 @@ namespace LibHac.IO.Save return freeList; } + public void Free(int listBlockIndex) + { + int listEntryIndex = BlockToEntryIndex(listBlockIndex); + AllocationTableEntry listEntry = ReadEntry(listEntryIndex); + + if (!listEntry.IsListStart()) + { + throw new ArgumentOutOfRangeException(nameof(listBlockIndex), "The block to free must be the start of a list."); + } + + int freeListIndex = GetFreeListEntryIndex(); + + // Free list is empty + if (freeListIndex == 0) + { + SetFreeListEntryIndex(listEntryIndex); + return; + } + + Join(listBlockIndex, EntryIndexToBlock(freeListIndex)); + + SetFreeListBlockIndex(listBlockIndex); + } + /// /// Combines 2 lists into one list. The second list will be attached to the end of the first list. /// - /// The index of the first block. - /// The index of the second block. + /// The index of the start block of the first list. + /// The index of the start block of the second list. public void Join(int frontListBlockIndex, int backListBlockIndex) { int frontEntryIndex = BlockToEntryIndex(frontListBlockIndex); diff --git a/src/LibHac/IO/Save/HierarchicalSaveFileTable.cs b/src/LibHac/IO/Save/HierarchicalSaveFileTable.cs index fd7b9ed9..4c45b465 100644 --- a/src/LibHac/IO/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/IO/Save/HierarchicalSaveFileTable.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Runtime.InteropServices; namespace LibHac.IO.Save @@ -43,7 +44,7 @@ namespace LibHac.IO.Save Span nameBytes = stackalloc byte[FileTable.MaxNameLength]; - bool success = FileTable.TryGetValue((int)position.NextFile, out TableEntry entry, ref nameBytes); + bool success = FileTable.TryGetValue(position.NextFile, out TableEntry entry, ref nameBytes); // todo error message if (!success) @@ -140,7 +141,7 @@ namespace LibHac.IO.Save DirectoryTable.GetValue(prevIndex, out TableEntry parentEntry); - fileEntry.NextSibling = (int)parentEntry.Value.NextFile; + fileEntry.NextSibling = parentEntry.Value.NextFile; parentEntry.Value.NextFile = index; DirectoryTable.SetValue(prevIndex, ref parentEntry); @@ -151,6 +152,54 @@ namespace LibHac.IO.Save } } + public void DeleteFile(string path) + { + path = PathTools.Normalize(path); + ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); + + FindPathRecursive(pathBytes, out SaveEntryKey key); + int parentIndex = key.Parent; + + DirectoryTable.GetValue(parentIndex, out TableEntry parentEntry); + + int toDeleteIndex = FileTable.GetIndexFromKey(ref key).Index; + if (toDeleteIndex < 0) throw new FileNotFoundException(); + + FileTable.GetValue(toDeleteIndex, out TableEntry toDeleteEntry); + + if (parentEntry.Value.NextFile == toDeleteIndex) + { + parentEntry.Value.NextFile = toDeleteEntry.NextSibling; + DirectoryTable.SetValue(parentIndex, ref parentEntry); + FileTable.Remove(ref key); + return; + } + + int prevIndex = parentEntry.Value.NextFile; + FileTable.GetValue(prevIndex, out TableEntry prevEntry); + int curIndex = prevEntry.NextSibling; + + while (curIndex != 0) + { + FileTable.GetValue(curIndex, out TableEntry curEntry); + + if (curIndex == toDeleteIndex) + { + prevEntry.NextSibling = curEntry.NextSibling; + FileTable.SetValue(prevIndex, ref prevEntry); + + FileTable.Remove(ref key); + return; + } + + prevIndex = curIndex; + prevEntry = curEntry; + curIndex = prevEntry.NextSibling; + } + + throw new FileNotFoundException(); + } + public bool TryOpenDirectory(string path, out SaveFindPosition position) { if (!FindPathRecursive(Util.GetUtf8Bytes(path), out SaveEntryKey key)) diff --git a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs index be2e857b..12966a8f 100644 --- a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs @@ -51,7 +51,19 @@ namespace LibHac.IO.Save public void DeleteFile(string path) { - throw new System.NotImplementedException(); + path = PathTools.Normalize(path); + + if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) + { + throw new FileNotFoundException(); + } + + if (fileInfo.StartBlock != int.MinValue) + { + AllocationTable.Free(fileInfo.StartBlock); + } + + FileTable.DeleteFile(path); } public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) diff --git a/src/LibHac/IO/Save/SaveFsEntries.cs b/src/LibHac/IO/Save/SaveFsEntries.cs index ee4dd8d5..625e5ba5 100644 --- a/src/LibHac/IO/Save/SaveFsEntries.cs +++ b/src/LibHac/IO/Save/SaveFsEntries.cs @@ -32,6 +32,6 @@ namespace LibHac.IO.Save /// The ID of the next directory to be enumerated. public int NextDirectory; /// The ID of the next file to be enumerated. - public long NextFile; + public int NextFile; } } diff --git a/src/LibHac/IO/Save/SaveFsList.cs b/src/LibHac/IO/Save/SaveFsList.cs index dcb49103..8142c49c 100644 --- a/src/LibHac/IO/Save/SaveFsList.cs +++ b/src/LibHac/IO/Save/SaveFsList.cs @@ -112,6 +112,18 @@ namespace LibHac.IO.Save return length; } + private void Free(int entryIndex) + { + ReadEntry(FreeListHeadIndex, out SaveFsEntry freeEntry); + ReadEntry(entryIndex, out SaveFsEntry entry); + + entry.Next = freeEntry.Next; + freeEntry.Next = entryIndex; + + WriteEntry(FreeListHeadIndex, ref freeEntry); + WriteEntry(entryIndex, ref entry); + } + public bool TryGetValue(ref SaveEntryKey key, out T value) { int index = GetIndexFromKey(ref key).Index; @@ -201,6 +213,19 @@ namespace LibHac.IO.Save WriteEntry(index, ref entry); } + public void Remove(ref SaveEntryKey key) + { + (int index, int previousIndex) = GetIndexFromKey(ref key); + + ReadEntry(previousIndex, out SaveFsEntry prevEntry); + ReadEntry(index, out SaveFsEntry entryToDel); + + prevEntry.Next = entryToDel.Next; + WriteEntry(previousIndex, ref prevEntry); + + Free(index); + } + private int GetListCapacity() { Span buf = stackalloc byte[sizeof(int)];