From 8914d89b32dc966eb5fc49d9309f690285348ba8 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 20 Apr 2019 14:15:00 -0400 Subject: [PATCH] Add SaveDataFile resizing --- src/LibHac/IO/Save/AllocationTableStorage.cs | 43 +++++++++++++++++++- src/LibHac/IO/Save/SaveDataFile.cs | 31 ++++++++++---- src/LibHac/IO/Save/SaveDataFileSystemCore.cs | 7 +--- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/LibHac/IO/Save/AllocationTableStorage.cs b/src/LibHac/IO/Save/AllocationTableStorage.cs index 44b4673c..9a061088 100644 --- a/src/LibHac/IO/Save/AllocationTableStorage.cs +++ b/src/LibHac/IO/Save/AllocationTableStorage.cs @@ -6,7 +6,7 @@ namespace LibHac.IO.Save { private IStorage BaseStorage { get; } private int BlockSize { get; } - private int InitialBlock { get; } + internal int InitialBlock { get; private set; } private AllocationTable Fat { get; } private long _length; @@ -18,7 +18,7 @@ namespace LibHac.IO.Save Fat = table; InitialBlock = initialBlock; - _length = table.GetListLength(initialBlock) * blockSize; + _length = initialBlock == -1 ? 0 : table.GetListLength(initialBlock) * blockSize; } protected override void ReadImpl(Span destination, long offset) @@ -81,5 +81,44 @@ namespace LibHac.IO.Save } public override long GetSize() => _length; + + public override void SetSize(long size) + { + int oldBlockCount = (int)Util.DivideByRoundUp(_length, BlockSize); + int newBlockCount = (int)Util.DivideByRoundUp(size, BlockSize); + + if (oldBlockCount == newBlockCount) return; + + if (oldBlockCount == 0) + { + InitialBlock = Fat.Allocate(newBlockCount); + _length = newBlockCount * BlockSize; + + return; + } + + if (newBlockCount == 0) + { + Fat.Free(InitialBlock); + + InitialBlock = -1; + _length = 0; + + return; + } + + if (newBlockCount > oldBlockCount) + { + int newBlocks = Fat.Allocate(newBlockCount - oldBlockCount); + Fat.Join(InitialBlock, newBlocks); + } + else + { + int oldBlocks = Fat.Trim(InitialBlock, newBlockCount); + Fat.Free(oldBlocks); + } + + _length = newBlockCount * BlockSize; + } } } diff --git a/src/LibHac/IO/Save/SaveDataFile.cs b/src/LibHac/IO/Save/SaveDataFile.cs index bf852858..24ce1e1a 100644 --- a/src/LibHac/IO/Save/SaveDataFile.cs +++ b/src/LibHac/IO/Save/SaveDataFile.cs @@ -1,18 +1,21 @@ using System; +using System.IO; namespace LibHac.IO.Save { public class SaveDataFile : FileBase { private AllocationTableStorage BaseStorage { get; } - private long Offset { get; } - private long Size { get; } + private string Path { get; } + private HierarchicalSaveFileTable FileTable { get; } + private long Size { get; set; } - public SaveDataFile(AllocationTableStorage baseStorage, long offset, long size, OpenMode mode) + public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) { Mode = mode; BaseStorage = baseStorage; - Offset = offset; + Path = path; + FileTable = fileTable; Size = size; } @@ -20,8 +23,7 @@ namespace LibHac.IO.Save { int toRead = ValidateReadParamsAndGetSize(destination, offset); - long storageOffset = Offset + offset; - BaseStorage.Read(destination.Slice(0, toRead), storageOffset); + BaseStorage.Read(destination.Slice(0, toRead), offset); return toRead; } @@ -45,7 +47,22 @@ namespace LibHac.IO.Save public override void SetSize(long size) { - throw new NotImplementedException(); + if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); + if (Size == size) return; + + BaseStorage.SetSize(size); + + if (!FileTable.TryOpenFile(Path, out SaveFileInfo fileInfo)) + { + throw new FileNotFoundException(); + } + + fileInfo.StartBlock = BaseStorage.InitialBlock; + fileInfo.Length = size; + + FileTable.AddFile(Path, ref fileInfo); + + Size = size; } } } diff --git a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs index d1bd0f27..4345a06a 100644 --- a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs @@ -86,14 +86,9 @@ namespace LibHac.IO.Save throw new FileNotFoundException(); } - if (file.StartBlock < 0) - { - return new NullFile(); - } - AllocationTableStorage storage = OpenFatStorage(file.StartBlock); - return new SaveDataFile(storage, 0, file.Length, mode); + return new SaveDataFile(storage, path, FileTable, file.Length, mode); } public void RenameDirectory(string srcPath, string dstPath)