From 5a8744c6b5ed5f542fa6997d781cc57f71eb4e60 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 9 Jun 2019 21:31:00 -0500 Subject: [PATCH] Add basic filesystem accessors --- src/LibHac/Fs/Accessors/DirectoryAccessor.cs | 27 +++ src/LibHac/Fs/Accessors/FileAccessor.cs | 63 +++++++ src/LibHac/Fs/Accessors/FileSystemAccessor.cs | 155 ++++++++++++++++++ src/LibHac/Fs/Accessors/IAccessLogger.cs | 7 + src/LibHac/Fs/Accessors/MountTable.cs | 57 +++++++ src/LibHac/Fs/FileSystemManager.cs | 16 ++ src/LibHac/Horizon.cs | 16 ++ src/LibHac/ITimeSpanGenerator.cs | 9 + 8 files changed, 350 insertions(+) create mode 100644 src/LibHac/Fs/Accessors/DirectoryAccessor.cs create mode 100644 src/LibHac/Fs/Accessors/FileAccessor.cs create mode 100644 src/LibHac/Fs/Accessors/FileSystemAccessor.cs create mode 100644 src/LibHac/Fs/Accessors/IAccessLogger.cs create mode 100644 src/LibHac/Fs/Accessors/MountTable.cs create mode 100644 src/LibHac/Fs/FileSystemManager.cs create mode 100644 src/LibHac/Horizon.cs create mode 100644 src/LibHac/ITimeSpanGenerator.cs diff --git a/src/LibHac/Fs/Accessors/DirectoryAccessor.cs b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs new file mode 100644 index 00000000..6715c7ee --- /dev/null +++ b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace LibHac.Fs.Accessors +{ + public class DirectoryAccessor + { + private IDirectory Directory { get; } + + public FileSystemAccessor Parent { get; } + + public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent) + { + Directory = baseDirectory; + Parent = parent; + } + + public IEnumerable Read() + { + return Directory.Read(); + } + + public int GetEntryCount() + { + return Directory.GetEntryCount(); + } + } +} diff --git a/src/LibHac/Fs/Accessors/FileAccessor.cs b/src/LibHac/Fs/Accessors/FileAccessor.cs new file mode 100644 index 00000000..b3df935b --- /dev/null +++ b/src/LibHac/Fs/Accessors/FileAccessor.cs @@ -0,0 +1,63 @@ +using System; + +namespace LibHac.Fs.Accessors +{ + public class FileAccessor + { + private IFile File { get; } + + public FileSystemAccessor Parent { get; } + public WriteState WriteState { get; private set; } + public OpenMode OpenMode { get; } + + public FileAccessor(IFile baseFile, FileSystemAccessor parent, OpenMode mode) + { + File = baseFile; + Parent = parent; + OpenMode = mode; + } + + public int Read(Span destination, long offset, ReadOption options) + { + return File.Read(destination, offset, options); + } + + public void Write(ReadOnlySpan source, long offset, WriteOption options) + { + if (source.Length == 0) + { + WriteState = (WriteState)(~options & WriteOption.Flush); + + return; + } + + File.Write(source, offset, options); + + WriteState = (WriteState)(~options & WriteOption.Flush); + } + + public void Flush() + { + File.Flush(); + + WriteState = WriteState.None; + } + + public long GetSize() + { + return File.GetSize(); + } + + public void SetSize(long size) + { + File.SetSize(size); + } + } + + public enum WriteState + { + None, + Unflushed, + Error + } +} diff --git a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs new file mode 100644 index 00000000..6614870e --- /dev/null +++ b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using static LibHac.Fs.ResultsFs; + +namespace LibHac.Fs.Accessors +{ + public class FileSystemAccessor + { + public string Name { get; } + + private IFileSystem FileSystem { get; } + + private HashSet OpenFiles { get; } = new HashSet(); + private HashSet OpenDirectories { get; } = new HashSet(); + + private readonly object _locker = new object(); + + public FileSystemAccessor(string name, IFileSystem baseFileSystem) + { + Name = name; + FileSystem = baseFileSystem; + } + + public void CreateDirectory(string path) + { + FileSystem.CreateDirectory(path); + } + + public void CreateFile(string path, long size, CreateFileOptions options) + { + FileSystem.CreateFile(path, size, options); + } + + public void DeleteDirectory(string path) + { + FileSystem.DeleteDirectory(path); + } + + public void DeleteDirectoryRecursively(string path) + { + FileSystem.DeleteDirectoryRecursively(path); + } + + public void CleanDirectoryRecursively(string path) + { + FileSystem.CleanDirectoryRecursively(path); + } + + public void DeleteFile(string path) + { + FileSystem.DeleteFile(path); + } + + public DirectoryAccessor OpenDirectory(string path, OpenDirectoryMode mode) + { + IDirectory dir = FileSystem.OpenDirectory(path, mode); + + var accessor = new DirectoryAccessor(dir, this); + + lock (_locker) + { + OpenDirectories.Add(accessor); + } + + return accessor; + } + + public FileAccessor OpenFile(string path, OpenMode mode) + { + IFile file = FileSystem.OpenFile(path, mode); + + var accessor = new FileAccessor(file, this, mode); + + lock (_locker) + { + OpenFiles.Add(accessor); + } + + return accessor; + } + + public void RenameDirectory(string srcPath, string dstPath) + { + FileSystem.RenameDirectory(srcPath, dstPath); + } + + public void RenameFile(string srcPath, string dstPath) + { + FileSystem.RenameFile(srcPath, dstPath); + } + + public void DirectoryExists(string path) + { + FileSystem.DirectoryExists(path); + } + + public void FileExists(string path) + { + FileSystem.FileExists(path); + } + + public DirectoryEntryType GetEntryType(string path) + { + return FileSystem.GetEntryType(path); + } + + public long GetFreeSpaceSize(string path) + { + return FileSystem.GetFreeSpaceSize(path); + } + + public long GetTotalSpaceSize(string path) + { + return FileSystem.GetTotalSpaceSize(path); + } + + public FileTimeStampRaw GetFileTimeStampRaw(string path) + { + return FileSystem.GetFileTimeStampRaw(path); + } + + public void Commit() + { + if (OpenFiles.Any(x => (x.OpenMode & OpenMode.Write) != 0)) + { + ThrowHelper.ThrowResult(ResultFsWritableFileOpen); + } + + FileSystem.Commit(); + } + + public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + { + FileSystem.QueryEntry(outBuffer, inBuffer, path, queryId); + } + + internal void NotifyCloseFile(FileAccessor file) + { + lock (_locker) + { + OpenFiles.Remove(file); + } + } + + internal void NotifyCloseDirectory(DirectoryAccessor directory) + { + lock (_locker) + { + OpenDirectories.Remove(directory); + } + } + } +} diff --git a/src/LibHac/Fs/Accessors/IAccessLogger.cs b/src/LibHac/Fs/Accessors/IAccessLogger.cs new file mode 100644 index 00000000..a01db508 --- /dev/null +++ b/src/LibHac/Fs/Accessors/IAccessLogger.cs @@ -0,0 +1,7 @@ +namespace LibHac.Fs.Accessors +{ + public interface IAccessLogger + { + + } +} \ No newline at end of file diff --git a/src/LibHac/Fs/Accessors/MountTable.cs b/src/LibHac/Fs/Accessors/MountTable.cs new file mode 100644 index 00000000..c0c328d8 --- /dev/null +++ b/src/LibHac/Fs/Accessors/MountTable.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +using static LibHac.Results; +using static LibHac.Fs.ResultsFs; + +namespace LibHac.Fs.Accessors +{ + public class MountTable + { + private Dictionary Table { get; } = new Dictionary(); + + private readonly object _locker = new object(); + + public Result Mount(FileSystemAccessor fileSystem) + { + lock (_locker) + { + string mountName = fileSystem.Name; + + if (Table.ContainsKey(mountName)) + { + return ResultFsMountNameAlreadyExists; + } + + Table.Add(mountName, fileSystem); + + return ResultSuccess; + } + } + + public Result Find(string name, out FileSystemAccessor fileSystem) + { + lock (_locker) + { + if (!Table.TryGetValue(name, out fileSystem)) + { + return ResultFsMountNameNotFound; + } + + return ResultSuccess; + } + } + + public Result Unmount(string name) + { + lock (_locker) + { + if (!Table.Remove(name)) + { + return ResultFsMountNameNotFound; + } + + return ResultSuccess; + } + } + } +} diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs new file mode 100644 index 00000000..b17a60b7 --- /dev/null +++ b/src/LibHac/Fs/FileSystemManager.cs @@ -0,0 +1,16 @@ +using LibHac.Fs.Accessors; + +namespace LibHac.Fs +{ + public class FileSystemManager + { + internal Horizon Os { get; } + + internal MountTable MountTable { get; } = new MountTable(); + + public FileSystemManager(Horizon os) + { + Os = os; + } + } +} diff --git a/src/LibHac/Horizon.cs b/src/LibHac/Horizon.cs new file mode 100644 index 00000000..cfb0ccff --- /dev/null +++ b/src/LibHac/Horizon.cs @@ -0,0 +1,16 @@ +using LibHac.Fs; + +namespace LibHac +{ + public class Horizon + { + internal ITimeSpanGenerator Time { get; } + + public FileSystemManager Fs { get; } + + public Horizon() + { + Fs = new FileSystemManager(this); + } + } +} diff --git a/src/LibHac/ITimeSpanGenerator.cs b/src/LibHac/ITimeSpanGenerator.cs new file mode 100644 index 00000000..c9cdad38 --- /dev/null +++ b/src/LibHac/ITimeSpanGenerator.cs @@ -0,0 +1,9 @@ +using System; + +namespace LibHac +{ + public interface ITimeSpanGenerator + { + TimeSpan GetCurrent(); + } +} \ No newline at end of file