mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Update file system accessor classes
This commit is contained in:
parent
77aef9166f
commit
4efe313281
@ -14,6 +14,10 @@ namespace LibHac.Common
|
|||||||
private const int NullTerminatorLength = 1;
|
private const int NullTerminatorLength = 1;
|
||||||
|
|
||||||
public Span<byte> Buffer { get; private set; }
|
public Span<byte> Buffer { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current length of the string not including the null terminator.
|
||||||
|
/// </summary>
|
||||||
public int Length { get; private set; }
|
public int Length { get; private set; }
|
||||||
public bool Overflowed { get; private set; }
|
public bool Overflowed { get; private set; }
|
||||||
public bool AutoExpand { get; }
|
public bool AutoExpand { get; }
|
||||||
|
@ -635,7 +635,7 @@ namespace LibHac.Fs.Impl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Result rc = fs.Fs.GetGlobalAccessLogMode(out g.GlobalAccessLogMode);
|
Result rc = fs.Fs.GetGlobalAccessLogMode(out g.GlobalAccessLogMode);
|
||||||
fs.LogErrorMessage(rc);
|
fs.LogResultErrorMessage(rc);
|
||||||
if (rc.IsFailure()) Abort.DoAbort(rc);
|
if (rc.IsFailure()) Abort.DoAbort(rc);
|
||||||
|
|
||||||
if (g.GlobalAccessLogMode != GlobalAccessLogMode.None)
|
if (g.GlobalAccessLogMode != GlobalAccessLogMode.None)
|
||||||
@ -703,7 +703,7 @@ namespace LibHac.Fs.Impl
|
|||||||
public static void EnableFileSystemAccessorAccessLog(this FileSystemClientImpl fs, U8Span mountName)
|
public static void EnableFileSystemAccessorAccessLog(this FileSystemClientImpl fs, U8Span mountName)
|
||||||
{
|
{
|
||||||
Result rc = fs.Find(out FileSystemAccessor fileSystem, mountName);
|
Result rc = fs.Find(out FileSystemAccessor fileSystem, mountName);
|
||||||
fs.LogErrorMessage(rc);
|
fs.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
fileSystem.SetAccessLog(true);
|
fileSystem.SetAccessLog(true);
|
||||||
|
@ -60,7 +60,7 @@ namespace LibHac.Fs
|
|||||||
return _writeBufferLength;
|
return _writeBufferLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly int GetLength()
|
public readonly int GetLength()
|
||||||
{
|
{
|
||||||
return StringUtils.GetLength(GetString());
|
return StringUtils.GetLength(GetString());
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace LibHac.Fs
|
|||||||
{
|
{
|
||||||
if (IsValid)
|
if (IsValid)
|
||||||
{
|
{
|
||||||
Directory.GetParent().FsClient.CloseDirectory(this);
|
Directory.GetParent().Hos.Fs.CloseDirectory(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace LibHac.Fs
|
|||||||
{
|
{
|
||||||
if (IsValid)
|
if (IsValid)
|
||||||
{
|
{
|
||||||
File.FsClient.CloseFile(this);
|
File.Hos.Fs.CloseFile(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_directory?.Dispose();
|
IDirectory directory = Shared.Move(ref _directory);
|
||||||
_directory = null;
|
directory?.Dispose();
|
||||||
|
|
||||||
_parentFileSystem.NotifyCloseDirectory(this);
|
_parentFileSystem.NotifyCloseDirectory(this);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
internal class FileAccessor : IDisposable
|
internal class FileAccessor : IDisposable
|
||||||
{
|
{
|
||||||
|
private const string NeedFlushMessage = "Error: nn::fs::CloseFile() failed because the file was not flushed.\n";
|
||||||
|
|
||||||
private IFile _file;
|
private IFile _file;
|
||||||
private FileSystemAccessor _parentFileSystem;
|
private FileSystemAccessor _parentFileSystem;
|
||||||
private WriteState _writeState;
|
private WriteState _writeState;
|
||||||
@ -26,15 +28,17 @@ namespace LibHac.Fs.Impl
|
|||||||
// ReSharper disable once NotAccessedField.Local
|
// ReSharper disable once NotAccessedField.Local
|
||||||
private int _pathHashIndex;
|
private int _pathHashIndex;
|
||||||
|
|
||||||
internal FileSystemClient FsClient { get; }
|
internal HorizonClient Hos { get; }
|
||||||
|
|
||||||
public FileAccessor(FileSystemClient fsClient, ref IFile file, FileSystemAccessor parentFileSystem,
|
public FileAccessor(HorizonClient hosClient, ref IFile file, FileSystemAccessor parentFileSystem,
|
||||||
OpenMode mode)
|
OpenMode mode)
|
||||||
{
|
{
|
||||||
FsClient = fsClient;
|
Hos = hosClient;
|
||||||
|
|
||||||
_file = Shared.Move(ref file);
|
_file = Shared.Move(ref file);
|
||||||
_parentFileSystem = parentFileSystem;
|
_parentFileSystem = parentFileSystem;
|
||||||
|
_writeState = WriteState.None;
|
||||||
|
_lastResult = Result.Success;
|
||||||
_openMode = mode;
|
_openMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,13 +46,14 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
if (_lastResult.IsSuccess() && _writeState == WriteState.NeedsFlush)
|
if (_lastResult.IsSuccess() && _writeState == WriteState.NeedsFlush)
|
||||||
{
|
{
|
||||||
Abort.DoAbort(ResultFs.NeedFlush.Log(), "File needs flush before closing.");
|
Hos.Fs.Impl.LogErrorMessage(ResultFs.NeedFlush.Value, NeedFlushMessage);
|
||||||
|
Abort.DoAbort(ResultFs.NeedFlush.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_parentFileSystem?.NotifyCloseFile(this);
|
_parentFileSystem?.NotifyCloseFile(this);
|
||||||
_file?.Dispose();
|
|
||||||
|
|
||||||
_file = null;
|
IFile file = Shared.Move(ref _file);
|
||||||
|
file?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenMode GetOpenMode() => _openMode;
|
public OpenMode GetOpenMode() => _openMode;
|
||||||
@ -91,18 +96,18 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
if (_lastResult.IsFailure())
|
if (_lastResult.IsFailure())
|
||||||
{
|
{
|
||||||
if (FsClient.Impl.IsEnabledAccessLog() && FsClient.Impl.IsEnabledHandleAccessLog(handle))
|
if (Hos.Fs.Impl.IsEnabledAccessLog() && Hos.Fs.Impl.IsEnabledHandleAccessLog(handle))
|
||||||
{
|
{
|
||||||
Tick start = FsClient.Hos.Os.GetSystemTick();
|
Tick start = Hos.Os.GetSystemTick();
|
||||||
rc = _lastResult;
|
rc = _lastResult;
|
||||||
Tick end = FsClient.Hos.Os.GetSystemTick();
|
Tick end = Hos.Os.GetSystemTick();
|
||||||
|
|
||||||
var sb = new U8StringBuilder(logBuffer, true);
|
var sb = new U8StringBuilder(logBuffer, true);
|
||||||
sb.Append(LogOffset).AppendFormat(offset)
|
sb.Append(LogOffset).AppendFormat(offset)
|
||||||
.Append(LogSize).AppendFormat(destination.Length)
|
.Append(LogSize).AppendFormat(destination.Length)
|
||||||
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
||||||
|
|
||||||
FsClient.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
Hos.Fs.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
||||||
nameof(UserFile.ReadFile));
|
nameof(UserFile.ReadFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,18 +128,18 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (FsClient.Impl.IsEnabledAccessLog() && FsClient.Impl.IsEnabledHandleAccessLog(handle))
|
if (Hos.Fs.Impl.IsEnabledAccessLog() && Hos.Fs.Impl.IsEnabledHandleAccessLog(handle))
|
||||||
{
|
{
|
||||||
Tick start = FsClient.Hos.Os.GetSystemTick();
|
Tick start = Hos.Os.GetSystemTick();
|
||||||
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
rc = ReadWithoutCacheAccessLog(out bytesRead, offset, destination, in option);
|
||||||
Tick end = FsClient.Hos.Os.GetSystemTick();
|
Tick end = Hos.Os.GetSystemTick();
|
||||||
|
|
||||||
var sb = new U8StringBuilder(logBuffer, true);
|
var sb = new U8StringBuilder(logBuffer, true);
|
||||||
sb.Append(LogOffset).AppendFormat(offset)
|
sb.Append(LogOffset).AppendFormat(offset)
|
||||||
.Append(LogSize).AppendFormat(destination.Length)
|
.Append(LogSize).AppendFormat(destination.Length)
|
||||||
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
.Append(LogReadSize).AppendFormat(AccessLogImpl.DereferenceOutValue(in bytesRead, rc));
|
||||||
|
|
||||||
FsClient.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
Hos.Fs.Impl.OutputAccessLog(rc, start, end, handle, new U8Span(logBuffer),
|
||||||
nameof(UserFile.ReadFile));
|
nameof(UserFile.ReadFile));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -12,6 +12,12 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
internal class FileSystemAccessor : IDisposable
|
internal class FileSystemAccessor : IDisposable
|
||||||
{
|
{
|
||||||
|
private const string EmptyMountNameMessage = "Error: Mount failed because the mount name was empty.\n";
|
||||||
|
private const string TooLongMountNameMessage = "Error: Mount failed because the mount name was too long. The mount name was \"{0}\".\n";
|
||||||
|
private const string FileNotClosedMessage = "Error: Unmount failed because not all files were closed.\n";
|
||||||
|
private const string DirectoryNotClosedMessage = "Error: Unmount failed because not all directories were closed.\n";
|
||||||
|
private const string InvalidFsEntryObjectMessage = "Invalid file or directory object.";
|
||||||
|
|
||||||
private MountName _mountName;
|
private MountName _mountName;
|
||||||
private IFileSystem _fileSystem;
|
private IFileSystem _fileSystem;
|
||||||
private LinkedList<FileAccessor> _openFiles;
|
private LinkedList<FileAccessor> _openFiles;
|
||||||
@ -24,14 +30,16 @@ namespace LibHac.Fs.Impl
|
|||||||
private bool _isPathCacheAttachable;
|
private bool _isPathCacheAttachable;
|
||||||
private bool _isPathCacheAttached;
|
private bool _isPathCacheAttached;
|
||||||
private IMultiCommitTarget _multiCommitTarget;
|
private IMultiCommitTarget _multiCommitTarget;
|
||||||
|
private PathFlags _pathFlags;
|
||||||
|
private Optional<Ncm.DataId> _dataId;
|
||||||
|
|
||||||
internal FileSystemClient FsClient { get; }
|
internal HorizonClient Hos { get; }
|
||||||
|
|
||||||
public FileSystemAccessor(FileSystemClient fsClient, U8Span name, IMultiCommitTarget multiCommitTarget,
|
public FileSystemAccessor(HorizonClient hosClient, U8Span name, IMultiCommitTarget multiCommitTarget,
|
||||||
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
|
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
|
||||||
ISaveDataAttributeGetter saveAttributeGetter)
|
ISaveDataAttributeGetter saveAttributeGetter)
|
||||||
{
|
{
|
||||||
FsClient = fsClient;
|
Hos = hosClient;
|
||||||
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_openFiles = new LinkedList<FileAccessor>();
|
_openFiles = new LinkedList<FileAccessor>();
|
||||||
@ -42,32 +50,43 @@ namespace LibHac.Fs.Impl
|
|||||||
_multiCommitTarget = multiCommitTarget;
|
_multiCommitTarget = multiCommitTarget;
|
||||||
|
|
||||||
if (name.IsEmpty())
|
if (name.IsEmpty())
|
||||||
Abort.DoAbort(ResultFs.InvalidMountName.Log());
|
{
|
||||||
|
Hos.Fs.Impl.LogErrorMessage(ResultFs.InvalidMountName.Value, EmptyMountNameMessage);
|
||||||
|
Abort.DoAbort(ResultFs.InvalidMountName.Value);
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.GetLength(name, PathTool.MountNameLengthMax + 1) > PathTool.MountNameLengthMax)
|
int mountLength = StringUtils.Copy(_mountName.Name, name, PathTool.MountNameLengthMax + 1);
|
||||||
Abort.DoAbort(ResultFs.InvalidMountName.Log());
|
|
||||||
|
|
||||||
StringUtils.Copy(_mountName.Name.Slice(0, PathTool.MountNameLengthMax), name);
|
if (mountLength > PathTool.MountNameLengthMax)
|
||||||
_mountName.Name[PathTool.MountNameLengthMax] = 0;
|
{
|
||||||
|
Hos.Fs.Impl.LogErrorMessage(ResultFs.InvalidMountName.Value, TooLongMountNameMessage,
|
||||||
|
name.ToString());
|
||||||
|
Abort.DoAbort(ResultFs.InvalidMountName.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.Compare(_mountName.Name, CommonMountNames.HostRootFileSystemMountName) == 0)
|
||||||
|
{
|
||||||
|
_pathFlags.AllowWindowsPath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!disposing) return;
|
|
||||||
|
|
||||||
using (ScopedLock.Lock(ref _openListLock))
|
using (ScopedLock.Lock(ref _openListLock))
|
||||||
{
|
{
|
||||||
Abort.DoAbortUnless(_openFiles.Count == 0, ResultFs.FileNotClosed.Value,
|
DumpUnclosedAccessorList(OpenMode.All, OpenDirectoryMode.All);
|
||||||
"All files must be closed before unmounting.");
|
|
||||||
|
|
||||||
Abort.DoAbortUnless(_openDirectories.Count == 0, ResultFs.DirectoryNotClosed.Value,
|
if (_openFiles.Count != 0)
|
||||||
"All directories must be closed before unmounting.");
|
{
|
||||||
|
Hos.Fs.Impl.LogErrorMessage(ResultFs.FileNotClosed.Value, FileNotClosedMessage);
|
||||||
|
Abort.DoAbort(ResultFs.FileNotClosed.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_openDirectories.Count != 0)
|
||||||
|
{
|
||||||
|
Hos.Fs.Impl.LogErrorMessage(ResultFs.DirectoryNotClosed.Value, DirectoryNotClosedMessage);
|
||||||
|
Abort.DoAbort(ResultFs.DirectoryNotClosed.Value);
|
||||||
|
}
|
||||||
|
|
||||||
if (_isPathCacheAttached)
|
if (_isPathCacheAttached)
|
||||||
{
|
{
|
||||||
@ -75,46 +94,27 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_saveDataAttributeGetter?.Dispose();
|
ISaveDataAttributeGetter saveDataAttributeGetter = Shared.Move(ref _saveDataAttributeGetter);
|
||||||
_saveDataAttributeGetter = null;
|
saveDataAttributeGetter?.Dispose();
|
||||||
|
|
||||||
_mountNameGenerator?.Dispose();
|
ICommonMountNameGenerator mountNameGenerator = Shared.Move(ref _mountNameGenerator);
|
||||||
_mountNameGenerator = null;
|
mountNameGenerator?.Dispose();
|
||||||
|
|
||||||
_fileSystem?.Dispose();
|
IFileSystem fileSystem = Shared.Move(ref _fileSystem);
|
||||||
_fileSystem = null;
|
fileSystem?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Remove<T>(LinkedList<T> list, T item)
|
private static void Remove<T>(LinkedList<T> list, T item)
|
||||||
{
|
{
|
||||||
LinkedListNode<T> node = list.Find(item);
|
LinkedListNode<T> node = list.Find(item);
|
||||||
Abort.DoAbortUnless(node is not null, "Invalid file or directory object.");
|
|
||||||
|
|
||||||
list.Remove(node);
|
if (node is not null)
|
||||||
}
|
|
||||||
|
|
||||||
private static Result CheckPath(U8Span mountName, U8Span path)
|
|
||||||
{
|
|
||||||
int mountNameLength = StringUtils.GetLength(mountName, PathTool.MountNameLengthMax);
|
|
||||||
int pathLength = StringUtils.GetLength(path, PathTool.EntryNameLengthMax);
|
|
||||||
|
|
||||||
if (mountNameLength + 1 + pathLength > PathTool.EntryNameLengthMax)
|
|
||||||
return ResultFs.TooLongPath.Log();
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool HasOpenWriteModeFiles(LinkedList<FileAccessor> list)
|
|
||||||
{
|
|
||||||
for (LinkedListNode<FileAccessor> file = list.First; file is not null; file = file.Next)
|
|
||||||
{
|
{
|
||||||
if (file.Value.GetOpenMode().HasFlag(OpenMode.Write))
|
list.Remove(node);
|
||||||
{
|
return;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
Assert.SdkAssert(false, InvalidFsEntryObjectMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAccessLog(bool isEnabled) => _isAccessLogEnabled = isEnabled;
|
public void SetAccessLog(bool isEnabled) => _isAccessLogEnabled = isEnabled;
|
||||||
@ -131,9 +131,44 @@ namespace LibHac.Fs.Impl
|
|||||||
_isPathCacheAttached = true;
|
_isPathCacheAttached = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Ncm.DataId> GetDataId() => _dataId;
|
||||||
|
public void SetDataId(Ncm.DataId dataId) => _dataId.Set(dataId);
|
||||||
|
|
||||||
|
public Result SetUpPath(ref Path path, U8Span pathBuffer)
|
||||||
|
{
|
||||||
|
Result rc = PathFormatter.IsNormalized(out bool isNormalized, out _, pathBuffer, _pathFlags);
|
||||||
|
|
||||||
|
if (rc.IsSuccess() && isNormalized)
|
||||||
|
{
|
||||||
|
path.SetShallowBuffer(pathBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_pathFlags.IsWindowsPathAllowed())
|
||||||
|
{
|
||||||
|
rc = path.InitializeWithReplaceForwardSlashes(pathBuffer);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = path.InitializeWithReplaceBackslash(pathBuffer);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = path.Normalize(_pathFlags);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.GetLength() > PathTool.EntryNameLengthMax)
|
||||||
|
return ResultFs.TooLongPath.Log();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
public Result CreateFile(U8Span path, long size, CreateFileOptions option)
|
public Result CreateFile(U8Span path, long size, CreateFileOptions option)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (_isPathCacheAttached)
|
if (_isPathCacheAttached)
|
||||||
@ -142,80 +177,87 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = _fileSystem.CreateFile(path, size, option);
|
rc = _fileSystem.CreateFile(in pathNormalized, size, option);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result DeleteFile(U8Span path)
|
public Result DeleteFile(U8Span path)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.DeleteFile(path);
|
rc = _fileSystem.DeleteFile(in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result CreateDirectory(U8Span path)
|
public Result CreateDirectory(U8Span path)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.CreateDirectory(path);
|
rc = _fileSystem.CreateDirectory(in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result DeleteDirectory(U8Span path)
|
public Result DeleteDirectory(U8Span path)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.DeleteDirectory(path);
|
rc = _fileSystem.CreateDirectory(in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result DeleteDirectoryRecursively(U8Span path)
|
public Result DeleteDirectoryRecursively(U8Span path)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.DeleteDirectoryRecursively(path);
|
rc = _fileSystem.DeleteDirectoryRecursively(in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result CleanDirectoryRecursively(U8Span path)
|
public Result CleanDirectoryRecursively(U8Span path)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.CleanDirectoryRecursively(path);
|
rc = _fileSystem.CleanDirectoryRecursively(in pathNormalized);
|
||||||
}
|
|
||||||
|
|
||||||
public Result RenameFile(U8Span oldPath, U8Span newPath)
|
|
||||||
{
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), oldPath);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = CheckPath(new U8Span(_mountName.Name), newPath);
|
pathNormalized.Dispose();
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
if (_isPathCacheAttached)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = _fileSystem.RenameFile(oldPath, newPath);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result RenameDirectory(U8Span oldPath, U8Span newPath)
|
public Result RenameFile(U8Span currentPath, U8Span newPath)
|
||||||
{
|
{
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), oldPath);
|
var currentPathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref currentPathNormalized, currentPath);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = CheckPath(new U8Span(_mountName.Name), newPath);
|
var newPathNormalized = new Path();
|
||||||
|
rc = SetUpPath(ref newPathNormalized, newPath);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (_isPathCacheAttached)
|
if (_isPathCacheAttached)
|
||||||
@ -224,10 +266,37 @@ namespace LibHac.Fs.Impl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = _fileSystem.RenameDirectory(oldPath, newPath);
|
rc = _fileSystem.RenameFile(in currentPathNormalized, in newPathNormalized);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentPathNormalized.Dispose();
|
||||||
|
newPathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result RenameDirectory(U8Span currentPath, U8Span newPath)
|
||||||
|
{
|
||||||
|
var currentPathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref currentPathNormalized, currentPath);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var newPathNormalized = new Path();
|
||||||
|
rc = SetUpPath(ref newPathNormalized, newPath);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (_isPathCacheAttached)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = _fileSystem.RenameDirectory(in currentPathNormalized, in newPathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPathNormalized.Dispose();
|
||||||
|
newPathNormalized.Dispose();
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,46 +304,62 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out entryType);
|
UnsafeHelpers.SkipParamInit(out entryType);
|
||||||
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.GetEntryType(out entryType, path);
|
rc = _fileSystem.GetEntryType(out entryType, in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result GetFreeSpaceSize(out long freeSpace, U8Span path)
|
public Result GetFreeSpaceSize(out long freeSpace, U8Span path)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out freeSpace);
|
UnsafeHelpers.SkipParamInit(out freeSpace);
|
||||||
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.GetFreeSpaceSize(out freeSpace, path);
|
rc = _fileSystem.GetFreeSpaceSize(out freeSpace, in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result GetTotalSpaceSize(out long totalSpace, U8Span path)
|
public Result GetTotalSpaceSize(out long totalSpace, U8Span path)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out totalSpace);
|
UnsafeHelpers.SkipParamInit(out totalSpace);
|
||||||
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return _fileSystem.GetTotalSpaceSize(out totalSpace, path);
|
rc = _fileSystem.GetTotalSpaceSize(out totalSpace, in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenFile(out FileAccessor file, U8Span path, OpenMode mode)
|
public Result OpenFile(out FileAccessor file, U8Span path, OpenMode mode)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out file);
|
UnsafeHelpers.SkipParamInit(out file);
|
||||||
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IFile iFile = null;
|
IFile iFile = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenFile(out iFile, path, mode);
|
rc = _fileSystem.OpenFile(out iFile, in pathNormalized, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
var fileAccessor = new FileAccessor(FsClient, ref iFile, this, mode);
|
var fileAccessor = new FileAccessor(Hos, ref iFile, this, mode);
|
||||||
|
|
||||||
using (ScopedLock.Lock(ref _openListLock))
|
using (ScopedLock.Lock(ref _openListLock))
|
||||||
{
|
{
|
||||||
@ -299,6 +384,7 @@ namespace LibHac.Fs.Impl
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
iFile?.Dispose();
|
iFile?.Dispose();
|
||||||
|
pathNormalized.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,13 +392,14 @@ namespace LibHac.Fs.Impl
|
|||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out directory);
|
UnsafeHelpers.SkipParamInit(out directory);
|
||||||
|
|
||||||
Result rc = CheckPath(new U8Span(_mountName.Name), path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
IDirectory iDirectory = null;
|
IDirectory iDirectory = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rc = _fileSystem.OpenDirectory(out iDirectory, path, mode);
|
rc = _fileSystem.OpenDirectory(out iDirectory, in pathNormalized, mode);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
var directoryAccessor = new DirectoryAccessor(ref iDirectory, this);
|
var directoryAccessor = new DirectoryAccessor(ref iDirectory, this);
|
||||||
@ -328,11 +415,25 @@ namespace LibHac.Fs.Impl
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
iDirectory?.Dispose();
|
iDirectory?.Dispose();
|
||||||
|
pathNormalized.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Commit()
|
public Result Commit()
|
||||||
{
|
{
|
||||||
|
static bool HasOpenWriteModeFiles(LinkedList<FileAccessor> list)
|
||||||
|
{
|
||||||
|
for (LinkedListNode<FileAccessor> file = list.First; file is not null; file = file.Next)
|
||||||
|
{
|
||||||
|
if (file.Value.GetOpenMode().HasFlag(OpenMode.Write))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
using (ScopedLock.Lock(ref _openListLock))
|
using (ScopedLock.Lock(ref _openListLock))
|
||||||
{
|
{
|
||||||
DumpUnclosedAccessorList(OpenMode.Write, 0);
|
DumpUnclosedAccessorList(OpenMode.Write, 0);
|
||||||
@ -346,12 +447,30 @@ namespace LibHac.Fs.Impl
|
|||||||
|
|
||||||
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
|
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
|
||||||
{
|
{
|
||||||
return _fileSystem.GetFileTimeStampRaw(out timeStamp, path);
|
UnsafeHelpers.SkipParamInit(out timeStamp);
|
||||||
|
|
||||||
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = _fileSystem.GetFileTimeStampRaw(out timeStamp, in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
|
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
|
||||||
{
|
{
|
||||||
return _fileSystem.QueryEntry(outBuffer, inBuffer, queryId, path);
|
var pathNormalized = new Path();
|
||||||
|
Result rc = SetUpPath(ref pathNormalized, path);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = _fileSystem.QueryEntry(outBuffer, inBuffer, queryId, in pathNormalized);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
pathNormalized.Dispose();
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public U8Span GetName()
|
public U8Span GetName()
|
||||||
@ -374,7 +493,10 @@ namespace LibHac.Fs.Impl
|
|||||||
if (_saveDataAttributeGetter is null)
|
if (_saveDataAttributeGetter is null)
|
||||||
return ResultFs.PreconditionViolation.Log();
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
return _saveDataAttributeGetter.GetSaveDataAttribute(out attribute);
|
Result rc = _saveDataAttributeGetter.GetSaveDataAttribute(out attribute);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
|
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
|
||||||
@ -387,21 +509,203 @@ namespace LibHac.Fs.Impl
|
|||||||
cacheAccessor.Purge(_fileSystem);
|
cacheAccessor.Purge(_fileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotifyCloseFile(FileAccessor file)
|
internal void NotifyCloseFile(FileAccessor file)
|
||||||
{
|
{
|
||||||
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
|
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
|
||||||
Remove(_openFiles, file);
|
Remove(_openFiles, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NotifyCloseDirectory(DirectoryAccessor directory)
|
internal void NotifyCloseDirectory(DirectoryAccessor directory)
|
||||||
{
|
{
|
||||||
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
|
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
|
||||||
Remove(_openDirectories, directory);
|
Remove(_openDirectories, directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogFsModuleName => new[] { (byte)'$', (byte)'f', (byte)'s' }; // "$fs"
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogFsErrorInfo => // "------ FS ERROR INFORMATION ------\n"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'-', (byte)'-', (byte)'-', (byte)'-', (byte)'-', (byte)'-', (byte)' ', (byte)'F',
|
||||||
|
(byte)'S', (byte)' ', (byte)'E', (byte)'R', (byte)'R', (byte)'O', (byte)'R', (byte)' ',
|
||||||
|
(byte)'I', (byte)'N', (byte)'F', (byte)'O', (byte)'R', (byte)'M', (byte)'A', (byte)'T',
|
||||||
|
(byte)'I', (byte)'O', (byte)'N', (byte)' ', (byte)'-', (byte)'-', (byte)'-', (byte)'-',
|
||||||
|
(byte)'-', (byte)'-', (byte)'\\', (byte)'n'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogFileNotClosed => // "Error: File not closed"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'E', (byte)'r', (byte)'r', (byte)'o', (byte)'r', (byte)':', (byte)' ', (byte)'F',
|
||||||
|
(byte)'i', (byte)'l', (byte)'e', (byte)' ', (byte)'n', (byte)'o', (byte)'t', (byte)' ',
|
||||||
|
(byte)'c', (byte)'l', (byte)'o', (byte)'s', (byte)'e', (byte)'d'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogDirectoryNotClosed => // "Error: Directory not closed"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'E', (byte)'r', (byte)'r', (byte)'o', (byte)'r', (byte)':', (byte)' ', (byte)'D',
|
||||||
|
(byte)'i', (byte)'r', (byte)'e', (byte)'c', (byte)'t', (byte)'o', (byte)'r', (byte)'y',
|
||||||
|
(byte)' ', (byte)'n', (byte)'o', (byte)'t', (byte)' ', (byte)'c', (byte)'l', (byte)'o',
|
||||||
|
(byte)'s', (byte)'e', (byte)'d'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogMountName => // " (mount_name: ""
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)' ', (byte)'(', (byte)'m', (byte)'o', (byte)'u', (byte)'n', (byte)'t', (byte)'_',
|
||||||
|
(byte)'n', (byte)'a', (byte)'m', (byte)'e', (byte)':', (byte)' ', (byte)'"'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogCount => // "", count: "
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'"', (byte)',', (byte)' ', (byte)'c', (byte)'o', (byte)'u', (byte)'n', (byte)'t',
|
||||||
|
(byte)':', (byte)' '
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ReadOnlySpan<byte> LogLineEnd => new[] { (byte)')', (byte)'\\', (byte)'n' }; // ")\n"
|
||||||
|
|
||||||
|
public static ReadOnlySpan<byte> LogOrOperator => new[] { (byte)' ', (byte)'|', (byte)' ' }; // " | "
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogOpenModeRead => // "OpenMode_Read"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'O', (byte)'p', (byte)'e', (byte)'n', (byte)'M', (byte)'o', (byte)'d', (byte)'e',
|
||||||
|
(byte)'_', (byte)'R', (byte)'e', (byte)'a', (byte)'d'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogOpenModeWrite => // "OpenMode_Write"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'O', (byte)'p', (byte)'e', (byte)'n', (byte)'M', (byte)'o', (byte)'d', (byte)'e',
|
||||||
|
(byte)'_', (byte)'W', (byte)'r', (byte)'i', (byte)'t', (byte)'e'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogOpenModeAppend => // "OpenMode_AllowAppend"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)'O', (byte)'p', (byte)'e', (byte)'n', (byte)'M', (byte)'o', (byte)'d', (byte)'e',
|
||||||
|
(byte)'_', (byte)'A', (byte)'l', (byte)'l', (byte)'o', (byte)'w', (byte)'A', (byte)'p',
|
||||||
|
(byte)'p', (byte)'e', (byte)'n', (byte)'d'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogHandle => // " handle: 0x"
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)' ', (byte)' ', (byte)' ', (byte)' ', (byte)' ', (byte)'h', (byte)'a', (byte)'n',
|
||||||
|
(byte)'d', (byte)'l', (byte)'e', (byte)':', (byte)' ', (byte)'0', (byte)'x'
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogOpenMode => // ", open_mode: "
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)',', (byte)' ', (byte)'o', (byte)'p', (byte)'e', (byte)'n', (byte)'_', (byte)'m',
|
||||||
|
(byte)'o', (byte)'d', (byte)'e', (byte)':', (byte)' '
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> LogSize => // ", size: "
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
(byte)',', (byte)' ', (byte)'s', (byte)'i', (byte)'z', (byte)'e', (byte)':', (byte)' '
|
||||||
|
};
|
||||||
|
|
||||||
private void DumpUnclosedAccessorList(OpenMode fileOpenModeMask, OpenDirectoryMode directoryOpenModeMask)
|
private void DumpUnclosedAccessorList(OpenMode fileOpenModeMask, OpenDirectoryMode directoryOpenModeMask)
|
||||||
{
|
{
|
||||||
// Todo: Implement
|
static int GetOpenFileCount(LinkedList<FileAccessor> list, OpenMode mask)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (LinkedListNode<FileAccessor> file = list.First; file is not null; file = file.Next)
|
||||||
|
{
|
||||||
|
if ((file.Value.GetOpenMode() & mask) != 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> stringBuffer = stackalloc byte[0xA0];
|
||||||
|
Span<byte> openModeStringBuffer = stackalloc byte[0x40];
|
||||||
|
|
||||||
|
int openFileCount = GetOpenFileCount(_openFiles, fileOpenModeMask);
|
||||||
|
|
||||||
|
if (openFileCount > 0 || directoryOpenModeMask != 0 && _openDirectories.Count != 0)
|
||||||
|
{
|
||||||
|
Hos.Diag.Impl.LogImpl(LogFsModuleName, LogSeverity.Error, LogFsErrorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openFileCount > 0)
|
||||||
|
{
|
||||||
|
var sb = new U8StringBuilder(stringBuffer, true);
|
||||||
|
sb.Append(LogFileNotClosed).Append(LogMountName).Append(GetName()).Append(LogCount)
|
||||||
|
.AppendFormat(openFileCount).Append(LogLineEnd);
|
||||||
|
|
||||||
|
Hos.Diag.Impl.LogImpl(LogFsModuleName, LogSeverity.Error, sb.Buffer);
|
||||||
|
sb.Dispose();
|
||||||
|
|
||||||
|
for (LinkedListNode<FileAccessor> file = _openFiles.First; file is not null; file = file.Next)
|
||||||
|
{
|
||||||
|
OpenMode openMode = file.Value.GetOpenMode();
|
||||||
|
|
||||||
|
if ((openMode & fileOpenModeMask) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Result rc = file.Value.GetSize(out long fileSize);
|
||||||
|
if (rc.IsFailure())
|
||||||
|
fileSize = -1;
|
||||||
|
|
||||||
|
var openModeString = new U8StringBuilder(openModeStringBuffer);
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> readModeString = openMode.HasFlag(OpenMode.Read) ? LogOpenModeRead : default;
|
||||||
|
openModeString.Append(readModeString);
|
||||||
|
Assert.SdkAssert(!openModeString.Overflowed);
|
||||||
|
|
||||||
|
if (openMode.HasFlag(OpenMode.Write))
|
||||||
|
{
|
||||||
|
if (openModeString.Length > 0)
|
||||||
|
sb.Append(LogOrOperator);
|
||||||
|
|
||||||
|
openModeString.Append(LogOpenModeWrite);
|
||||||
|
Assert.SdkAssert(!openModeString.Overflowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openMode.HasFlag(OpenMode.AllowAppend))
|
||||||
|
{
|
||||||
|
if (openModeString.Length > 0)
|
||||||
|
sb.Append(LogOrOperator);
|
||||||
|
|
||||||
|
openModeString.Append(LogOpenModeAppend);
|
||||||
|
Assert.SdkAssert(!openModeString.Overflowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileInfoString = new U8StringBuilder(stringBuffer, true);
|
||||||
|
fileInfoString.Append(LogHandle).AppendFormat(file.Value.GetHashCode(), 'x', 16).Append(LogOpenMode)
|
||||||
|
.Append(openModeString.Buffer).Append(LogSize).AppendFormat(fileSize).Append((byte) '\n');
|
||||||
|
|
||||||
|
Hos.Diag.Impl.LogImpl(LogFsModuleName, LogSeverity.Error, fileInfoString.Buffer);
|
||||||
|
fileInfoString.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directoryOpenModeMask != 0 && _openDirectories.Count != 0)
|
||||||
|
{
|
||||||
|
var sb = new U8StringBuilder(stringBuffer, true);
|
||||||
|
sb.Append(LogDirectoryNotClosed).Append(LogMountName).Append(GetName()).Append(LogCount)
|
||||||
|
.AppendFormat(_openDirectories.Count).Append(LogLineEnd);
|
||||||
|
|
||||||
|
Hos.Diag.Impl.LogImpl(LogFsModuleName, LogSeverity.Error, sb.Buffer);
|
||||||
|
sb.Dispose();
|
||||||
|
|
||||||
|
for (LinkedListNode<DirectoryAccessor> dir = _openDirectories.First; dir is not null; dir = dir.Next)
|
||||||
|
{
|
||||||
|
var dirInfoString = new U8StringBuilder(stringBuffer, true);
|
||||||
|
dirInfoString.Append(LogHandle).AppendFormat(dir.Value.GetHashCode(), 'x', 16).Append((byte)'\n');
|
||||||
|
|
||||||
|
Hos.Diag.Impl.LogImpl(LogFsModuleName, LogSeverity.Error, dirInfoString.Buffer);
|
||||||
|
dirInfoString.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
{
|
{
|
||||||
rc = fs.Impl.Unmount(mountName);
|
rc = fs.Impl.Unmount(mountName);
|
||||||
}
|
}
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
{
|
{
|
||||||
rc = fs.Impl.IsMounted(out isMounted, mountName);
|
rc = fs.Impl.IsMounted(out isMounted, mountName);
|
||||||
}
|
}
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
return isMounted;
|
return isMounted;
|
||||||
|
@ -18,7 +18,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
{
|
{
|
||||||
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem)
|
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
var accessor = new FileSystemAccessor(fs, name, null, fileSystem, null, null);
|
var accessor = new FileSystemAccessor(fs.Hos, name, null, fileSystem, null, null);
|
||||||
fs.Impl.Register(accessor);
|
fs.Impl.Register(accessor);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -27,7 +27,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem,
|
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem,
|
||||||
ICommonMountNameGenerator mountNameGenerator)
|
ICommonMountNameGenerator mountNameGenerator)
|
||||||
{
|
{
|
||||||
var accessor = new FileSystemAccessor(fs, name, null, fileSystem, mountNameGenerator, null);
|
var accessor = new FileSystemAccessor(fs.Hos, name, null, fileSystem, mountNameGenerator, null);
|
||||||
fs.Impl.Register(accessor);
|
fs.Impl.Register(accessor);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
@ -44,7 +44,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
|
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
|
||||||
ISaveDataAttributeGetter saveAttributeGetter, bool useDataCache, bool usePathCache)
|
ISaveDataAttributeGetter saveAttributeGetter, bool useDataCache, bool usePathCache)
|
||||||
{
|
{
|
||||||
var accessor = new FileSystemAccessor(fs, name, multiCommitTarget, fileSystem, mountNameGenerator,
|
var accessor = new FileSystemAccessor(fs.Hos, name, multiCommitTarget, fileSystem, mountNameGenerator,
|
||||||
saveAttributeGetter);
|
saveAttributeGetter);
|
||||||
|
|
||||||
accessor.SetFileDataCacheAttachable(useDataCache);
|
accessor.SetFileDataCacheAttachable(useDataCache);
|
||||||
|
@ -530,7 +530,7 @@ namespace LibHac.Fs.Fsa
|
|||||||
|
|
||||||
public static Result OpenFile(this FileSystemClient fs, out FileHandle handle, IFile file, OpenMode mode)
|
public static Result OpenFile(this FileSystemClient fs, out FileHandle handle, IFile file, OpenMode mode)
|
||||||
{
|
{
|
||||||
var accessor = new FileAccessor(fs, ref file, null, mode);
|
var accessor = new FileAccessor(fs.Hos, ref file, null, mode);
|
||||||
handle = new FileHandle(accessor);
|
handle = new FileHandle(accessor);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -42,8 +42,18 @@ namespace LibHac.Fs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LogErrorMessage(this FileSystemClientImpl fs, Result result,
|
public static void LogErrorMessage(this FileSystemClientImpl fs, Result result, string message)
|
||||||
[CallerMemberName] string functionName = "")
|
{
|
||||||
|
// Todo
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogErrorMessage(this FileSystemClientImpl fs, Result result, string format, object arg0)
|
||||||
|
{
|
||||||
|
// Todo
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogErrorMessage(this FileSystemClientImpl fs, Result result, string format,
|
||||||
|
params object[] args)
|
||||||
{
|
{
|
||||||
// Todo
|
// Todo
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ namespace LibHac.Fs.Shim
|
|||||||
int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);
|
int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);
|
||||||
if (pathLen > PathTools.MaxPathLength)
|
if (pathLen > PathTools.MaxPathLength)
|
||||||
{
|
{
|
||||||
fs.Impl.LogErrorMessage(ResultFs.TooLongPath.Value);
|
fs.Impl.LogResultErrorMessage(ResultFs.TooLongPath.Value);
|
||||||
return ResultFs.TooLongPath.Log();
|
return ResultFs.TooLongPath.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ namespace LibHac.Fs.Shim
|
|||||||
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
||||||
|
|
||||||
rc = fsProxy.Target.SetBisRootForHost(partitionId, in sfPath);
|
rc = fsProxy.Target.SetBisRootForHost(partitionId, in sfPath);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,11 +157,11 @@ namespace LibHac.Fs.Shim
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
|
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
rc = deviceOperator.Target.IsGameCardInserted(out bool isInserted);
|
rc = deviceOperator.Target.IsGameCardInserted(out bool isInserted);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
return isInserted;
|
return isInserted;
|
||||||
|
@ -508,7 +508,7 @@ namespace LibHac.Fs.Shim
|
|||||||
{
|
{
|
||||||
rc = fs.Impl.Unmount(mountName);
|
rc = fs.Impl.Unmount(mountName);
|
||||||
}
|
}
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1788,7 +1788,7 @@ namespace LibHac.Fs.Shim
|
|||||||
|
|
||||||
Result rc = fsProxy.Target.DisableAutoSaveDataCreation();
|
Result rc = fsProxy.Target.DisableAutoSaveDataCreation();
|
||||||
|
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +136,11 @@ namespace LibHac.Fs.Shim
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
|
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
rc = CheckIfInserted(fs, deviceOperator, out bool isInserted);
|
rc = CheckIfInserted(fs, deviceOperator, out bool isInserted);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
return isInserted;
|
return isInserted;
|
||||||
@ -191,7 +191,7 @@ namespace LibHac.Fs.Shim
|
|||||||
public static void SetSdCardAccessibility(this FileSystemClient fs, bool isAccessible)
|
public static void SetSdCardAccessibility(this FileSystemClient fs, bool isAccessible)
|
||||||
{
|
{
|
||||||
Result rc = fs.Impl.SetSdCardAccessibility(isAccessible);
|
Result rc = fs.Impl.SetSdCardAccessibility(isAccessible);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ namespace LibHac.Fs.Shim
|
|||||||
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
||||||
|
|
||||||
Result rc = fsProxy.Target.IsSdCardAccessible(out bool isAccessible);
|
Result rc = fsProxy.Target.IsSdCardAccessible(out bool isAccessible);
|
||||||
fs.Impl.LogErrorMessage(rc);
|
fs.Impl.LogResultErrorMessage(rc);
|
||||||
Abort.DoAbortUnless(rc.IsSuccess());
|
Abort.DoAbortUnless(rc.IsSuccess());
|
||||||
|
|
||||||
return isAccessible;
|
return isAccessible;
|
||||||
|
@ -330,7 +330,9 @@ namespace hactoolnet
|
|||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
save.GetFreeSpaceSize(out long freeSpace, "".ToU8String()).ThrowIfFailure();
|
var emptyPath = new LibHac.Fs.Path();
|
||||||
|
emptyPath.InitializeAsEmpty().ThrowIfFailure();
|
||||||
|
save.GetFreeSpaceSize(out long freeSpace, in emptyPath).ThrowIfFailure();
|
||||||
|
|
||||||
sb.AppendLine("Savefile:");
|
sb.AppendLine("Savefile:");
|
||||||
PrintItem(sb, colLen, "CMAC Key Used:", keySet.DeviceUniqueSaveMacKeys[0].DataRo.ToArray());
|
PrintItem(sb, colLen, "CMAC Key Used:", keySet.DeviceUniqueSaveMacKeys[0].DataRo.ToArray());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user