Add DeleteFile to savedata

This commit is contained in:
Alex Barney 2019-04-12 22:52:33 -04:00
parent b1997806c1
commit 9c0e6030e5
5 changed files with 129 additions and 9 deletions

View file

@ -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);
}
/// <summary>
/// Combines 2 lists into one list. The second list will be attached to the end of the first list.
/// </summary>
/// <param name="frontListBlockIndex">The index of the first block.</param>
/// <param name="backListBlockIndex">The index of the second block.</param>
/// <param name="frontListBlockIndex">The index of the start block of the first list.</param>
/// <param name="backListBlockIndex">The index of the start block of the second list.</param>
public void Join(int frontListBlockIndex, int backListBlockIndex)
{
int frontEntryIndex = BlockToEntryIndex(frontListBlockIndex);

View file

@ -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<byte> nameBytes = stackalloc byte[FileTable.MaxNameLength];
bool success = FileTable.TryGetValue((int)position.NextFile, out TableEntry<SaveFileInfo> entry, ref nameBytes);
bool success = FileTable.TryGetValue(position.NextFile, out TableEntry<SaveFileInfo> entry, ref nameBytes);
// todo error message
if (!success)
@ -140,7 +141,7 @@ namespace LibHac.IO.Save
DirectoryTable.GetValue(prevIndex, out TableEntry<SaveFindPosition> 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<byte> pathBytes = Util.GetUtf8Bytes(path);
FindPathRecursive(pathBytes, out SaveEntryKey key);
int parentIndex = key.Parent;
DirectoryTable.GetValue(parentIndex, out TableEntry<SaveFindPosition> parentEntry);
int toDeleteIndex = FileTable.GetIndexFromKey(ref key).Index;
if (toDeleteIndex < 0) throw new FileNotFoundException();
FileTable.GetValue(toDeleteIndex, out TableEntry<SaveFileInfo> 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<SaveFileInfo> prevEntry);
int curIndex = prevEntry.NextSibling;
while (curIndex != 0)
{
FileTable.GetValue(curIndex, out TableEntry<SaveFileInfo> 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))

View file

@ -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)

View file

@ -32,6 +32,6 @@ namespace LibHac.IO.Save
/// <summary>The ID of the next directory to be enumerated.</summary>
public int NextDirectory;
/// <summary>The ID of the next file to be enumerated.</summary>
public long NextFile;
public int NextFile;
}
}

View file

@ -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<byte> buf = stackalloc byte[sizeof(int)];