mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add ConcatenationFileSystem writing
This commit is contained in:
parent
a33f829b55
commit
c3026f04b6
16 changed files with 142 additions and 27 deletions
|
@ -75,6 +75,13 @@ namespace LibHac.Nand
|
||||||
return Fs.GetAttributes(path);
|
return Fs.GetAttributes(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFileAttributes(string path, FileAttributes attributes)
|
||||||
|
{
|
||||||
|
path = ToDiscUtilsPath(PathTools.Normalize(path));
|
||||||
|
|
||||||
|
Fs.SetAttributes(path, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
public long GetFileSize(string path)
|
public long GetFileSize(string path)
|
||||||
{
|
{
|
||||||
path = ToDiscUtilsPath(PathTools.Normalize(path));
|
path = ToDiscUtilsPath(PathTools.Normalize(path));
|
||||||
|
@ -85,7 +92,7 @@ namespace LibHac.Nand
|
||||||
public void Commit() { }
|
public void Commit() { }
|
||||||
|
|
||||||
public void CreateDirectory(string path) => throw new NotSupportedException();
|
public void CreateDirectory(string path) => throw new NotSupportedException();
|
||||||
public void CreateFile(string path, long size) => throw new NotSupportedException();
|
public void CreateFile(string path, long size, CreateFileOptions options) => throw new NotSupportedException();
|
||||||
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
public void RenameFile(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameFile(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace LibHac.IO
|
||||||
BaseFileSystem.CreateDirectory(path);
|
BaseFileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace LibHac.IO
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long size = ParentFileSystem.GetSplitFileSize(entry.FullPath);
|
long size = ParentFileSystem.GetConcatenationFileSize(entry.FullPath);
|
||||||
yield return new DirectoryEntry(entry.Name, entry.FullPath, DirectoryEntryType.File, size);
|
yield return new DirectoryEntry(entry.Name, entry.FullPath, DirectoryEntryType.File, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,26 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public override void Write(ReadOnlySpan<byte> source, long offset)
|
public override void Write(ReadOnlySpan<byte> source, long offset)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
ValidateWriteParams(source, offset);
|
||||||
|
|
||||||
|
long inPos = offset;
|
||||||
|
int outPos = 0;
|
||||||
|
int remaining = source.Length;
|
||||||
|
|
||||||
|
while (remaining > 0)
|
||||||
|
{
|
||||||
|
int fileIndex = GetFileIndexFromOffset(offset);
|
||||||
|
IFile file = Sources[fileIndex];
|
||||||
|
long fileOffset = offset - fileIndex * SplitFileSize;
|
||||||
|
|
||||||
|
long fileEndOffset = Math.Min((fileIndex + 1) * SplitFileSize, GetSize());
|
||||||
|
int bytesToWrite = (int)Math.Min(fileEndOffset - inPos, remaining);
|
||||||
|
file.Write(source.Slice(outPos, bytesToWrite), fileOffset);
|
||||||
|
|
||||||
|
outPos += bytesToWrite;
|
||||||
|
inPos += bytesToWrite;
|
||||||
|
remaining -= bytesToWrite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
|
|
|
@ -6,12 +6,16 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class ConcatenationFileSystem : IFileSystem
|
public class ConcatenationFileSystem : IFileSystem
|
||||||
{
|
{
|
||||||
|
private const long DefaultSplitFileSize = 0xFFFF0000; // Hard-coded value used by FS
|
||||||
private IAttributeFileSystem BaseFileSystem { get; }
|
private IAttributeFileSystem BaseFileSystem { get; }
|
||||||
private long SplitFileSize { get; } = 0xFFFF0000; // Hard-coded value used by FS
|
private long SplitFileSize { get; }
|
||||||
|
|
||||||
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem)
|
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem) : this(baseFileSystem, DefaultSplitFileSize) { }
|
||||||
|
|
||||||
|
public ConcatenationFileSystem(IAttributeFileSystem baseFileSystem, long splitFileSize)
|
||||||
{
|
{
|
||||||
BaseFileSystem = baseFileSystem;
|
BaseFileSystem = baseFileSystem;
|
||||||
|
SplitFileSize = splitFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool IsSplitFile(string path)
|
internal bool IsSplitFile(string path)
|
||||||
|
@ -23,22 +27,78 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public void CreateDirectory(string path)
|
public void CreateDirectory(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
|
if (FileExists(path))
|
||||||
|
{
|
||||||
|
throw new IOException("Cannot create directory because a file with this name already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseFileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
|
CreateFileOptions newOptions = options & ~CreateFileOptions.CreateConcatenationFile;
|
||||||
|
|
||||||
|
if (!options.HasFlag(CreateFileOptions.CreateConcatenationFile))
|
||||||
|
{
|
||||||
|
BaseFileSystem.CreateFile(path, size, newOptions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A concatenation file directory can't contain normal files
|
||||||
|
string parentDir = PathTools.GetParentDirectory(path);
|
||||||
|
if (IsSplitFile(parentDir)) throw new IOException("Cannot create files inside of a concatenation file");
|
||||||
|
|
||||||
|
BaseFileSystem.CreateDirectory(path);
|
||||||
|
FileAttributes attributes = BaseFileSystem.GetFileAttributes(path) | FileAttributes.Archive;
|
||||||
|
BaseFileSystem.SetFileAttributes(path, attributes);
|
||||||
|
|
||||||
|
long remaining = size;
|
||||||
|
|
||||||
|
for (int i = 0; remaining > 0; i++)
|
||||||
|
{
|
||||||
|
long fileSize = Math.Min(SplitFileSize, remaining);
|
||||||
|
string fileName = GetSplitFilePath(path, i);
|
||||||
|
|
||||||
|
BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None);
|
||||||
|
|
||||||
|
remaining -= fileSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteDirectory(string path)
|
public void DeleteDirectory(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
|
if (IsSplitFile(path))
|
||||||
|
{
|
||||||
|
throw new DirectoryNotFoundException(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseFileSystem.DeleteDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFile(string path)
|
public void DeleteFile(string path)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
|
if (!IsSplitFile(path))
|
||||||
|
{
|
||||||
|
BaseFileSystem.DeleteFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = GetSplitFileCount(path);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
BaseFileSystem.DeleteFile(GetSplitFilePath(path, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseFileSystem.DeleteDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
public IDirectory OpenDirectory(string path, OpenDirectoryMode mode)
|
||||||
|
@ -151,7 +211,7 @@ namespace LibHac.IO
|
||||||
return $"{dirPath}/{index:D2}";
|
return $"{dirPath}/{index:D2}";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal long GetSplitFileSize(string path)
|
internal long GetConcatenationFileSize(string path)
|
||||||
{
|
{
|
||||||
int fileCount = GetSplitFileCount(path);
|
int fileCount = GetSplitFileCount(path);
|
||||||
long size = 0;
|
long size = 0;
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public static class FileSystemExtensions
|
public static class FileSystemExtensions
|
||||||
{
|
{
|
||||||
public static void CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null)
|
public static void CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None)
|
||||||
{
|
{
|
||||||
IFileSystem sourceFs = source.ParentFileSystem;
|
IFileSystem sourceFs = source.ParentFileSystem;
|
||||||
IFileSystem destFs = dest.ParentFileSystem;
|
IFileSystem destFs = dest.ParentFileSystem;
|
||||||
|
@ -27,12 +27,12 @@ namespace LibHac.IO
|
||||||
IDirectory subSrcDir = sourceFs.OpenDirectory(subSrcPath, OpenDirectoryMode.All);
|
IDirectory subSrcDir = sourceFs.OpenDirectory(subSrcPath, OpenDirectoryMode.All);
|
||||||
IDirectory subDstDir = destFs.OpenDirectory(subDstPath, OpenDirectoryMode.All);
|
IDirectory subDstDir = destFs.OpenDirectory(subDstPath, OpenDirectoryMode.All);
|
||||||
|
|
||||||
subSrcDir.CopyDirectory(subDstDir, logger);
|
subSrcDir.CopyDirectory(subDstDir, logger, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.Type == DirectoryEntryType.File)
|
if (entry.Type == DirectoryEntryType.File)
|
||||||
{
|
{
|
||||||
destFs.CreateFile(subDstPath, entry.Size);
|
destFs.CreateFile(subDstPath, entry.Size, options);
|
||||||
|
|
||||||
using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read))
|
using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read))
|
||||||
using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write))
|
using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write))
|
||||||
|
@ -44,12 +44,12 @@ namespace LibHac.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CopyFileSystem(this IFileSystem source, IFileSystem dest, IProgressReport logger = null)
|
public static void CopyFileSystem(this IFileSystem source, IFileSystem dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None)
|
||||||
{
|
{
|
||||||
IDirectory sourceRoot = source.OpenDirectory("/", OpenDirectoryMode.All);
|
IDirectory sourceRoot = source.OpenDirectory("/", OpenDirectoryMode.All);
|
||||||
IDirectory destRoot = dest.OpenDirectory("/", OpenDirectoryMode.All);
|
IDirectory destRoot = dest.OpenDirectory("/", OpenDirectoryMode.All);
|
||||||
|
|
||||||
sourceRoot.CopyDirectory(destRoot, logger);
|
sourceRoot.CopyDirectory(destRoot, logger, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Extract(this IFileSystem source, string destinationPath, IProgressReport logger = null)
|
public static void Extract(this IFileSystem source, string destinationPath, IProgressReport logger = null)
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace LibHac.IO
|
||||||
public interface IAttributeFileSystem : IFileSystem
|
public interface IAttributeFileSystem : IFileSystem
|
||||||
{
|
{
|
||||||
FileAttributes GetFileAttributes(string path);
|
FileAttributes GetFileAttributes(string path);
|
||||||
|
void SetFileAttributes(string path, FileAttributes attributes);
|
||||||
long GetFileSize(string path);
|
long GetFileSize(string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace LibHac.IO
|
||||||
public interface IFileSystem
|
public interface IFileSystem
|
||||||
{
|
{
|
||||||
void CreateDirectory(string path);
|
void CreateDirectory(string path);
|
||||||
void CreateFile(string path, long size);
|
void CreateFile(string path, long size, CreateFileOptions options);
|
||||||
void DeleteDirectory(string path);
|
void DeleteDirectory(string path);
|
||||||
void DeleteFile(string path);
|
void DeleteFile(string path);
|
||||||
IDirectory OpenDirectory(string path, OpenDirectoryMode mode);
|
IDirectory OpenDirectory(string path, OpenDirectoryMode mode);
|
||||||
|
@ -25,4 +25,11 @@ namespace LibHac.IO
|
||||||
Files = 2,
|
Files = 2,
|
||||||
All = Directories | Files
|
All = Directories | Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum CreateFileOptions
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
CreateConcatenationFile = 1 << 0
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -100,7 +100,7 @@ namespace LibHac.IO
|
||||||
public void Commit() { }
|
public void Commit() { }
|
||||||
|
|
||||||
public void CreateDirectory(string path) => throw new NotSupportedException();
|
public void CreateDirectory(string path) => throw new NotSupportedException();
|
||||||
public void CreateFile(string path, long size) => throw new NotSupportedException();
|
public void CreateFile(string path, long size, CreateFileOptions options) => throw new NotSupportedException();
|
||||||
public void DeleteDirectory(string path) => throw new NotSupportedException();
|
public void DeleteDirectory(string path) => throw new NotSupportedException();
|
||||||
public void DeleteFile(string path) => throw new NotSupportedException();
|
public void DeleteFile(string path) => throw new NotSupportedException();
|
||||||
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
|
|
|
@ -23,6 +23,12 @@ namespace LibHac.IO
|
||||||
return File.GetAttributes(ResolveLocalPath(path));
|
return File.GetAttributes(ResolveLocalPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFileAttributes(string path, FileAttributes attributes)
|
||||||
|
{
|
||||||
|
path = PathTools.Normalize(path);
|
||||||
|
File.SetAttributes(ResolveLocalPath(path), attributes);
|
||||||
|
}
|
||||||
|
|
||||||
public long GetFileSize(string path)
|
public long GetFileSize(string path)
|
||||||
{
|
{
|
||||||
path = PathTools.Normalize(path);
|
path = PathTools.Normalize(path);
|
||||||
|
@ -36,7 +42,7 @@ namespace LibHac.IO
|
||||||
Directory.CreateDirectory(ResolveLocalPath(path));
|
Directory.CreateDirectory(ResolveLocalPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
path = PathTools.Normalize(path);
|
path = PathTools.Normalize(path);
|
||||||
string localPath = ResolveLocalPath(path);
|
string localPath = ResolveLocalPath(path);
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace LibHac.IO
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,21 @@ namespace LibHac.IO
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetParentDirectory(string path)
|
||||||
|
{
|
||||||
|
if (path.Length == 0) return "/";
|
||||||
|
|
||||||
|
int i = path.Length - 1;
|
||||||
|
|
||||||
|
// A trailing separator should be ignored
|
||||||
|
if (path[i] == '/') i--;
|
||||||
|
|
||||||
|
while (i >= 0 && path[i] != '/') i--;
|
||||||
|
|
||||||
|
if (i < 1) return "/";
|
||||||
|
return path.Substring(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static bool IsDirectorySeparator(char c)
|
internal static bool IsDirectorySeparator(char c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -148,7 +148,7 @@ namespace LibHac.IO
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateDirectory(string path) => throw new NotSupportedException();
|
public void CreateDirectory(string path) => throw new NotSupportedException();
|
||||||
public void CreateFile(string path, long size) => throw new NotSupportedException();
|
public void CreateFile(string path, long size, CreateFileOptions options) => throw new NotSupportedException();
|
||||||
public void DeleteDirectory(string path) => throw new NotSupportedException();
|
public void DeleteDirectory(string path) => throw new NotSupportedException();
|
||||||
public void DeleteFile(string path) => throw new NotSupportedException();
|
public void DeleteFile(string path) => throw new NotSupportedException();
|
||||||
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException();
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace LibHac.IO.Save
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace LibHac.IO.Save
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
ParentFileSystem.CreateDirectory(ResolveFullPath(path));
|
ParentFileSystem.CreateDirectory(ResolveFullPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFile(string path, long size)
|
public void CreateFile(string path, long size, CreateFileOptions options)
|
||||||
{
|
{
|
||||||
path = PathTools.Normalize(path);
|
path = PathTools.Normalize(path);
|
||||||
|
|
||||||
ParentFileSystem.CreateFile(ResolveFullPath(path), size);
|
ParentFileSystem.CreateFile(ResolveFullPath(path), size, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteDirectory(string path)
|
public void DeleteDirectory(string path)
|
||||||
|
|
Loading…
Reference in a new issue