diff --git a/src/LibHac/IO/AesXtsFile.cs b/src/LibHac/IO/AesXtsFile.cs index bc42f831..2e394f73 100644 --- a/src/LibHac/IO/AesXtsFile.cs +++ b/src/LibHac/IO/AesXtsFile.cs @@ -74,7 +74,9 @@ namespace LibHac.IO { Header.SetSize(size, VerificationKey); - throw new NotImplementedException(); + BaseFile.Write(Header.ToBytes(false), 0); + + BaseStorage.SetSize(size); } } } diff --git a/src/LibHac/IO/AesXtsFileHeader.cs b/src/LibHac/IO/AesXtsFileHeader.cs index 58d8f8d9..74439cd1 100644 --- a/src/LibHac/IO/AesXtsFileHeader.cs +++ b/src/LibHac/IO/AesXtsFileHeader.cs @@ -47,7 +47,7 @@ namespace LibHac.IO EncryptHeader(path, kekSeed, verificationKey); } - private void EncryptHeader(string path, byte[] kekSeed, byte[] verificationKey) + public void EncryptHeader(string path, byte[] kekSeed, byte[] verificationKey) { GenerateKek(kekSeed, path); EncryptKeys(); @@ -84,7 +84,7 @@ namespace LibHac.IO private void GenerateKek(byte[] kekSeed, string path) { var hash = new HMACSHA256(kekSeed); - byte[] pathBytes = Encoding.ASCII.GetBytes(path); + byte[] pathBytes = Encoding.UTF8.GetBytes(path); byte[] checksum = hash.ComputeHash(pathBytes, 0, pathBytes.Length); Array.Copy(checksum, 0, Kek1, 0, 0x10); diff --git a/src/LibHac/IO/AesXtsFileSystem.cs b/src/LibHac/IO/AesXtsFileSystem.cs index d736e5cc..2c39f450 100644 --- a/src/LibHac/IO/AesXtsFileSystem.cs +++ b/src/LibHac/IO/AesXtsFileSystem.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.IO; namespace LibHac.IO { @@ -95,7 +97,24 @@ namespace LibHac.IO public void RenameFile(string srcPath, string dstPath) { - throw new NotImplementedException(); + srcPath = PathTools.Normalize(srcPath); + dstPath = PathTools.Normalize(dstPath); + + AesXtsFileHeader header = ReadXtsHeader(srcPath); + + BaseFileSystem.RenameFile(srcPath, dstPath); + + try + { + WriteXtsHeader(header, dstPath); + } + catch (Exception) + { + BaseFileSystem.RenameFile(dstPath, srcPath); + WriteXtsHeader(header, srcPath); + + throw; + } } public bool DirectoryExists(string path) @@ -117,5 +136,34 @@ namespace LibHac.IO { BaseFileSystem.Commit(); } + + private AesXtsFileHeader ReadXtsHeader(string path) + { + Debug.Assert(PathTools.IsNormalized(path.AsSpan())); + + using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read)) + { + var header = new AesXtsFileHeader(file); + + if (!header.TryDecryptHeader(path, KekSource, ValidationKey)) + { + throw new InvalidDataException("Could not decrypt AES-XTS keys"); + } + + return header; + } + } + + private void WriteXtsHeader(AesXtsFileHeader header, string path) + { + Debug.Assert(PathTools.IsNormalized(path.AsSpan())); + + header.EncryptHeader(path, KekSource, ValidationKey); + + using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.ReadWrite)) + { + file.Write(header.ToBytes(false), 0); + } + } } } diff --git a/src/LibHac/IO/CachedStorage.cs b/src/LibHac/IO/CachedStorage.cs index 588bc539..33376251 100644 --- a/src/LibHac/IO/CachedStorage.cs +++ b/src/LibHac/IO/CachedStorage.cs @@ -8,7 +8,7 @@ namespace LibHac.IO { private IStorage BaseStorage { get; } private int BlockSize { get; } - private readonly long _length; + private long _length; private LinkedList Blocks { get; } = new LinkedList(); private Dictionary> BlockDict { get; } = new Dictionary>(); @@ -99,6 +99,13 @@ namespace LibHac.IO public override long GetSize() => _length; + public override void SetSize(long size) + { + BaseStorage.SetSize(size); + + _length = BaseStorage.GetSize(); + } + private CacheBlock GetBlock(long blockIndex) { if (BlockDict.TryGetValue(blockIndex, out LinkedListNode node)) diff --git a/src/LibHac/IO/FileStorage.cs b/src/LibHac/IO/FileStorage.cs index 5fa34316..655f12c4 100644 --- a/src/LibHac/IO/FileStorage.cs +++ b/src/LibHac/IO/FileStorage.cs @@ -27,5 +27,10 @@ namespace LibHac.IO } public override long GetSize() => BaseFile.GetSize(); + + public override void SetSize(long size) + { + BaseFile.SetSize(size); + } } } diff --git a/src/LibHac/IO/SectorStorage.cs b/src/LibHac/IO/SectorStorage.cs index af19fde0..4db475a0 100644 --- a/src/LibHac/IO/SectorStorage.cs +++ b/src/LibHac/IO/SectorStorage.cs @@ -7,7 +7,7 @@ namespace LibHac.IO protected IStorage BaseStorage { get; } public int SectorSize { get; } - public int SectorCount { get; } + public int SectorCount { get; private set; } private long _length; @@ -15,8 +15,8 @@ namespace LibHac.IO { BaseStorage = baseStorage; SectorSize = sectorSize; - SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), sectorSize); - _length = baseStorage.GetSize(); + SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); + _length = BaseStorage.GetSize(); if (!leaveOpen) ToDispose.Add(BaseStorage); } @@ -40,6 +40,14 @@ namespace LibHac.IO public override long GetSize() => _length; + public override void SetSize(long size) + { + BaseStorage.SetSize(size); + + SectorCount = (int)Util.DivideByRoundUp(BaseStorage.GetSize(), SectorSize); + _length = BaseStorage.GetSize(); + } + /// /// Validates that the size is a multiple of the sector size /// diff --git a/src/LibHac/IO/SubStorage.cs b/src/LibHac/IO/SubStorage.cs index 39c12606..4d9c254a 100644 --- a/src/LibHac/IO/SubStorage.cs +++ b/src/LibHac/IO/SubStorage.cs @@ -54,5 +54,23 @@ namespace LibHac.IO } public override long GetSize() => _length; + + public override void SetSize(long size) + { + //if (!IsResizable) + // return 0x313802; + + //if (Offset < 0 || size < 0) + // return 0x2F5C02; + + if (BaseStorage.GetSize() != Offset + _length) + { + throw new NotSupportedException("SubStorage cannot be resized unless it is located at the end of the base storage."); + } + + BaseStorage.SetSize(Offset + size); + + _length = size; + } } }