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)];