Merge pull request #120 from Thealexbarney/utf8-strings

Use UTF-8 strings at more public API points.

There is still unnecessary UTF-16 to UTF-8 conversion internally. This PR is first focusing on the external interfaces.
This commit is contained in:
Alex Barney 2020-03-09 23:43:36 -07:00 committed by GitHub
commit d393c32e5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 1460 additions and 1187 deletions

View File

@ -152,7 +152,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
2,6061,,InvalidOffset,
2,6062,,InvalidSize,
2,6063,,NullArgument,
2,6063,,NullptrArgument,
2,6065,,InvalidMountName,
2,6066,,ExtensionSizeTooLarge,
2,6067,,ExtensionSizeInvalid,

1 Module,DescriptionStart,DescriptionEnd,Name,Summary
152 2,6359,,UnsupportedOperationInConcatFsQueryEntry,
153 2,6364,,UnsupportedOperationModifyRomFsFileSystem,
154 2,6366,,UnsupportedOperationRomFsFileSystemGetSpace,
155 2,6367,,UnsupportedOperationModifyRomFsFile,
156 2,6369,,UnsupportedOperationModifyReadOnlyFileSystem,
157 2,6371,,UnsupportedOperationReadOnlyFileSystemGetSpace,
158 2,6372,,UnsupportedOperationModifyReadOnlyFile,

View File

@ -62,9 +62,9 @@ namespace LibHac.Common
return new U8Span(_buffer.Slice(start, length));
}
public static implicit operator ReadOnlySpan<byte>(U8Span value) => value.Value;
public static implicit operator ReadOnlySpan<byte>(in U8Span value) => value.Value;
public static explicit operator string(U8Span value) => value.ToString();
public static explicit operator string(in U8Span value) => value.ToString();
public static explicit operator U8Span(string value) => new U8Span(value);
public override string ToString()

View File

@ -46,6 +46,18 @@ namespace LibHac.Common
return StringUtils.Utf8ZToString(_buffer);
}
public bool IsEmpty() => _buffer == null || _buffer.Length == 0;
/// <summary>
/// Checks if the <see cref="U8String"/> has no buffer.
/// </summary>
/// <returns><see langword="true"/> if the string has no buffer.
/// Otherwise, <see langword="false"/>.</returns>
public bool IsNull() => _buffer == null;
/// <summary>
/// Checks if the <see cref="U8String"/> has no buffer or begins with a null terminator.
/// </summary>
/// <returns><see langword="true"/> if the string has no buffer or begins with a null terminator.
/// Otherwise, <see langword="false"/>.</returns>
public bool IsEmpty() => _buffer == null || _buffer.Length < 1 || _buffer[0] == 0;
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using LibHac.FsSystem;
namespace LibHac.Fs.Accessors
{
@ -10,22 +8,10 @@ namespace LibHac.Fs.Accessors
public FileSystemAccessor Parent { get; }
private IFileSystem ParentFs { get; }
private string Path { get; }
public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent, IFileSystem parentFs, string path)
public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent)
{
Directory = baseDirectory;
Parent = parent;
ParentFs = parentFs;
Path = path;
}
public IEnumerable<DirectoryEntryEx> Read()
{
CheckIfDisposed();
return ParentFs.EnumerateEntries(Path, "*", SearchOptions.Default);
}
public Result Read(out long entriesRead, Span<DirectoryEntry> entryBuffer)

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LibHac.FsSystem;
using LibHac.Common;
namespace LibHac.Fs.Accessors
{
@ -28,44 +28,44 @@ namespace LibHac.Fs.Accessors
MountNameGenerator = nameGenerator;
}
public Result CreateDirectory(string path)
public Result CreateDirectory(U8Span path)
{
return FileSystem.CreateDirectory(path);
}
public Result CreateFile(string path, long size, CreateFileOptions options)
public Result CreateFile(U8Span path, long size, CreateFileOptions options)
{
return FileSystem.CreateFile(path, size, options);
}
public Result DeleteDirectory(string path)
public Result DeleteDirectory(U8Span path)
{
return FileSystem.DeleteDirectory(path);
}
public Result DeleteDirectoryRecursively(string path)
public Result DeleteDirectoryRecursively(U8Span path)
{
return FileSystem.DeleteDirectoryRecursively(path);
}
public Result CleanDirectoryRecursively(string path)
public Result CleanDirectoryRecursively(U8Span path)
{
return FileSystem.CleanDirectoryRecursively(path);
}
public Result DeleteFile(string path)
public Result DeleteFile(U8Span path)
{
return FileSystem.DeleteFile(path);
}
public Result OpenDirectory(out DirectoryAccessor directory, string path, OpenDirectoryMode mode)
public Result OpenDirectory(out DirectoryAccessor directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
Result rc = FileSystem.OpenDirectory(out IDirectory rawDirectory, path, mode);
if (rc.IsFailure()) return rc;
var accessor = new DirectoryAccessor(rawDirectory, this, FileSystem, path);
var accessor = new DirectoryAccessor(rawDirectory, this);
lock (_locker)
{
@ -76,7 +76,7 @@ namespace LibHac.Fs.Accessors
return Result.Success;
}
public Result OpenFile(out FileAccessor file, string path, OpenMode mode)
public Result OpenFile(out FileAccessor file, U8Span path, OpenMode mode)
{
file = default;
@ -94,42 +94,32 @@ namespace LibHac.Fs.Accessors
return Result.Success;
}
public Result RenameDirectory(string oldPath, string newPath)
public Result RenameDirectory(U8Span oldPath, U8Span newPath)
{
return FileSystem.RenameDirectory(oldPath, newPath);
}
public Result RenameFile(string oldPath, string newPath)
public Result RenameFile(U8Span oldPath, U8Span newPath)
{
return FileSystem.RenameFile(oldPath, newPath);
}
public bool DirectoryExists(string path)
{
return FileSystem.DirectoryExists(path);
}
public bool FileExists(string path)
{
return FileSystem.FileExists(path);
}
public Result GetEntryType(out DirectoryEntryType type, string path)
public Result GetEntryType(out DirectoryEntryType type, U8Span path)
{
return FileSystem.GetEntryType(out type, path);
}
public Result GetFreeSpaceSize(out long freeSpace, string path)
public Result GetFreeSpaceSize(out long freeSpace, U8Span path)
{
return FileSystem.GetFreeSpaceSize(out freeSpace, path);
}
public Result GetTotalSpaceSize(out long totalSpace, string path)
public Result GetTotalSpaceSize(out long totalSpace, U8Span path)
{
return FileSystem.GetTotalSpaceSize(out totalSpace, path);
}
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path)
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
{
return FileSystem.GetFileTimeStampRaw(out timeStamp, path);
}
@ -144,7 +134,7 @@ namespace LibHac.Fs.Accessors
return FileSystem.Commit();
}
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, string path, QueryId queryId)
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, U8Span path, QueryId queryId)
{
return FileSystem.QueryEntry(outBuffer, inBuffer, queryId, path);
}

View File

@ -1,20 +1,22 @@
namespace LibHac.Fs
using LibHac.Common;
namespace LibHac.Fs
{
public abstract class AttributeFileSystemBase : FileSystemBase, IAttributeFileSystem
{
protected abstract Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute);
protected abstract Result GetFileAttributesImpl(string path, out NxFileAttributes attributes);
protected abstract Result SetFileAttributesImpl(string path, NxFileAttributes attributes);
protected abstract Result GetFileSizeImpl(out long fileSize, string path);
protected abstract Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute);
protected abstract Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path);
protected abstract Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes);
protected abstract Result GetFileSizeImpl(out long fileSize, U8Span path);
public Result CreateDirectory(string path, NxFileAttributes archiveAttribute)
public Result CreateDirectory(U8Span path, NxFileAttributes archiveAttribute)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return CreateDirectoryImpl(path, archiveAttribute);
}
public Result GetFileAttributes(out NxFileAttributes attributes, string path)
public Result GetFileAttributes(out NxFileAttributes attributes, U8Span path)
{
if (IsDisposed)
{
@ -22,17 +24,17 @@
return ResultFs.PreconditionViolation.Log();
}
return GetFileAttributesImpl(path, out attributes);
return GetFileAttributesImpl(out attributes, path);
}
public Result SetFileAttributes(string path, NxFileAttributes attributes)
public Result SetFileAttributes(U8Span path, NxFileAttributes attributes)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return SetFileAttributesImpl(path, attributes);
}
public Result GetFileSize(out long fileSize, string path)
public Result GetFileSize(out long fileSize, U8Span path)
{
if (IsDisposed)
{

View File

@ -4,16 +4,16 @@ namespace LibHac.Fs
{
internal static class CommonMountNames
{
public static readonly U8String GameCardMountName = new U8String("@Gc");
public static readonly U8String SystemContentMountName = new U8String("@SystemContent");
public static readonly U8String UserContentMountName = new U8String("@UserContent");
public static readonly U8String SdCardContentMountName = new U8String("@SdCardContent");
public static readonly U8String CalibrationPartitionMountName = new U8String("@CalibFile");
public static readonly U8String SafePartitionMountName = new U8String("@Safe");
public static readonly U8String UserPartitionMountName = new U8String("@User");
public static readonly U8String SystemPartitionMountName = new U8String("@System");
public static readonly U8String SdCardMountName = new U8String("@Sdcard");
public static readonly U8String HostMountName = new U8String("@Host");
public static readonly U8String GameCardFileSystemMountName = new U8String("@Gc");
public static readonly U8String ContentStorageSystemMountName = new U8String("@SystemContent");
public static readonly U8String ContentStorageUserMountName = new U8String("@UserContent");
public static readonly U8String ContentStorageSdCardMountName = new U8String("@SdCardContent");
public static readonly U8String BisCalibrationFilePartitionMountName = new U8String("@CalibFile");
public static readonly U8String BisSafeModePartitionMountName = new U8String("@Safe");
public static readonly U8String BisUserPartitionMountName = new U8String("@User");
public static readonly U8String BisSystemPartitionMountName = new U8String("@System");
public static readonly U8String SdCardFileSystemMountName = new U8String("@Sdcard");
public static readonly U8String HostRootFileSystemMountName = new U8String("@Host");
public static readonly U8String RegisteredUpdatePartitionMountName = new U8String("@RegUpdate");
}
}

View File

@ -30,7 +30,7 @@ namespace LibHac.Fs
private Result Initialize(IFileSystem baseFileSystem, U8Span path, OpenMode mode)
{
Result rc = baseFileSystem.OpenFile(out IFile file, path.ToString(), mode);
Result rc = baseFileSystem.OpenFile(out IFile file, path, mode);
if (rc.IsFailure()) return rc;
SetFile(file);

View File

@ -1,5 +1,6 @@
using System;
using System.Threading;
using LibHac.Common;
namespace LibHac.Fs
{
@ -9,85 +10,86 @@ namespace LibHac.Fs
private int _disposedState;
protected bool IsDisposed => _disposedState != 0;
protected abstract Result CreateDirectoryImpl(string path);
protected abstract Result CreateFileImpl(string path, long size, CreateFileOptions options);
protected abstract Result DeleteDirectoryImpl(string path);
protected abstract Result DeleteDirectoryRecursivelyImpl(string path);
protected abstract Result CleanDirectoryRecursivelyImpl(string path);
protected abstract Result DeleteFileImpl(string path);
protected abstract Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode);
protected abstract Result OpenFileImpl(out IFile file, string path, OpenMode mode);
protected abstract Result RenameDirectoryImpl(string oldPath, string newPath);
protected abstract Result RenameFileImpl(string oldPath, string newPath);
protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path);
protected abstract Result CreateDirectoryImpl(U8Span path);
protected abstract Result CreateFileImpl(U8Span path, long size, CreateFileOptions options);
protected abstract Result DeleteDirectoryImpl(U8Span path);
protected abstract Result DeleteDirectoryRecursivelyImpl(U8Span path);
protected abstract Result CleanDirectoryRecursivelyImpl(U8Span path);
protected abstract Result DeleteFileImpl(U8Span path);
protected abstract Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode);
protected abstract Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode);
protected abstract Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath);
protected abstract Result RenameFileImpl(U8Span oldPath, U8Span newPath);
protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path);
protected abstract Result CommitImpl();
protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
freeSpace = default;
return ResultFs.NotImplemented.Log();
}
protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
totalSpace = default;
return ResultFs.NotImplemented.Log();
}
protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
timeStamp = default;
return ResultFs.NotImplemented.Log();
}
protected virtual Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected virtual Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
return ResultFs.NotImplemented.Log();
}
public Result CreateDirectory(string path)
public Result CreateDirectory(U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return CreateDirectoryImpl(path);
}
public Result CreateFile(string path, long size, CreateFileOptions options)
public Result CreateFile(U8Span path, long size, CreateFileOptions options)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return CreateFileImpl(path, size, options);
}
public Result DeleteDirectory(string path)
public Result DeleteDirectory(U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return DeleteDirectoryImpl(path);
}
public Result DeleteDirectoryRecursively(string path)
public Result DeleteDirectoryRecursively(U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return DeleteDirectoryRecursivelyImpl(path);
}
public Result CleanDirectoryRecursively(string path)
public Result CleanDirectoryRecursively(U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return CleanDirectoryRecursivelyImpl(path);
}
public Result DeleteFile(string path)
public Result DeleteFile(U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return DeleteFileImpl(path);
}
public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode)
public Result OpenDirectory(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
if (IsDisposed)
{
@ -95,10 +97,10 @@ namespace LibHac.Fs
return ResultFs.PreconditionViolation.Log();
}
if (path == null)
if (path.IsNull())
{
directory = default;
return ResultFs.NullArgument.Log();
return ResultFs.NullptrArgument.Log();
}
if ((mode & ~OpenDirectoryMode.All) != 0 || (mode & OpenDirectoryMode.All) == 0)
@ -110,7 +112,7 @@ namespace LibHac.Fs
return OpenDirectoryImpl(out directory, path, mode);
}
public Result OpenFile(out IFile file, string path, OpenMode mode)
public Result OpenFile(out IFile file, U8Span path, OpenMode mode)
{
if (IsDisposed)
{
@ -118,10 +120,10 @@ namespace LibHac.Fs
return ResultFs.PreconditionViolation.Log();
}
if (path == null)
if (path.IsNull())
{
file = default;
return ResultFs.NullArgument.Log();
return ResultFs.NullptrArgument.Log();
}
if ((mode & ~OpenMode.All) != 0 || (mode & OpenMode.ReadWrite) == 0)
@ -133,21 +135,21 @@ namespace LibHac.Fs
return OpenFileImpl(out file, path, mode);
}
public Result RenameDirectory(string oldPath, string newPath)
public Result RenameDirectory(U8Span oldPath, U8Span newPath)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return RenameDirectoryImpl(oldPath, newPath);
}
public Result RenameFile(string oldPath, string newPath)
public Result RenameFile(U8Span oldPath, U8Span newPath)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return RenameFileImpl(oldPath, newPath);
}
public Result GetEntryType(out DirectoryEntryType entryType, string path)
public Result GetEntryType(out DirectoryEntryType entryType, U8Span path)
{
if (IsDisposed)
{
@ -158,7 +160,7 @@ namespace LibHac.Fs
return GetEntryTypeImpl(out entryType, path);
}
public Result GetFreeSpaceSize(out long freeSpace, string path)
public Result GetFreeSpaceSize(out long freeSpace, U8Span path)
{
if (IsDisposed)
{
@ -169,7 +171,7 @@ namespace LibHac.Fs
return GetFreeSpaceSizeImpl(out freeSpace, path);
}
public Result GetTotalSpaceSize(out long totalSpace, string path)
public Result GetTotalSpaceSize(out long totalSpace, U8Span path)
{
if (IsDisposed)
{
@ -180,7 +182,7 @@ namespace LibHac.Fs
return GetTotalSpaceSizeImpl(out totalSpace, path);
}
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path)
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
{
if (IsDisposed)
{
@ -198,7 +200,7 @@ namespace LibHac.Fs
return CommitImpl();
}
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();

View File

@ -105,9 +105,9 @@ namespace LibHac.Fs
return IsEnabledAccessLog(AccessLogTarget.All);
}
internal bool IsEnabledFileSystemAccessorAccessLog(string mountName)
internal bool IsEnabledFileSystemAccessorAccessLog(U8Span mountName)
{
if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure())
if (MountTable.Find(mountName.ToString(), out FileSystemAccessor accessor).IsFailure())
{
return true;
}

View File

@ -1,147 +1,148 @@
using System;
using LibHac.Common;
using LibHac.Fs.Accessors;
namespace LibHac.Fs
{
public partial class FileSystemClient
{
public Result CreateDirectory(string path)
public Result CreateDirectory(U8Span path)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.CreateDirectory(subPath.ToString());
rc = fileSystem.CreateDirectory(subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.CreateDirectory(subPath.ToString());
rc = fileSystem.CreateDirectory(subPath);
}
return rc;
}
public Result CreateFile(string path, long size)
public Result CreateFile(U8Span path, long size)
{
return CreateFile(path, size, CreateFileOptions.None);
}
public Result CreateFile(string path, long size, CreateFileOptions options)
public Result CreateFile(U8Span path, long size, CreateFileOptions options)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.CreateFile(subPath.ToString(), size, options);
rc = fileSystem.CreateFile(subPath, size, options);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\", size: {size}");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\", size: {size}");
}
else
{
rc = fileSystem.CreateFile(subPath.ToString(), size, options);
rc = fileSystem.CreateFile(subPath, size, options);
}
return rc;
}
public Result DeleteDirectory(string path)
public Result DeleteDirectory(U8Span path)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.DeleteDirectory(subPath.ToString());
rc = fileSystem.DeleteDirectory(subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.DeleteDirectory(subPath.ToString());
rc = fileSystem.DeleteDirectory(subPath);
}
return rc;
}
public Result DeleteDirectoryRecursively(string path)
public Result DeleteDirectoryRecursively(U8Span path)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString());
rc = fileSystem.DeleteDirectoryRecursively(subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString());
rc = fileSystem.DeleteDirectoryRecursively(subPath);
}
return rc;
}
public Result CleanDirectoryRecursively(string path)
public Result CleanDirectoryRecursively(U8Span path)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.CleanDirectoryRecursively(subPath.ToString());
rc = fileSystem.CleanDirectoryRecursively(subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.CleanDirectoryRecursively(subPath.ToString());
rc = fileSystem.CleanDirectoryRecursively(subPath);
}
return rc;
}
public Result DeleteFile(string path)
public Result DeleteFile(U8Span path)
{
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.DeleteFile(subPath.ToString());
rc = fileSystem.DeleteFile(subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.DeleteFile(subPath.ToString());
rc = fileSystem.DeleteFile(subPath);
}
return rc;
}
public Result RenameDirectory(string oldPath, string newPath)
public Result RenameDirectory(U8Span oldPath, U8Span newPath)
{
Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan<char> oldSubPath);
Result rc = FindFileSystem(out FileSystemAccessor oldFileSystem, out U8Span oldSubPath, oldPath);
if (rc.IsFailure()) return rc;
rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan<char> newSubPath);
rc = FindFileSystem(out FileSystemAccessor newFileSystem, out U8Span newSubPath, newPath);
if (rc.IsFailure()) return rc;
if (oldFileSystem != newFileSystem)
@ -152,25 +153,25 @@ namespace LibHac.Fs
if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString());
rc = oldFileSystem.RenameDirectory(oldSubPath, newSubPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\"");
}
else
{
rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString());
rc = oldFileSystem.RenameDirectory(oldSubPath, newSubPath);
}
return rc;
}
public Result RenameFile(string oldPath, string newPath)
public Result RenameFile(U8Span oldPath, U8Span newPath)
{
Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan<char> oldSubPath);
Result rc = FindFileSystem(out FileSystemAccessor oldFileSystem, out U8Span oldSubPath, oldPath);
if (rc.IsFailure()) return rc;
rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan<char> newSubPath);
rc = FindFileSystem(out FileSystemAccessor newFileSystem, out U8Span newSubPath, newPath);
if (rc.IsFailure()) return rc;
if (oldFileSystem != newFileSystem)
@ -181,125 +182,125 @@ namespace LibHac.Fs
if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString());
rc = oldFileSystem.RenameFile(oldSubPath, newSubPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\"");
}
else
{
rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString());
rc = oldFileSystem.RenameFile(oldSubPath, newSubPath);
}
return rc;
}
public Result GetEntryType(out DirectoryEntryType type, string path)
public Result GetEntryType(out DirectoryEntryType type, U8Span path)
{
type = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.GetEntryType(out type, subPath.ToString());
rc = fileSystem.GetEntryType(out type, subPath);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\"");
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
}
else
{
rc = fileSystem.GetEntryType(out type, subPath.ToString());
rc = fileSystem.GetEntryType(out type, subPath);
}
return rc;
}
public Result OpenFile(out FileHandle handle, string path, OpenMode mode)
public Result OpenFile(out FileHandle handle, U8Span path, OpenMode mode)
{
handle = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode);
rc = fileSystem.OpenFile(out FileAccessor file, subPath, mode);
handle = new FileHandle(file);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}");
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}");
}
else
{
rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode);
rc = fileSystem.OpenFile(out FileAccessor file, subPath, mode);
handle = new FileHandle(file);
}
return rc;
}
public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode)
public Result OpenDirectory(out DirectoryHandle handle, U8Span path, OpenDirectoryMode mode)
{
handle = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
{
TimeSpan startTime = Time.GetCurrent();
rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode);
rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath, mode);
handle = new DirectoryHandle(dir);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}");
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}");
}
else
{
rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode);
rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath, mode);
handle = new DirectoryHandle(dir);
}
return rc;
}
public Result GetFreeSpaceSize(out long freeSpace, string path)
public Result GetFreeSpaceSize(out long freeSpace, U8Span path)
{
freeSpace = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString());
return fileSystem.GetFreeSpaceSize(out freeSpace, subPath);
}
public Result GetTotalSpaceSize(out long totalSpace, string path)
public Result GetTotalSpaceSize(out long totalSpace, U8Span path)
{
totalSpace = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString());
return fileSystem.GetTotalSpaceSize(out totalSpace, subPath);
}
public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path)
public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, U8Span path)
{
timeStamp = default;
Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath);
Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path);
if (rc.IsFailure()) return rc;
return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString());
return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath);
}
public Result Commit(string mountName)
public Result Commit(U8Span mountName)
{
Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem);
Result rc = MountTable.Find(mountName.ToString(), out FileSystemAccessor fileSystem);
if (rc.IsFailure()) return rc;
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
@ -308,7 +309,7 @@ namespace LibHac.Fs
rc = fileSystem.Commit();
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\"");
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
}
else
{

View File

@ -1,4 +1,6 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs.Accessors;
using LibHac.FsService;
@ -76,45 +78,65 @@ namespace LibHac.Fs
return Result.Success;
}
public void Unmount(string mountName)
public void Unmount(U8Span mountName)
{
Result rc;
string mountNameStr = mountName.ToString();
if (IsEnabledAccessLog() && IsEnabledFileSystemAccessorAccessLog(mountName))
{
TimeSpan startTime = Time.GetCurrent();
rc = MountTable.Unmount(mountName);
rc = MountTable.Unmount(mountNameStr);
TimeSpan endTime = Time.GetCurrent();
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\"");
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountNameStr}\"");
}
else
{
rc = MountTable.Unmount(mountName);
rc = MountTable.Unmount(mountNameStr);
}
rc.ThrowIfFailure();
}
internal Result FindFileSystem(ReadOnlySpan<char> path, out FileSystemAccessor fileSystem, out ReadOnlySpan<char> subPath)
internal Result FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, U8Span path)
{
fileSystem = default;
subPath = default;
Result rc = GetMountName(path, out ReadOnlySpan<char> mountName, out subPath);
if (path.IsNull())
return ResultFs.NullptrArgument.Log();
int hostMountNameLen = StringUtils.GetLength(CommonMountNames.HostRootFileSystemMountName);
if (StringUtils.Compare(path, CommonMountNames.HostRootFileSystemMountName, hostMountNameLen) == 0)
{
return ResultFs.NotMounted.Log();
}
Result rc = GetMountNameAndSubPath(out MountName mountName, out subPath, path);
if (rc.IsFailure()) return rc;
rc = MountTable.Find(mountName.ToString(), out fileSystem);
rc = MountTable.Find(StringUtils.Utf8ZToString(mountName.Name), out fileSystem);
if (rc.IsFailure()) return rc;
return Result.Success;
}
internal static Result GetMountName(ReadOnlySpan<char> path, out ReadOnlySpan<char> mountName, out ReadOnlySpan<char> subPath)
internal static Result GetMountNameAndSubPath(out MountName mountName, out U8Span subPath, U8Span path)
{
int mountLen = 0;
int maxMountLen = Math.Min(path.Length, PathTools.MountNameLengthMax);
if (PathUtility.IsWindowsDrive(path) || PathUtility.IsUnc(path))
{
StringUtils.Copy(mountName.Name, CommonMountNames.HostRootFileSystemMountName);
mountName.Name[PathTools.MountNameLengthMax] = StringTraits.NullTerminator;
subPath = path;
return Result.Success;
}
for (int i = 0; i <= maxMountLen; i++)
{
if (path[i] == PathTools.MountSeparator)
@ -124,7 +146,7 @@ namespace LibHac.Fs
}
}
if (mountLen == 0)
if (mountLen == 0 || mountLen > maxMountLen)
{
mountName = default;
subPath = default;
@ -132,18 +154,30 @@ namespace LibHac.Fs
return ResultFs.InvalidMountName.Log();
}
mountName = path.Slice(0, mountLen);
U8Span subPathTemp = path.Slice(mountLen + 1);
if (mountLen + 1 < path.Length)
{
subPath = path.Slice(mountLen + 1);
}
else
if (subPathTemp.Length == 0 || !PathTool.IsAnySeparator(subPathTemp[0]))
{
mountName = default;
subPath = default;
return ResultFs.InvalidPathFormat.Log();
}
path.Value.Slice(0, mountLen).CopyTo(mountName.Name);
mountName.Name[mountLen] = StringTraits.NullTerminator;
subPath = subPathTemp;
return Result.Success;
}
}
[StructLayout(LayoutKind.Sequential, Size = 16)]
[DebuggerDisplay("{ToString()}")]
internal struct MountName
{
public Span<byte> Name => SpanHelpers.AsByteSpan(ref this);
public override string ToString() => new U8Span(Name).ToString();
}
}

View File

@ -12,7 +12,7 @@ namespace LibHac.Fs
public static Result CopyDirectory(this FileSystemClient fs, string sourcePath, string destPath,
CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null)
{
Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All);
Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All);
if (rc.IsFailure()) return rc;
using (sourceHandle)
@ -46,12 +46,12 @@ namespace LibHac.Fs
public static Result CopyFile(this FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null)
{
Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read);
Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath.ToU8Span(), OpenMode.Read);
if (rc.IsFailure()) return rc;
using (sourceHandle)
{
rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend);
rc = fs.OpenFile(out FileHandle destHandle, destPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend);
if (rc.IsFailure()) return rc;
using (destHandle)
@ -111,7 +111,7 @@ namespace LibHac.Fs
bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive);
bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories);
fs.OpenDirectory(out DirectoryHandle sourceHandle, path, OpenDirectoryMode.All).ThrowIfFailure();
fs.OpenDirectory(out DirectoryHandle sourceHandle, path.ToU8Span(), OpenDirectoryMode.All).ThrowIfFailure();
using (sourceHandle)
{
@ -144,14 +144,14 @@ namespace LibHac.Fs
public static bool DirectoryExists(this FileSystemClient fs, string path)
{
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span());
return (rc.IsSuccess() && type == DirectoryEntryType.Directory);
}
public static bool FileExists(this FileSystemClient fs, string path)
{
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span());
return (rc.IsSuccess() && type == DirectoryEntryType.File);
}
@ -189,25 +189,30 @@ namespace LibHac.Fs
{
string subPath = path.Substring(0, i);
fs.CreateDirectory(subPath);
fs.CreateDirectory(subPath.ToU8Span());
}
}
fs.CreateDirectory(path);
fs.CreateDirectory(path.ToU8Span());
}
public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size)
public static Result CreateOrOverwriteFile(this FileSystemClient fs, string path, long size)
{
fs.CreateOrOverwriteFile(path, size, CreateFileOptions.None);
return fs.CreateOrOverwriteFile(path, size, CreateFileOptions.None);
}
public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size, CreateFileOptions options)
public static Result CreateOrOverwriteFile(this FileSystemClient fs, string path, long size, CreateFileOptions options)
{
path = PathTools.Normalize(path);
var u8Path = path.ToU8Span();
if (fs.FileExists(path)) fs.DeleteFile(path);
if (fs.FileExists(path))
{
Result rc = fs.DeleteFile(u8Path);
if (rc.IsFailure()) return rc;
}
fs.CreateFile(path, size, CreateFileOptions.None);
return fs.CreateFile(u8Path, size, CreateFileOptions.None);
}
internal static bool IsEnabledFileSystemAccessorAccessLog(this FileSystemClient fs, string mountName)

View File

@ -1,10 +1,12 @@
namespace LibHac.Fs
using LibHac.Common;
namespace LibHac.Fs
{
public interface IAttributeFileSystem : IFileSystem
{
Result CreateDirectory(string path, NxFileAttributes archiveAttribute);
Result GetFileAttributes(out NxFileAttributes attributes, string path);
Result SetFileAttributes(string path, NxFileAttributes attributes);
Result GetFileSize(out long fileSize, string path);
Result CreateDirectory(U8Span path, NxFileAttributes archiveAttribute);
Result GetFileAttributes(out NxFileAttributes attributes, U8Span path);
Result SetFileAttributes(U8Span path, NxFileAttributes attributes);
Result GetFileSize(out long fileSize, U8Span path);
}
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.FsSystem;
namespace LibHac.Fs
@ -23,7 +24,7 @@ namespace LibHac.Fs
/// Specified path already exists as either a file or directory: <see cref="ResultFs.PathAlreadyExists"/>
/// Insufficient free space to create the file: <see cref="ResultFs.InsufficientFreeSpace"/>
/// </remarks>
Result CreateFile(string path, long size, CreateFileOptions options);
Result CreateFile(U8Span path, long size, CreateFileOptions options);
/// <summary>
/// Deletes the specified file.
@ -35,7 +36,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist or is a directory: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result DeleteFile(string path);
Result DeleteFile(U8Span path);
/// <summary>
/// Creates all directories and subdirectories in the specified path unless they already exist.
@ -49,7 +50,7 @@ namespace LibHac.Fs
/// Specified path already exists as either a file or directory: <see cref="ResultFs.PathAlreadyExists"/>
/// Insufficient free space to create the directory: <see cref="ResultFs.InsufficientFreeSpace"/>
/// </remarks>
Result CreateDirectory(string path);
Result CreateDirectory(U8Span path);
/// <summary>
/// Deletes the specified directory.
@ -62,7 +63,7 @@ namespace LibHac.Fs
/// The specified path does not exist or is a file: <see cref="ResultFs.PathNotFound"/>
/// The specified directory is not empty: <see cref="ResultFs.DirectoryNotEmpty"/>
/// </remarks>
Result DeleteDirectory(string path);
Result DeleteDirectory(U8Span path);
/// <summary>
/// Deletes the specified directory and any subdirectories and files in the directory.
@ -74,7 +75,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist or is a file: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result DeleteDirectoryRecursively(string path);
Result DeleteDirectoryRecursively(U8Span path);
/// <summary>
/// Deletes any subdirectories and files in the specified directory.
@ -86,7 +87,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist or is a file: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result CleanDirectoryRecursively(string path);
Result CleanDirectoryRecursively(U8Span path);
/// <summary>
/// Renames or moves a file to a new location.
@ -102,7 +103,7 @@ namespace LibHac.Fs
/// <paramref name="newPath"/>'s parent directory does not exist: <see cref="ResultFs.PathNotFound"/>
/// <paramref name="newPath"/> already exists as either a file or directory: <see cref="ResultFs.PathAlreadyExists"/>
/// </remarks>
Result RenameFile(string oldPath, string newPath);
Result RenameFile(U8Span oldPath, U8Span newPath);
/// <summary>
/// Renames or moves a directory to a new location.
@ -119,7 +120,7 @@ namespace LibHac.Fs
/// <paramref name="newPath"/> already exists as either a file or directory: <see cref="ResultFs.PathAlreadyExists"/>
/// Either <paramref name="oldPath"/> or <paramref name="newPath"/> is a subpath of the other: <see cref="ResultFs.DestinationIsSubPathOfSource"/>
/// </remarks>
Result RenameDirectory(string oldPath, string newPath);
Result RenameDirectory(U8Span oldPath, U8Span newPath);
/// <summary>
/// Determines whether the specified path is a file or directory, or does not exist.
@ -127,7 +128,7 @@ namespace LibHac.Fs
/// <param name="entryType">If the operation returns successfully, the <see cref="DirectoryEntryType"/> of the file.</param>
/// <param name="path">The full path to check.</param>
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
Result GetEntryType(out DirectoryEntryType entryType, string path);
Result GetEntryType(out DirectoryEntryType entryType, U8Span path);
/// <summary>
/// Gets the amount of available free space on a drive, in bytes.
@ -135,7 +136,7 @@ namespace LibHac.Fs
/// <param name="freeSpace">If the operation returns successfully, the amount of free space available on the drive, in bytes.</param>
/// <param name="path">The path of the drive to query. Unused in almost all cases.</param>
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
Result GetFreeSpaceSize(out long freeSpace, string path);
Result GetFreeSpaceSize(out long freeSpace, U8Span path);
/// <summary>
/// Gets the total size of storage space on a drive, in bytes.
@ -143,7 +144,7 @@ namespace LibHac.Fs
/// <param name="totalSpace">If the operation returns successfully, the total size of the drive, in bytes.</param>
/// <param name="path">The path of the drive to query. Unused in almost all cases.</param>
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
Result GetTotalSpaceSize(out long totalSpace, string path);
Result GetTotalSpaceSize(out long totalSpace, U8Span path);
/// <summary>
/// Opens an <see cref="IFile"/> instance for the specified path.
@ -158,7 +159,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist or is a directory: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result OpenFile(out IFile file, string path, OpenMode mode);
Result OpenFile(out IFile file, U8Span path, OpenMode mode);
/// <summary>
/// Creates an <see cref="IDirectory"/> instance for enumerating the specified directory.
@ -173,7 +174,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist or is a file: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode);
Result OpenDirectory(out IDirectory directory, U8Span path, OpenDirectoryMode mode);
/// <summary>
/// Commits any changes to a transactional file system.
@ -194,7 +195,7 @@ namespace LibHac.Fs
///
/// The specified path does not exist: <see cref="ResultFs.PathNotFound"/>
/// </remarks>
Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path);
Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path);
/// <summary>
/// Performs a query on the specified file.
@ -208,7 +209,7 @@ namespace LibHac.Fs
/// <param name="queryId">The type of query to perform.</param>
/// <param name="path">The full path of the file to query.</param>
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path);
Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path);
}
/// <summary>

View File

@ -18,59 +18,55 @@ namespace LibHac.Fs
FsTable = new FileTable();
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
return FsTable.AddDirectory(new U8Span(path));
}
protected override Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute)
protected override Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute)
{
var u8Path = new U8Span(path);
Result rc = FsTable.AddDirectory(u8Path);
Result rc = FsTable.AddDirectory(path);
if (rc.IsFailure()) return rc;
rc = FsTable.GetDirectory(u8Path, out DirectoryNode dir);
rc = FsTable.GetDirectory(path, out DirectoryNode dir);
if (rc.IsFailure()) return rc;
dir.Attributes = archiveAttribute;
return Result.Success;
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
var u8Path = new U8Span(path);
Result rc = FsTable.AddFile(u8Path);
Result rc = FsTable.AddFile(path);
if (rc.IsFailure()) return rc;
rc = FsTable.GetFile(u8Path, out FileNode file);
rc = FsTable.GetFile(path, out FileNode file);
if (rc.IsFailure()) return rc;
return file.File.SetSize(size);
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
return FsTable.DeleteDirectory(new U8Span(path), false);
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
return FsTable.DeleteDirectory(new U8Span(path), true);
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
return FsTable.CleanDirectory(new U8Span(path));
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
return FsTable.DeleteFile(new U8Span(path));
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
@ -81,12 +77,11 @@ namespace LibHac.Fs
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
var u8Path = new U8Span(path);
Result rc = FsTable.GetFile(u8Path, out FileNode fileNode);
Result rc = FsTable.GetFile(path, out FileNode fileNode);
if (rc.IsFailure()) return rc;
file = new MemoryFile(mode, fileNode.File);
@ -94,27 +89,25 @@ namespace LibHac.Fs
return Result.Success;
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
return FsTable.RenameDirectory(new U8Span(oldPath), new U8Span(newPath));
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
return FsTable.RenameFile(new U8Span(oldPath), new U8Span(newPath));
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
var u8Path = new U8Span(path);
if (FsTable.GetFile(u8Path, out _).IsSuccess())
if (FsTable.GetFile(path, out _).IsSuccess())
{
entryType = DirectoryEntryType.File;
return Result.Success;
}
if (FsTable.GetDirectory(u8Path, out _).IsSuccess())
if (FsTable.GetDirectory(path, out _).IsSuccess())
{
entryType = DirectoryEntryType.Directory;
return Result.Success;
@ -129,17 +122,15 @@ namespace LibHac.Fs
return Result.Success;
}
protected override Result GetFileAttributesImpl(string path, out NxFileAttributes attributes)
protected override Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path)
{
var u8Path = new U8Span(path);
if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess())
if (FsTable.GetFile(path, out FileNode file).IsSuccess())
{
attributes = file.Attributes;
return Result.Success;
}
if (FsTable.GetDirectory(u8Path, out DirectoryNode dir).IsSuccess())
if (FsTable.GetDirectory(path, out DirectoryNode dir).IsSuccess())
{
attributes = dir.Attributes;
return Result.Success;
@ -149,17 +140,15 @@ namespace LibHac.Fs
return ResultFs.PathNotFound.Log();
}
protected override Result SetFileAttributesImpl(string path, NxFileAttributes attributes)
protected override Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes)
{
var u8Path = new U8Span(path);
if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess())
if (FsTable.GetFile(path, out FileNode file).IsSuccess())
{
file.Attributes = attributes;
return Result.Success;
}
if (FsTable.GetDirectory(u8Path, out DirectoryNode dir).IsSuccess())
if (FsTable.GetDirectory(path, out DirectoryNode dir).IsSuccess())
{
dir.Attributes = attributes;
return Result.Success;
@ -168,11 +157,9 @@ namespace LibHac.Fs
return ResultFs.PathNotFound.Log();
}
protected override Result GetFileSizeImpl(out long fileSize, string path)
protected override Result GetFileSizeImpl(out long fileSize, U8Span path)
{
var u8Path = new U8Span(path);
if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess())
if (FsTable.GetFile(path, out FileNode file).IsSuccess())
{
return file.File.GetSize(out fileSize);
}
@ -646,7 +633,12 @@ namespace LibHac.Fs
while (parser.MoveNext())
{
if (!TryFindChildDirectory(new U8Span(parser.GetCurrent()), current, out DirectoryNode child))
var currentDir = new U8Span(parser.GetCurrent());
// End if we've hit a trailing separator
if (currentDir.IsEmpty() && parser.IsFinished()) break;
if (!TryFindChildDirectory(currentDir, current, out DirectoryNode child))
{
directory = default;
return ResultFs.PathNotFound.Log();

View File

@ -6,7 +6,7 @@ namespace LibHac.Fs
{
public static Result CheckMountName(U8Span name)
{
if (name.IsNull()) return ResultFs.NullArgument.Log();
if (name.IsNull()) return ResultFs.NullptrArgument.Log();
if (name.Length > 0 && name[0] == '@') return ResultFs.InvalidMountName.Log();
if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log();
@ -16,7 +16,7 @@ namespace LibHac.Fs
public static Result CheckMountNameAcceptingReservedMountName(U8Span name)
{
if (name.IsNull()) return ResultFs.NullArgument.Log();
if (name.IsNull()) return ResultFs.NullptrArgument.Log();
if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log();

View File

@ -301,7 +301,7 @@ namespace LibHac.Fs
/// <summary>Error code: 2002-6062; Inner value: 0x2f5c02</summary>
public static Result.Base InvalidSize => new Result.Base(ModuleFs, 6062);
/// <summary>Error code: 2002-6063; Inner value: 0x2f5e02</summary>
public static Result.Base NullArgument => new Result.Base(ModuleFs, 6063);
public static Result.Base NullptrArgument => new Result.Base(ModuleFs, 6063);
/// <summary>Error code: 2002-6065; Inner value: 0x2f6202</summary>
public static Result.Base InvalidMountName => new Result.Base(ModuleFs, 6065);
/// <summary>Error code: 2002-6066; Inner value: 0x2f6402</summary>

View File

@ -31,11 +31,11 @@ namespace LibHac.Fs.Shim
switch (storageId)
{
case ContentStorageId.System:
return CommonMountNames.SystemContentMountName;
return CommonMountNames.ContentStorageSystemMountName;
case ContentStorageId.User:
return CommonMountNames.UserContentMountName;
return CommonMountNames.ContentStorageUserMountName;
case ContentStorageId.SdCard:
return CommonMountNames.SdCardContentMountName;
return CommonMountNames.ContentStorageSdCardMountName;
default:
throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null);
}

View File

@ -70,7 +70,7 @@ namespace LibHac.Fs.Shim
{
char letter = GetGameCardMountNameSuffix(PartitionId);
string mountName = $"{CommonMountNames.GameCardMountName}{letter}{Handle.Value:x8}";
string mountName = $"{CommonMountNames.GameCardFileSystemMountName}{letter}{Handle.Value:x8}";
new U8Span(mountName).Value.CopyTo(nameBuffer);
return Result.Success;

View File

@ -23,7 +23,7 @@ namespace LibHac.FsService.Creators
fileSystem = default;
if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log();
if (rootPath == null) return ResultFs.NullArgument.Log();
if (rootPath == null) return ResultFs.NullptrArgument.Log();
if (Config.TryGetFileSystem(out fileSystem, partitionId))
{

View File

@ -14,7 +14,7 @@ namespace LibHac.FsService.Creators
public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId)
{
if (fileSystem == null) return ResultFs.NullArgument.Log();
if (fileSystem == null) return ResultFs.NullptrArgument.Log();
if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log();
PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem;
@ -24,7 +24,7 @@ namespace LibHac.FsService.Creators
public Result SetPath(string path, BisPartitionId partitionId)
{
if (path == null) return ResultFs.NullArgument.Log();
if (path == null) return ResultFs.NullptrArgument.Log();
if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log();
PartitionPaths[GetArrayIndex(partitionId)] = path;

View File

@ -1,9 +1,10 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsService.Creators
{
public interface ISubDirectoryFileSystemCreator
{
Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path);
Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path);
}
}

View File

@ -27,7 +27,7 @@ namespace LibHac.FsService.Creators
fileSystem = default;
extraDataAccessor = default;
string saveDataPath = $"/{saveDataId:x16}";
var saveDataPath = $"/{saveDataId:x16}".ToU8String();
Result rc = sourceFileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath);
if (rc.IsFailure())
@ -40,7 +40,7 @@ namespace LibHac.FsService.Creators
case DirectoryEntryType.Directory:
if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log();
rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subDirFs, sourceFileSystem, saveDataPath.ToU8String());
rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subDirFs, sourceFileSystem, saveDataPath);
if (rc.IsFailure()) return rc;
bool isPersistentSaveData = type != SaveDataType.Temporary;

View File

@ -6,7 +6,7 @@ namespace LibHac.FsService.Creators
{
public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator
{
public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path)
public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path)
{
subDirFileSystem = default;

View File

@ -1113,7 +1113,7 @@ namespace LibHac.FsService
string.Empty, false);
if (rc.IsFailure()) return rc;
rc = saveDirFs.CleanDirectoryRecursively("/");
rc = saveDirFs.CleanDirectoryRecursively("/".ToU8Span());
if (rc.IsFailure()) return rc;
SaveDataIndexerReader reader = default;

View File

@ -65,7 +65,7 @@ namespace LibHac.FsService
{
fileSystem = default;
string contentDirPath = default;
U8String contentDirPath = default;
IFileSystem baseFileSystem = default;
bool isEncrypted = false;
Result rc;
@ -74,15 +74,15 @@ namespace LibHac.FsService
{
case ContentStorageId.System:
rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System);
contentDirPath = $"/{ContentDirectoryName}";
contentDirPath = $"/{ContentDirectoryName}".ToU8String();
break;
case ContentStorageId.User:
rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User);
contentDirPath = $"/{ContentDirectoryName}";
contentDirPath = $"/{ContentDirectoryName}".ToU8String();
break;
case ContentStorageId.SdCard:
rc = OpenSdCardFileSystem(out baseFileSystem);
contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}";
contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}".ToU8String();
isEncrypted = true;
break;
default:
@ -92,7 +92,7 @@ namespace LibHac.FsService
if (rc.IsFailure()) return rc;
baseFileSystem.EnsureDirectoryExists(contentDirPath);
baseFileSystem.EnsureDirectoryExists(contentDirPath.ToString());
rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem,
baseFileSystem, contentDirPath);
@ -199,7 +199,7 @@ namespace LibHac.FsService
string saveDataPath = $"/{saveDataId:x16}";
rc = fileSystem.GetEntryType(out _, saveDataPath);
rc = fileSystem.GetEntryType(out _, saveDataPath.ToU8Span());
if (rc.IsFailure())
{
@ -337,7 +337,7 @@ namespace LibHac.FsService
string metaFilePath = $"/{(int)type:x8}.meta";
return metaDirFs.OpenFile(out file, metaFilePath, OpenMode.ReadWrite);
return metaDirFs.OpenFile(out file, metaFilePath.ToU8Span(), OpenMode.ReadWrite);
}
public Result DeleteSaveDataMetaFiles(ulong saveDataId, SaveDataSpaceId spaceId)
@ -348,7 +348,7 @@ namespace LibHac.FsService
{
if (rc.IsFailure()) return rc;
rc = metaDirFs.DeleteDirectoryRecursively($"/{saveDataId:x16}");
rc = metaDirFs.DeleteDirectoryRecursively($"/{saveDataId:x16}".ToU8Span());
if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc))
return rc;
@ -369,7 +369,7 @@ namespace LibHac.FsService
if (size < 0) return ResultFs.OutOfRange.Log();
return metaDirFs.CreateFile(metaFilePath, size, CreateFileOptions.None);
return metaDirFs.CreateFile(metaFilePath.ToU8Span(), size, CreateFileOptions.None);
}
public Result CreateSaveDataFileSystem(ulong saveDataId, ref SaveDataAttribute attribute,
@ -391,7 +391,7 @@ namespace LibHac.FsService
{
if (rc.IsFailure()) return rc;
string saveDataPath = GetSaveDataIdPath(saveDataId);
var saveDataPath = GetSaveDataIdPath(saveDataId).ToU8Span();
rc = fileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath);
if (rc.IsFailure()) return rc;

View File

@ -18,7 +18,7 @@ namespace LibHac.FsService
private const long LastIdFileSize = 8;
private FileSystemClient FsClient { get; }
private string MountName { get; }
private U8String MountName { get; }
private ulong SaveDataId { get; }
private SaveDataSpaceId SpaceId { get; }
private KeyValueDatabase<SaveDataAttribute> KvDatabase { get; set; }
@ -29,10 +29,10 @@ namespace LibHac.FsService
private int Version { get; set; }
private List<SaveDataInfoReader> OpenedReaders { get; } = new List<SaveDataInfoReader>();
public SaveDataIndexer(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, ulong saveDataId)
public SaveDataIndexer(FileSystemClient fsClient, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId)
{
FsClient = fsClient;
MountName = mountName;
MountName = mountName.ToU8String();
SaveDataId = saveDataId;
SpaceId = spaceId;
Version = 1;
@ -77,7 +77,7 @@ namespace LibHac.FsService
string idFilePath = $"{MountName}:/{LastIdFileName}";
rc = FsClient.OpenFile(out FileHandle handle, idFilePath, OpenMode.Write);
rc = FsClient.OpenFile(out FileHandle handle, idFilePath.ToU8Span(), OpenMode.Write);
if (rc.IsFailure()) return rc;
bool fileAlreadyClosed = false;
@ -423,7 +423,7 @@ namespace LibHac.FsService
string dbDirectory = $"{MountName}:/";
rc = FsClient.GetEntryType(out DirectoryEntryType entryType, dbDirectory);
rc = FsClient.GetEntryType(out DirectoryEntryType entryType, dbDirectory.ToU8Span());
if (rc.IsFailure()) return rc;
if (entryType == DirectoryEntryType.File)
@ -431,7 +431,7 @@ namespace LibHac.FsService
string dbArchiveFile = $"{dbDirectory}imkvdb.arc";
KvDatabase = new KeyValueDatabase<SaveDataAttribute>(FsClient, dbArchiveFile);
KvDatabase = new KeyValueDatabase<SaveDataAttribute>(FsClient, dbArchiveFile.ToU8Span());
IsInitialized = true;
return Result.Success;
@ -466,7 +466,7 @@ namespace LibHac.FsService
if (rc.IsFailure()) return rc;
bool createdNewFile = false;
string idFilePath = $"{MountName}:/{LastIdFileName}";
var idFilePath = $"{MountName}:/{LastIdFileName}".ToU8String();
rc = FsClient.OpenFile(out FileHandle handle, idFilePath, OpenMode.Read);
@ -572,10 +572,10 @@ namespace LibHac.FsService
private ref struct Mounter
{
private FileSystemClient FsClient { get; set; }
private string MountName { get; set; }
private U8String MountName { get; set; }
private bool IsMounted { get; set; }
public Result Initialize(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId,
public Result Initialize(FileSystemClient fsClient, U8String mountName, SaveDataSpaceId spaceId,
ulong saveDataId)
{
FsClient = fsClient;
@ -583,7 +583,7 @@ namespace LibHac.FsService
FsClient.DisableAutoSaveDataCreation();
Result rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId);
Result rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId);
if (rc.IsFailure())
{
@ -592,7 +592,7 @@ namespace LibHac.FsService
rc = FsClient.CreateSystemSaveData(spaceId, saveDataId, TitleId.Zero, 0xC0000, 0xC0000, 0);
if (rc.IsFailure()) return rc;
rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId);
rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId);
if (rc.IsFailure()) return rc;
}
else
@ -608,7 +608,7 @@ namespace LibHac.FsService
rc = FsClient.CreateSystemSaveData(spaceId, saveDataId, TitleId.Zero, 0xC0000, 0xC0000, 0);
if (rc.IsFailure()) return rc;
rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId);
rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId);
if (rc.IsFailure()) return rc;
}
}

View File

@ -1,4 +1,5 @@
using System.Threading;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsService
@ -30,7 +31,7 @@ namespace LibHac.FsService
if (!_bisIndexer.IsInitialized)
{
_bisIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDb", SaveDataSpaceId.System, SaveDataId);
_bisIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDb".ToU8Span(), SaveDataSpaceId.System, SaveDataId);
}
reader = new SaveDataIndexerReader(_bisIndexer.Indexer, _bisIndexer.Locker);
@ -44,7 +45,7 @@ namespace LibHac.FsService
if (!_sdCardIndexer.IsInitialized)
{
_sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd", SaveDataSpaceId.SdSystem, SaveDataId);
_sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd".ToU8Span(), SaveDataSpaceId.SdSystem, SaveDataId);
}
reader = new SaveDataIndexerReader(_sdCardIndexer.Indexer, _sdCardIndexer.Locker);
@ -66,7 +67,7 @@ namespace LibHac.FsService
if (!_safeIndexer.IsInitialized)
{
_safeIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbPr", SaveDataSpaceId.ProperSystem, SaveDataId);
_safeIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbPr".ToU8Span(), SaveDataSpaceId.ProperSystem, SaveDataId);
}
reader = new SaveDataIndexerReader(_safeIndexer.Indexer, _safeIndexer.Locker);
@ -77,7 +78,7 @@ namespace LibHac.FsService
if (!_properSystemIndexer.IsInitialized)
{
_properSystemIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSf", SaveDataSpaceId.SafeMode, SaveDataId);
_properSystemIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSf".ToU8Span(), SaveDataSpaceId.SafeMode, SaveDataId);
}
reader = new SaveDataIndexerReader(_properSystemIndexer.Indexer, _properSystemIndexer.Locker);

View File

@ -13,9 +13,9 @@ namespace LibHac.FsService
if (!createPathIfMissing)
{
if (path == null) return ResultFs.NullArgument.Log();
if (path == null) return ResultFs.NullptrArgument.Log();
Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path);
Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path.ToU8Span());
if (rc.IsFailure() || entryType != DirectoryEntryType.Directory)
{
@ -32,9 +32,9 @@ namespace LibHac.FsService
{
subFileSystem = default;
if (path == null) return ResultFs.NullArgument.Log();
if (path == null) return ResultFs.NullptrArgument.Log();
Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory);
Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path.ToU8Span(), OpenDirectoryMode.Directory);
if (rc.IsFailure()) return rc;
rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem fs, baseFileSystem, path.ToU8String());

View File

@ -6,13 +6,13 @@ namespace LibHac.FsSystem
{
public class AesXtsDirectory : IDirectory
{
private string Path { get; }
private U8String Path { get; }
private OpenDirectoryMode Mode { get; }
private IFileSystem BaseFileSystem { get; }
private IDirectory BaseDirectory { get; }
public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, string path, OpenDirectoryMode mode)
public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, U8String path, OpenDirectoryMode mode)
{
BaseFileSystem = baseFs;
BaseDirectory = baseDir;
@ -38,7 +38,7 @@ namespace LibHac.FsSystem
else
{
string entryName = Util.GetUtf8StringNullTerminated(entry.Name);
entry.Size = GetAesXtsFileSize(PathTools.Combine(Path, entryName));
entry.Size = GetAesXtsFileSize(PathTools.Combine(Path.ToString(), entryName).ToU8Span());
}
}
}
@ -56,7 +56,7 @@ namespace LibHac.FsSystem
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private long GetAesXtsFileSize(string path)
private long GetAesXtsFileSize(U8Span path)
{
const long magicOffset = 0x20;
const long fileSizeOffset = 0x48;

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
@ -6,7 +7,7 @@ namespace LibHac.FsSystem
public class AesXtsFile : FileBase
{
private IFile BaseFile { get; }
private string Path { get; }
private U8String Path { get; }
private byte[] KekSeed { get; }
private byte[] VerificationKey { get; }
private int BlockSize { get; }
@ -17,7 +18,7 @@ namespace LibHac.FsSystem
internal const int HeaderLength = 0x4000;
public AesXtsFile(OpenMode mode, IFile baseFile, string path, ReadOnlySpan<byte> kekSeed, ReadOnlySpan<byte> verificationKey, int blockSize)
public AesXtsFile(OpenMode mode, IFile baseFile, U8String path, ReadOnlySpan<byte> kekSeed, ReadOnlySpan<byte> verificationKey, int blockSize)
{
Mode = mode;
BaseFile = baseFile;
@ -30,7 +31,7 @@ namespace LibHac.FsSystem
baseFile.GetSize(out long fileSize).ThrowIfFailure();
if (!Header.TryDecryptHeader(Path, KekSeed, VerificationKey))
if (!Header.TryDecryptHeader(Path.ToString(), KekSeed, VerificationKey))
{
ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys.Value, "NAX0 key derivation failed.");
}

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
@ -28,12 +29,12 @@ namespace LibHac.FsSystem
BlockSize = blockSize;
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
return BaseFileSystem.CreateDirectory(path);
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
return CreateFile(path, size, options, new byte[0x20]);
}
@ -46,14 +47,14 @@ namespace LibHac.FsSystem
/// <param name="options">Flags to control how the file is created.
/// Should usually be <see cref="CreateFileOptions.None"/></param>
/// <param name="key">The 256-bit key containing a 128-bit data key followed by a 128-bit tweak key.</param>
public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key)
public Result CreateFile(U8Span path, long size, CreateFileOptions options, byte[] key)
{
long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10);
Result rc = BaseFileSystem.CreateFile(path, containerSize, options);
if (rc.IsFailure()) return rc;
var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey);
var header = new AesXtsFileHeader(key, size, path.ToString(), KekSource, ValidationKey);
rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write);
if (rc.IsFailure()) return rc;
@ -67,57 +68,52 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
return BaseFileSystem.DeleteDirectory(path);
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
return BaseFileSystem.DeleteDirectoryRecursively(path);
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
return BaseFileSystem.CleanDirectoryRecursively(path);
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
return BaseFileSystem.DeleteFile(path);
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
path = PathTools.Normalize(path);
Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode);
if (rc.IsFailure()) return rc;
directory = new AesXtsDirectory(BaseFileSystem, baseDir, path, mode);
directory = new AesXtsDirectory(BaseFileSystem, baseDir, path.ToU8String(), mode);
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
path = PathTools.Normalize(path);
Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read);
if (rc.IsFailure()) return rc;
var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize);
var xtsFile = new AesXtsFile(mode, baseFile, path.ToU8String(), KekSource, ValidationKey, BlockSize);
file = xtsFile;
return Result.Success;
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
// todo: Return proper result codes
// Official code procedure:
@ -133,11 +129,11 @@ namespace LibHac.FsSystem
try
{
RenameDirectoryImpl(oldPath, newPath, false);
RenameDirectoryImpl(oldPath.ToString(), newPath.ToString(), false);
}
catch (Exception)
{
RenameDirectoryImpl(oldPath, newPath, true);
RenameDirectoryImpl(oldPath.ToString(), newPath.ToString(), true);
BaseFileSystem.RenameDirectory(oldPath, newPath);
throw;
@ -176,26 +172,23 @@ namespace LibHac.FsSystem
}
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
// todo: Return proper result codes
AesXtsFileHeader header = ReadXtsHeader(oldPath, oldPath);
AesXtsFileHeader header = ReadXtsHeader(oldPath.ToString(), oldPath.ToString());
Result rc = BaseFileSystem.RenameFile(oldPath, newPath);
if (rc.IsFailure()) return rc;
try
{
WriteXtsHeader(header, newPath, newPath);
WriteXtsHeader(header, newPath.ToString(), newPath.ToString());
}
catch (Exception)
{
BaseFileSystem.RenameFile(newPath, oldPath);
WriteXtsHeader(header, oldPath, oldPath);
WriteXtsHeader(header, oldPath.ToString(), oldPath.ToString());
throw;
}
@ -203,22 +196,22 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
return BaseFileSystem.GetEntryType(out entryType, path);
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path);
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path);
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path);
}
@ -228,7 +221,8 @@ namespace LibHac.FsSystem
return BaseFileSystem.Commit();
}
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, path);
}
@ -250,7 +244,7 @@ namespace LibHac.FsSystem
header = null;
Result rc = BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.Read);
Result rc = BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.Read);
if (rc.IsFailure()) return false;
using (file)
@ -268,7 +262,7 @@ namespace LibHac.FsSystem
header.EncryptHeader(keyPath, KekSource, ValidationKey);
BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.ReadWrite);
BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.ReadWrite);
using (file)
{

View File

@ -7,20 +7,35 @@ namespace LibHac.FsSystem
{
public class ConcatenationDirectory : IDirectory
{
private string Path { get; }
private OpenDirectoryMode Mode { get; }
private ConcatenationFileSystem ParentFileSystem { get; }
private IFileSystem BaseFileSystem { get; }
private IDirectory ParentDirectory { get; }
private IFileSystem BaseFileSystem { get; }
private ConcatenationFileSystem ParentFileSystem { get; }
public ConcatenationDirectory(ConcatenationFileSystem fs, IFileSystem baseFs, IDirectory parentDirectory, OpenDirectoryMode mode, string path)
private FsPath _path;
public ConcatenationDirectory(ConcatenationFileSystem fs, IFileSystem baseFs, IDirectory parentDirectory, OpenDirectoryMode mode, U8Span path)
{
ParentFileSystem = fs;
BaseFileSystem = baseFs;
ParentDirectory = parentDirectory;
Mode = mode;
Path = path;
StringUtils.Copy(_path.Str, path);
_path.Str[PathTools.MaxPathLength] = StringTraits.NullTerminator;
// Ensure the path ends with a separator
int pathLength = StringUtils.GetLength(path, PathTools.MaxPathLength + 1);
if (pathLength != 0 && _path.Str[pathLength - 1] == StringTraits.DirectorySeparator)
return;
if (pathLength >= PathTools.MaxPathLength)
throw new HorizonResultException(ResultFs.TooLongPath.Value, "abort");
_path.Str[pathLength] = StringTraits.DirectorySeparator;
_path.Str[pathLength + 1] = StringTraits.NullTerminator;
_path.Str[PathTools.MaxPathLength] = StringTraits.NullTerminator;
}
public Result Read(out long entriesRead, Span<DirectoryEntry> entryBuffer)
@ -48,9 +63,12 @@ namespace LibHac.FsSystem
if (!Mode.HasFlag(OpenDirectoryMode.NoFileSize))
{
string entryName = Util.GetUtf8StringNullTerminated(entry.Name);
string entryFullPath = PathTools.Combine(Path, entryName);
string entryFullPath = PathTools.Combine(_path.ToString(), entryName);
entry.Size = ParentFileSystem.GetConcatenationFileSize(entryFullPath);
rc = ParentFileSystem.GetConcatenationFileSize(out long fileSize, entryFullPath.ToU8Span());
if (rc.IsFailure()) return rc;
entry.Size = fileSize;
}
}
@ -68,7 +86,7 @@ namespace LibHac.FsSystem
entryCount = 0;
long count = 0;
Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, Path,
Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, _path,
OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize);
if (rc.IsFailure()) return rc;
@ -104,7 +122,7 @@ namespace LibHac.FsSystem
else
{
string name = Util.GetUtf8StringNullTerminated(entry.Name);
string fullPath = PathTools.Combine(Path, name);
var fullPath = PathTools.Combine(_path.ToString(), name).ToU8Span();
return ParentFileSystem.IsConcatenationFile(fullPath);
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
@ -9,15 +10,15 @@ namespace LibHac.FsSystem
public class ConcatenationFile : FileBase
{
private IFileSystem BaseFileSystem { get; }
private string FilePath { get; }
private U8String FilePath { get; }
private List<IFile> Sources { get; }
private long SubFileSize { get; }
private OpenMode Mode { get; }
internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable<IFile> sources, long subFileSize, OpenMode mode)
internal ConcatenationFile(IFileSystem baseFileSystem, U8Span path, IEnumerable<IFile> sources, long subFileSize, OpenMode mode)
{
BaseFileSystem = baseFileSystem;
FilePath = path;
FilePath = path.ToU8String();
Sources = sources.ToList();
SubFileSize = subFileSize;
Mode = mode;
@ -78,7 +79,8 @@ namespace LibHac.FsSystem
long outPos = offset;
int remaining = source.Length;
GetSize(out long fileSize).ThrowIfFailure();
rc = GetSize(out long fileSize);
if (rc.IsFailure()) return rc;
while (remaining > 0)
{
@ -151,7 +153,12 @@ namespace LibHac.FsSystem
for (int i = currentSubFileCount; i < newSubFileCount; i++)
{
string newSubFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i);
FsPath newSubFilePath;
unsafe { _ = &newSubFilePath; } // workaround for CS0165
rc = ConcatenationFileSystem.GetSubFilePath(newSubFilePath.Str, FilePath, i);
if (rc.IsFailure()) return rc;
newSubFileSize = QuerySubFileSize(i, size, SubFileSize);
rc = BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None);
@ -170,7 +177,11 @@ namespace LibHac.FsSystem
Sources[i].Dispose();
Sources.RemoveAt(i);
string subFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i);
FsPath subFilePath;
unsafe { _ = &subFilePath; } // workaround for CS0165
rc = ConcatenationFileSystem.GetSubFilePath(subFilePath.Str, FilePath, i);
if (rc.IsFailure()) return rc;
rc = BaseFileSystem.DeleteFile(subFilePath);
if (rc.IsFailure()) return rc;

View File

@ -1,6 +1,9 @@
using System;
using System.Buffers;
using System.Buffers.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
@ -47,7 +50,7 @@ namespace LibHac.FsSystem
// .NET Core on platforms other than Windows doesn't support getting the
// archive flag in FAT file systems. Try to work around that for now for reading,
// but writing still won't work properly on those platforms
internal bool IsConcatenationFile(string path)
internal bool IsConcatenationFile(U8Span path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
@ -62,14 +65,14 @@ namespace LibHac.FsSystem
}
}
private bool IsConcatenationFileHeuristic(string path)
private bool IsConcatenationFileHeuristic(U8Span path)
{
// Check if the path is a directory
Result getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType pathType, path);
if (getTypeResult.IsFailure() || pathType != DirectoryEntryType.Directory) return false;
// Check if the directory contains at least one subfile
getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path, "00"));
getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path.ToString(), "00").ToU8Span());
if (getTypeResult.IsFailure() || subFileType != DirectoryEntryType.File) return false;
// Make sure the directory contains no subdirectories
@ -88,15 +91,14 @@ namespace LibHac.FsSystem
return (attributes & NxFileAttributes.Directory) != 0 && (attributes & NxFileAttributes.Archive) != 0;
}
private Result SetConcatenationFileAttribute(string path)
private Result SetConcatenationFileAttribute(U8Span path)
{
return BaseFileSystem.SetFileAttributes(path, NxFileAttributes.Archive);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
path = PathTools.Normalize(path);
string parent = PathTools.GetParentDirectory(path);
var parent = new U8Span(PathTools.GetParentDirectory(path));
if (IsConcatenationFile(parent))
{
@ -107,10 +109,8 @@ namespace LibHac.FsSystem
return BaseFileSystem.CreateDirectory(path);
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
path = PathTools.Normalize(path);
CreateFileOptions newOptions = options & ~CreateFileOptions.CreateConcatenationFile;
if (!options.HasFlag(CreateFileOptions.CreateConcatenationFile))
@ -119,9 +119,9 @@ namespace LibHac.FsSystem
}
// A concatenation file directory can't contain normal files
string parentDir = PathTools.GetParentDirectory(path);
ReadOnlySpan<byte> parentDir = PathTools.GetParentDirectory(path);
if (IsConcatenationFile(parentDir))
if (IsConcatenationFile(new U8Span(parentDir)))
{
// Cannot create a file inside of a concatenation file
return ResultFs.PathNotFound.Log();
@ -135,7 +135,12 @@ namespace LibHac.FsSystem
for (int i = 0; remaining > 0; i++)
{
long fileSize = Math.Min(SubFileSize, remaining);
string fileName = GetSubFilePath(path, i);
FsPath fileName;
unsafe { _ = &fileName; } // workaround for CS0165
rc = GetSubFilePath(fileName.Str, path, i);
if (rc.IsFailure()) return rc;
Result createSubFileResult = BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None);
@ -151,10 +156,8 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
path = PathTools.Normalize(path);
if (IsConcatenationFile(path))
{
return ResultFs.PathNotFound.Log();
@ -163,48 +166,48 @@ namespace LibHac.FsSystem
return BaseFileSystem.DeleteDirectory(path);
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
path = PathTools.Normalize(path);
if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log();
return BaseFileSystem.DeleteDirectoryRecursively(path);
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
path = PathTools.Normalize(path);
if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log();
return BaseFileSystem.CleanDirectoryRecursively(path);
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
path = PathTools.Normalize(path);
if (!IsConcatenationFile(path))
{
return BaseFileSystem.DeleteFile(path);
}
int count = GetSubFileCount(path);
Result rc = GetSubFileCount(out int count, path);
if (rc.IsFailure()) return rc;
for (int i = 0; i < count; i++)
{
Result rc = BaseFileSystem.DeleteFile(GetSubFilePath(path, i));
FsPath subFilePath;
unsafe { _ = &subFilePath; } // workaround for CS0165
rc = GetSubFilePath(subFilePath.Str, path, i);
if (rc.IsFailure()) return rc;
rc = BaseFileSystem.DeleteFile(subFilePath);
if (rc.IsFailure()) return rc;
}
return BaseFileSystem.DeleteDirectory(path);
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
path = PathTools.Normalize(path);
if (IsConcatenationFile(path))
{
@ -218,25 +221,29 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
path = PathTools.Normalize(path);
if (!IsConcatenationFile(path))
{
return BaseFileSystem.OpenFile(out file, path, mode);
}
int fileCount = GetSubFileCount(path);
Result rc = GetSubFileCount(out int fileCount, path);
if (rc.IsFailure()) return rc;
var files = new List<IFile>();
var files = new List<IFile>(fileCount);
for (int i = 0; i < fileCount; i++)
{
string filePath = GetSubFilePath(path, i);
FsPath subFilePath;
unsafe { _ = &subFilePath; } // workaround for CS0165
Result rc = BaseFileSystem.OpenFile(out IFile subFile, filePath, mode);
rc = GetSubFilePath(subFilePath.Str, path, i);
if (rc.IsFailure()) return rc;
rc = BaseFileSystem.OpenFile(out IFile subFile, subFilePath, mode);
if (rc.IsFailure()) return rc;
files.Add(subFile);
@ -246,11 +253,8 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
if (IsConcatenationFile(oldPath))
{
return ResultFs.PathNotFound.Log();
@ -259,11 +263,8 @@ namespace LibHac.FsSystem
return BaseFileSystem.RenameDirectory(oldPath, newPath);
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
if (IsConcatenationFile(oldPath))
{
return BaseFileSystem.RenameDirectory(oldPath, newPath);
@ -274,10 +275,8 @@ namespace LibHac.FsSystem
}
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
path = PathTools.Normalize(path);
if (IsConcatenationFile(path))
{
entryType = DirectoryEntryType.File;
@ -287,17 +286,17 @@ namespace LibHac.FsSystem
return BaseFileSystem.GetEntryType(out entryType, path);
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path);
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path);
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path);
}
@ -307,42 +306,101 @@ namespace LibHac.FsSystem
return BaseFileSystem.Commit();
}
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log();
return SetConcatenationFileAttribute(path);
}
private int GetSubFileCount(string dirPath)
private Result GetSubFileCount(out int fileCount, U8Span dirPath)
{
int count = 0;
fileCount = default;
while (BaseFileSystem.FileExists(GetSubFilePath(dirPath, count)))
FsPath buffer;
unsafe { _ = &buffer; } // workaround for CS0165
int pathLen = StringUtils.Copy(buffer.Str, dirPath);
// Make sure we have at least 3 bytes for the sub file name
if (pathLen + 3 > PathTools.MaxPathLength)
return ResultFs.TooLongPath.Log();
buffer.Str[pathLen] = StringTraits.DirectorySeparator;
Span<byte> subFileName = buffer.Str.Slice(pathLen + 1);
Result rc;
int count;
for (count = 0; ; count++)
{
count++;
Utf8Formatter.TryFormat(count, subFileName, out _, new StandardFormat('D', 2));
rc = BaseFileSystem.GetEntryType(out _, buffer);
if (rc.IsFailure()) break;
}
return count;
}
internal static string GetSubFilePath(string dirPath, int index)
{
return $"{dirPath}/{index:D2}";
}
internal long GetConcatenationFileSize(string path)
{
int fileCount = GetSubFileCount(path);
long size = 0;
for (int i = 0; i < fileCount; i++)
if (!ResultFs.PathNotFound.Includes(rc))
{
BaseFileSystem.GetFileSize(out long fileSize, GetSubFilePath(path, i)).ThrowIfFailure();
size += fileSize;
return rc;
}
return size;
fileCount = count;
return Result.Success;
}
internal static Result GetSubFilePath(Span<byte> subFilePathBuffer, ReadOnlySpan<byte> basePath, int index)
{
int basePathLen = StringUtils.Copy(subFilePathBuffer, basePath);
// Make sure we have at least 3 bytes for the sub file name
if (basePathLen + 3 > PathTools.MaxPathLength)
return ResultFs.TooLongPath.Log();
subFilePathBuffer[basePathLen] = StringTraits.DirectorySeparator;
Utf8Formatter.TryFormat(index, subFilePathBuffer.Slice(basePathLen + 1), out _, new StandardFormat('D', 2));
return Result.Success;
}
internal Result GetConcatenationFileSize(out long size, ReadOnlySpan<byte> path)
{
size = default;
FsPath buffer;
unsafe { _ = &buffer; } // workaround for CS0165
int pathLen = StringUtils.Copy(buffer.Str, path);
// Make sure we have at least 3 bytes for the sub file name
if (pathLen + 3 > PathTools.MaxPathLength)
return ResultFs.TooLongPath.Log();
buffer.Str[pathLen] = StringTraits.DirectorySeparator;
Span<byte> subFileName = buffer.Str.Slice(pathLen + 1);
Result rc;
long totalSize = 0;
for (int i = 0; ; i++)
{
Utf8Formatter.TryFormat(i, subFileName, out _, new StandardFormat('D', 2));
rc = BaseFileSystem.GetFileSize(out long fileSize, buffer);
if (rc.IsFailure()) break;
totalSize += fileSize;
}
if (!ResultFs.PathNotFound.Includes(rc))
{
return rc;
}
size = totalSize;
return Result.Success;
}
}
}

View File

@ -1,12 +1,18 @@
using LibHac.Fs;
using System;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
{
public class DirectorySaveDataFileSystem : FileSystemBase
{
private const string CommittedDir = "/0/";
private const string WorkingDir = "/1/";
private const string SyncDir = "/_/";
private ReadOnlySpan<byte> CommittedDirectoryBytes => new[] { (byte)'/', (byte)'0', (byte)'/' };
private ReadOnlySpan<byte> WorkingDirectoryBytes => new[] { (byte)'/', (byte)'1', (byte)'/' };
private ReadOnlySpan<byte> SynchronizingDirectoryBytes => new[] { (byte)'/', (byte)'_', (byte)'/' };
private U8Span CommittedDirectoryPath => new U8Span(CommittedDirectoryBytes);
private U8Span WorkingDirectoryPath => new U8Span(WorkingDirectoryBytes);
private U8Span SynchronizingDirectoryPath => new U8Span(SynchronizingDirectoryBytes);
private IFileSystem BaseFs { get; }
private object Locker { get; } = new object();
@ -44,18 +50,18 @@ namespace LibHac.FsSystem
IsUserSaveData = isUserSaveData;
// Ensure the working directory exists
Result rc = BaseFs.GetEntryType(out _, WorkingDir);
Result rc = BaseFs.GetEntryType(out _, WorkingDirectoryPath);
if (rc.IsFailure())
{
if (!ResultFs.PathNotFound.Includes(rc)) return rc;
rc = BaseFs.CreateDirectory(WorkingDir);
rc = BaseFs.CreateDirectory(WorkingDirectoryPath);
if (rc.IsFailure()) return rc;
if (!IsPersistentSaveData) return Result.Success;
rc = BaseFs.CreateDirectory(CommittedDir);
rc = BaseFs.CreateDirectory(CommittedDirectoryPath);
// Nintendo returns on all failures, but we'll keep going if committed already exists
// to avoid confusing people manually creating savedata in emulators
@ -65,11 +71,11 @@ namespace LibHac.FsSystem
// Only the working directory is needed for temporary savedata
if (!IsPersistentSaveData) return Result.Success;
rc = BaseFs.GetEntryType(out _, CommittedDir);
rc = BaseFs.GetEntryType(out _, CommittedDirectoryPath);
if (rc.IsSuccess())
{
return SynchronizeDirectory(WorkingDir, CommittedDir);
return SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath);
}
if (!ResultFs.PathNotFound.Includes(rc)) return rc;
@ -77,15 +83,19 @@ namespace LibHac.FsSystem
// If a previous commit failed, the committed dir may be missing.
// Finish that commit by copying the working dir to the committed dir
rc = SynchronizeDirectory(SyncDir, WorkingDir);
rc = SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath);
if (rc.IsFailure()) return rc;
return BaseFs.RenameDirectory(SyncDir, CommittedDir);
return BaseFs.RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -93,9 +103,13 @@ namespace LibHac.FsSystem
}
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -103,9 +117,13 @@ namespace LibHac.FsSystem
}
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -113,9 +131,13 @@ namespace LibHac.FsSystem
}
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -123,9 +145,13 @@ namespace LibHac.FsSystem
}
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -133,9 +159,13 @@ namespace LibHac.FsSystem
}
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
@ -143,9 +173,17 @@ namespace LibHac.FsSystem
}
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure())
{
directory = default;
return rc;
}
lock (Locker)
{
@ -153,14 +191,19 @@ namespace LibHac.FsSystem
}
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
lock (Locker)
{
Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode);
rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode);
if (rc.IsFailure()) return rc;
file = new DirectorySaveDataFile(this, baseFile, mode);
@ -174,31 +217,55 @@ namespace LibHac.FsSystem
}
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
string fullOldPath = GetFullPath(PathTools.Normalize(oldPath));
string fullNewPath = GetFullPath(PathTools.Normalize(newPath));
FsPath fullCurrentPath;
FsPath fullNewPath;
unsafe { _ = &fullCurrentPath; } // workaround for CS0165
unsafe { _ = &fullNewPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullCurrentPath.Str, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(fullNewPath.Str, newPath);
if (rc.IsFailure()) return rc;
lock (Locker)
{
return BaseFs.RenameDirectory(fullOldPath, fullNewPath);
return BaseFs.RenameDirectory(fullCurrentPath, fullNewPath);
}
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
string fullOldPath = GetFullPath(PathTools.Normalize(oldPath));
string fullNewPath = GetFullPath(PathTools.Normalize(newPath));
FsPath fullCurrentPath;
FsPath fullNewPath;
unsafe { _ = &fullCurrentPath; } // workaround for CS0165
unsafe { _ = &fullNewPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullCurrentPath.Str, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(fullNewPath.Str, newPath);
if (rc.IsFailure()) return rc;
lock (Locker)
{
return BaseFs.RenameFile(fullOldPath, fullNewPath);
return BaseFs.RenameFile(fullCurrentPath, fullNewPath);
}
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
string fullPath = GetFullPath(PathTools.Normalize(path));
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure())
{
entryType = default;
return rc;
}
lock (Locker)
{
@ -219,25 +286,31 @@ namespace LibHac.FsSystem
}
// Get rid of the previous commit by renaming the folder
Result rc = BaseFs.RenameDirectory(CommittedDir, SyncDir);
Result rc = BaseFs.RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath);
if (rc.IsFailure()) return rc;
// If something goes wrong beyond this point, the commit will be
// completed the next time the savedata is opened
rc = SynchronizeDirectory(SyncDir, WorkingDir);
rc = SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath);
if (rc.IsFailure()) return rc;
return BaseFs.RenameDirectory(SyncDir, CommittedDir);
return BaseFs.RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath);
}
}
private string GetFullPath(string path)
private Result ResolveFullPath(Span<byte> outPath, U8Span relativePath)
{
return PathTools.Normalize(PathTools.Combine(WorkingDir, path));
if (StringUtils.GetLength(relativePath, PathTools.MaxPathLength + 1) > PathTools.MaxPathLength)
return ResultFs.TooLongPath.Log();
StringUtils.Copy(outPath, WorkingDirectoryBytes);
outPath[^1] = StringTraits.NullTerminator;
return PathTool.Normalize(outPath.Slice(2), out _, relativePath, false, false);
}
private Result SynchronizeDirectory(string dest, string src)
private Result SynchronizeDirectory(U8Span dest, U8Span src)
{
Result rc = BaseFs.DeleteDirectoryRecursively(dest);
if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc)) return rc;
@ -245,7 +318,7 @@ namespace LibHac.FsSystem
rc = BaseFs.CreateDirectory(dest);
if (rc.IsFailure()) return rc;
return BaseFs.CopyDirectory(BaseFs, src, dest);
return BaseFs.CopyDirectory(BaseFs, src.ToString(), dest.ToString());
}
internal void NotifyCloseWritableFile()

View File

@ -11,9 +11,7 @@ namespace LibHac.FsSystem
public static Result IterateDirectoryRecursivelyInternal(IFileSystem fs, Span<byte> workPath,
ref DirectoryEntry entry, Blah onEnterDir, Blah onExitDir, Blah onFile)
{
string currentPath = Util.GetUtf8StringNullTerminated(workPath);
Result rc = fs.OpenDirectory(out IDirectory _, currentPath, OpenDirectoryMode.All);
Result rc = fs.OpenDirectory(out IDirectory _, new U8Span(workPath), OpenDirectoryMode.All);
if (rc.IsFailure()) return rc;
onFile(workPath, ref entry);
@ -40,7 +38,7 @@ namespace LibHac.FsSystem
try
{
Result rc = sourceFs.OpenFile(out srcFile, StringUtils.Utf8ZToString(sourcePath), OpenMode.Read);
Result rc = sourceFs.OpenFile(out srcFile, new U8Span(sourcePath), OpenMode.Read);
if (rc.IsFailure()) return rc;
FsPath dstPath = default;
@ -52,12 +50,10 @@ namespace LibHac.FsSystem
throw new ArgumentException();
}
string dstPathStr = StringUtils.Utf8ZToString(dstPath.Str);
rc = destFs.CreateFile(dstPathStr, dirEntry.Size, CreateFileOptions.None);
rc = destFs.CreateFile(dstPath, dirEntry.Size, CreateFileOptions.None);
if (rc.IsFailure()) return rc;
rc = destFs.OpenFile(out dstFile, dstPathStr, OpenMode.Write);
rc = destFs.OpenFile(out dstFile, dstPath, OpenMode.Write);
if (rc.IsFailure()) return rc;
long fileSize = dirEntry.Size;

View File

@ -31,12 +31,12 @@ namespace LibHac.FsSystem
{
destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options);
rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath, OpenMode.Read);
rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath.ToU8Span(), OpenMode.Read);
if (rc.IsFailure()) return rc;
using (srcFile)
{
rc = destFs.OpenFile(out IFile dstFile, subDstPath, OpenMode.Write | OpenMode.AllowAppend);
rc = destFs.OpenFile(out IFile dstFile, subDstPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend);
if (rc.IsFailure()) return rc;
using (dstFile)
@ -80,7 +80,7 @@ namespace LibHac.FsSystem
IFileSystem fs = fileSystem;
fileSystem.OpenDirectory(out IDirectory directory, path, OpenDirectoryMode.All).ThrowIfFailure();
fileSystem.OpenDirectory(out IDirectory directory, path.ToU8Span(), OpenDirectoryMode.All).ThrowIfFailure();
while (true)
{
@ -199,7 +199,7 @@ namespace LibHac.FsSystem
public static void SetConcatenationFileAttribute(this IFileSystem fs, string path)
{
fs.QueryEntry(Span<byte>.Empty, Span<byte>.Empty, QueryId.MakeConcatFile, path);
fs.QueryEntry(Span<byte>.Empty, Span<byte>.Empty, QueryId.MakeConcatFile, path.ToU8Span());
}
public static void CleanDirectoryRecursivelyGeneric(IFileSystem fileSystem, string path)
@ -213,11 +213,11 @@ namespace LibHac.FsSystem
if (entry.Type == DirectoryEntryType.Directory)
{
CleanDirectoryRecursivelyGeneric(fileSystem, subPath);
fs.DeleteDirectory(subPath);
fs.DeleteDirectory(subPath.ToU8Span());
}
else if (entry.Type == DirectoryEntryType.File)
{
fs.DeleteFile(subPath);
fs.DeleteFile(subPath.ToU8Span());
}
}
}
@ -234,14 +234,14 @@ namespace LibHac.FsSystem
public static bool DirectoryExists(this IFileSystem fs, string path)
{
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span());
return (rc.IsSuccess() && type == DirectoryEntryType.Directory);
}
public static bool FileExists(this IFileSystem fs, string path)
{
Result rc = fs.GetEntryType(out DirectoryEntryType type, path);
Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span());
return (rc.IsSuccess() && type == DirectoryEntryType.File);
}
@ -277,12 +277,12 @@ namespace LibHac.FsSystem
{
string subPath = path.Substring(0, i);
Result rc = fs.CreateDirectory(subPath);
Result rc = fs.CreateDirectory(subPath.ToU8Span());
if (rc.IsFailure()) return rc;
}
}
return fs.CreateDirectory(path);
return fs.CreateDirectory(path.ToU8Span());
}
public static void CreateOrOverwriteFile(this IFileSystem fs, string path, long size)
@ -294,9 +294,9 @@ namespace LibHac.FsSystem
{
path = PathTools.Normalize(path);
if (fs.FileExists(path)) fs.DeleteFile(path);
if (fs.FileExists(path)) fs.DeleteFile(path.ToU8Span());
fs.CreateFile(path, size, CreateFileOptions.None);
fs.CreateFile(path.ToU8Span(), size, CreateFileOptions.None);
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
@ -30,7 +31,9 @@ namespace LibHac.FsSystem
return builder.Overflowed ? ResultFs.TooLongPath.Log() : Result.Success;
}
public static implicit operator U8Span(FsPath value) => new U8Span(value.Str);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator U8Span(in FsPath value) => new U8Span(SpanHelpers.AsReadOnlyByteSpan(ref Unsafe.AsRef(in value)));
public override string ToString() => StringUtils.Utf8ZToString(Str);
}
}

View File

@ -35,10 +35,9 @@ namespace LibHac.FsSystem
Sources.AddRange(sourceFileSystems);
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
path = PathTools.Normalize(path);
// Open directories from all layers so they can be merged
// Only allocate the list for multiple sources if needed
@ -107,10 +106,9 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
path = PathTools.Normalize(path);
foreach (IFileSystem fs in Sources)
{
@ -137,10 +135,8 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
path = PathTools.Normalize(path);
foreach (IFileSystem fs in Sources)
{
Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path);
@ -156,10 +152,8 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
path = PathTools.Normalize(path);
foreach (IFileSystem fs in Sources)
{
Result getEntryResult = fs.GetEntryType(out _, path);
@ -174,10 +168,9 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
path = PathTools.Normalize(path);
foreach (IFileSystem fs in Sources)
{
Result getEntryResult = fs.GetEntryType(out _, path);
@ -196,31 +189,31 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log();
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log();
protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperation.Log();
protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log();
protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log();
protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperation.Log();
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperation.Log();
protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperation.Log();
protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperation.Log();
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperation.Log();
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperation.Log();
private class MergedDirectory : IDirectory
{
// Needed to open new directories for GetEntryCount
private List<IFileSystem> SourceFileSystems { get; }
private List<IDirectory> SourceDirs { get; }
private string Path { get; }
private U8String Path { get; }
private OpenDirectoryMode Mode { get; }
// todo: Efficient way to remove duplicates
private HashSet<string> Names { get; } = new HashSet<string>();
public MergedDirectory(List<IFileSystem> sourceFileSystems, string path, OpenDirectoryMode mode)
public MergedDirectory(List<IFileSystem> sourceFileSystems, U8Span path, OpenDirectoryMode mode)
{
SourceFileSystems = sourceFileSystems;
SourceDirs = new List<IDirectory>(sourceFileSystems.Count);
Path = path;
Path = path.ToU8String();
Mode = mode;
}
@ -280,7 +273,7 @@ namespace LibHac.FsSystem
long entriesRead;
do
{
dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry));
rc = dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry));
if (rc.IsFailure()) return rc;
if (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name)))

View File

@ -30,18 +30,49 @@ namespace LibHac.FsSystem
}
}
internal string ResolveLocalPath(string path)
private Result ResolveFullPath(out string fullPath, U8Span path)
{
return PathTools.Combine(BasePath, path);
fullPath = default;
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
fullPath = PathTools.Combine(BasePath, normalizedPath.ToString());
return Result.Success;
}
protected override Result GetFileAttributesImpl(string path, out NxFileAttributes attributes)
private Result CheckSubPath(U8Span path1, U8Span path2)
{
FsPath normalizedPath1;
FsPath normalizedPath2;
unsafe { _ = &normalizedPath1; } // workaround for CS0165
unsafe { _ = &normalizedPath2; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath1.Str, out _, path1, false, false);
if (rc.IsFailure()) return rc;
rc = PathTool.Normalize(normalizedPath2.Str, out _, path2, false, false);
if (rc.IsFailure()) return rc;
if (PathTool.IsSubpath(normalizedPath1, normalizedPath2))
{
return ResultFs.DestinationIsSubPathOfSource.Log();
}
return Result.Success;
}
protected override Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path)
{
attributes = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetFileInfo(out FileInfo info, localPath);
rc = GetFileInfo(out FileInfo info, fullPath);
if (rc.IsFailure()) return rc;
if (info.Attributes == (FileAttributes)(-1))
@ -54,11 +85,12 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result SetFileAttributesImpl(string path, NxFileAttributes attributes)
protected override Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetFileInfo(out FileInfo info, localPath);
rc = GetFileInfo(out FileInfo info, fullPath);
if (rc.IsFailure()) return rc;
if (info.Attributes == (FileAttributes)(-1))
@ -81,27 +113,30 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result GetFileSizeImpl(out long fileSize, string path)
protected override Result GetFileSizeImpl(out long fileSize, U8Span path)
{
fileSize = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = GetFileInfo(out FileInfo info, localPath);
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
rc = GetFileInfo(out FileInfo info, fullPath);
if (rc.IsFailure()) return rc;
return GetSizeInternal(out fileSize, info);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
return CreateDirectory(path, NxFileAttributes.None);
}
protected override Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute)
protected override Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetDirInfo(out DirectoryInfo dir, localPath);
rc = GetDirInfo(out DirectoryInfo dir, fullPath);
if (rc.IsFailure()) return rc;
if (dir.Exists)
@ -117,11 +152,12 @@ namespace LibHac.FsSystem
return CreateDirInternal(dir, archiveAttribute);
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetFileInfo(out FileInfo file, localPath);
rc = GetFileInfo(out FileInfo file, fullPath);
if (rc.IsFailure()) return rc;
if (file.Exists)
@ -144,42 +180,45 @@ namespace LibHac.FsSystem
}
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetDirInfo(out DirectoryInfo dir, localPath);
rc = GetDirInfo(out DirectoryInfo dir, fullPath);
if (rc.IsFailure()) return rc;
return DeleteDirectoryInternal(dir, false);
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetDirInfo(out DirectoryInfo dir, localPath);
rc = GetDirInfo(out DirectoryInfo dir, fullPath);
if (rc.IsFailure()) return rc;
return DeleteDirectoryInternal(dir, true);
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
foreach (string file in Directory.EnumerateFiles(localPath))
foreach (string file in Directory.EnumerateFiles(fullPath))
{
Result rc = GetFileInfo(out FileInfo fileInfo, file);
rc = GetFileInfo(out FileInfo fileInfo, file);
if (rc.IsFailure()) return rc;
rc = DeleteFileInternal(fileInfo);
if (rc.IsFailure()) return rc;
}
foreach (string dir in Directory.EnumerateDirectories(localPath))
foreach (string dir in Directory.EnumerateDirectories(fullPath))
{
Result rc = GetDirInfo(out DirectoryInfo dirInfo, dir);
rc = GetDirInfo(out DirectoryInfo dirInfo, dir);
if (rc.IsFailure()) return rc;
rc = DeleteDirectoryInternal(dirInfo, true);
@ -189,22 +228,24 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetFileInfo(out FileInfo file, localPath);
rc = GetFileInfo(out FileInfo file, fullPath);
if (rc.IsFailure()) return rc;
return DeleteFileInternal(file);
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
Result rc = GetDirInfo(out DirectoryInfo dirInfo, localPath);
rc = GetDirInfo(out DirectoryInfo dirInfo, fullPath);
if (rc.IsFailure()) return rc;
if (!dirInfo.Attributes.HasFlag(FileAttributes.Directory))
@ -225,12 +266,14 @@ namespace LibHac.FsSystem
}
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = GetEntryType(out DirectoryEntryType entryType, path);
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
rc = GetEntryType(out DirectoryEntryType entryType, path);
if (rc.IsFailure()) return rc;
if (entryType == DirectoryEntryType.Directory)
@ -238,59 +281,64 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
rc = OpenFileInternal(out FileStream fileStream, localPath, mode);
rc = OpenFileInternal(out FileStream fileStream, fullPath, mode);
if (rc.IsFailure()) return rc;
file = new LocalFile(fileStream, mode);
return Result.Success;
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
Result rc = CheckSubPath(oldPath, newPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(out string fullCurrentPath, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(out string fullNewPath, newPath);
if (rc.IsFailure()) return rc;
// Official FS behavior is to do nothing in this case
if (oldPath == newPath) return Result.Success;
if (fullCurrentPath == fullNewPath) return Result.Success;
// FS does the subpath check before verifying the path exists
if (PathTools.IsSubPath(oldPath.AsSpan(), newPath.AsSpan()))
{
ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource.Value);
}
Result rc = GetDirInfo(out DirectoryInfo srcDir, ResolveLocalPath(oldPath));
rc = GetDirInfo(out DirectoryInfo currentDirInfo, fullCurrentPath);
if (rc.IsFailure()) return rc;
rc = GetDirInfo(out DirectoryInfo dstDir, ResolveLocalPath(newPath));
rc = GetDirInfo(out DirectoryInfo newDirInfo, fullNewPath);
if (rc.IsFailure()) return rc;
return RenameDirInternal(srcDir, dstDir);
return RenameDirInternal(currentDirInfo, newDirInfo);
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
string srcLocalPath = ResolveLocalPath(PathTools.Normalize(oldPath));
string dstLocalPath = ResolveLocalPath(PathTools.Normalize(newPath));
Result rc = ResolveFullPath(out string fullCurrentPath, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(out string fullNewPath, newPath);
if (rc.IsFailure()) return rc;
// Official FS behavior is to do nothing in this case
if (srcLocalPath == dstLocalPath) return Result.Success;
if (fullCurrentPath == fullNewPath) return Result.Success;
Result rc = GetFileInfo(out FileInfo srcFile, srcLocalPath);
rc = GetFileInfo(out FileInfo currentFileInfo, fullCurrentPath);
if (rc.IsFailure()) return rc;
rc = GetFileInfo(out FileInfo dstFile, dstLocalPath);
rc = GetFileInfo(out FileInfo newFileInfo, fullNewPath);
if (rc.IsFailure()) return rc;
return RenameFileInternal(srcFile, dstFile);
return RenameFileInternal(currentFileInfo, newFileInfo);
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
entryType = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = GetDirInfo(out DirectoryInfo dir, localPath);
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
rc = GetDirInfo(out DirectoryInfo dir, fullPath);
if (rc.IsFailure()) return rc;
if (dir.Exists)
@ -299,7 +347,7 @@ namespace LibHac.FsSystem
return Result.Success;
}
rc = GetFileInfo(out FileInfo file, localPath);
rc = GetFileInfo(out FileInfo file, fullPath);
if (rc.IsFailure()) return rc;
if (file.Exists)
@ -312,30 +360,32 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
timeStamp = default;
string localPath = ResolveLocalPath(PathTools.Normalize(path));
Result rc = GetFileInfo(out FileInfo file, localPath);
Result rc = ResolveFullPath(out string fullPath, path);
if (rc.IsFailure()) return rc;
rc = GetFileInfo(out FileInfo file, fullPath);
if (rc.IsFailure()) return rc;
if (!file.Exists) return ResultFs.PathNotFound.Log();
timeStamp.Created = new DateTimeOffset(File.GetCreationTime(localPath)).ToUnixTimeSeconds();
timeStamp.Accessed = new DateTimeOffset(File.GetLastAccessTime(localPath)).ToUnixTimeSeconds();
timeStamp.Modified = new DateTimeOffset(File.GetLastWriteTime(localPath)).ToUnixTimeSeconds();
timeStamp.Created = new DateTimeOffset(file.CreationTimeUtc).ToUnixTimeSeconds();
timeStamp.Accessed = new DateTimeOffset(file.LastAccessTimeUtc).ToUnixTimeSeconds();
timeStamp.Modified = new DateTimeOffset(file.LastWriteTime).ToUnixTimeSeconds();
return Result.Success;
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
freeSpace = new DriveInfo(BasePath).AvailableFreeSpace;
return Result.Success;
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
totalSpace = new DriveInfo(BasePath).TotalSize;
return Result.Success;
@ -346,7 +396,8 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
return ResultFs.UnsupportedOperation.Log();
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LibHac.Common;
using LibHac.Crypto;
using LibHac.Fs;
@ -31,17 +32,17 @@ namespace LibHac.FsSystem
BaseStorage = storage;
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = new PartitionDirectory(this, path, mode);
directory = new PartitionDirectory(this, path.ToString(), mode);
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
path = PathTools.Normalize(path).TrimStart('/');
path = PathTools.Normalize(path.ToString()).TrimStart('/').ToU8Span();
if (!FileDict.TryGetValue(path, out PartitionFileEntry entry))
if (!FileDict.TryGetValue(path.ToString(), out PartitionFileEntry entry))
{
ThrowHelper.ThrowResult(ResultFs.PathNotFound.Value);
}
@ -55,18 +56,17 @@ namespace LibHac.FsSystem
return new PartitionFile(BaseStorage, HeaderSize + entry.Offset, entry.Size, mode);
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
entryType = default;
path = PathTools.Normalize(path);
if (path == "/")
if (path.ToString() == "/")
{
entryType = DirectoryEntryType.Directory;
return Result.Success;
}
if (FileDict.ContainsKey(path.TrimStart('/')))
if (FileDict.ContainsKey(path.ToString().TrimStart('/')))
{
entryType = DirectoryEntryType.File;
return Result.Success;
@ -75,14 +75,14 @@ namespace LibHac.FsSystem
return ResultFs.PathNotFound.Log();
}
protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CommitImpl()
{

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LibHac.Common;
using LibHac.Crypto;
using LibHac.Fs;
@ -26,7 +27,7 @@ namespace LibHac.FsSystem
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
{
input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure();
input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
AddFile(entry.FullPath.TrimStart('/'), file);
}

View File

@ -31,7 +31,7 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
@ -40,7 +40,7 @@ namespace LibHac.FsSystem
ReadOnlySpan<byte> rootPath = new[] { (byte)'/' };
if (StringUtils.Compare(rootPath, path.ToU8Span(), 2) != 0)
if (StringUtils.Compare(rootPath, path, 2) != 0)
return ResultFs.PathNotFound.Log();
directory = new PartitionDirectory(this, mode);
@ -48,7 +48,7 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
@ -58,7 +58,7 @@ namespace LibHac.FsSystem
if (!mode.HasFlag(OpenMode.Read) && !mode.HasFlag(OpenMode.Write))
return ResultFs.InvalidArgument.Log();
int entryIndex = MetaData.FindEntry(path.ToU8Span().Slice(1));
int entryIndex = MetaData.FindEntry(path.Slice(1));
if (entryIndex < 0) return ResultFs.PathNotFound.Log();
ref T entry = ref MetaData.GetEntry(entryIndex);
@ -68,25 +68,25 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
entryType = default;
if (!IsInitialized)
return ResultFs.PreconditionViolation.Log();
if (string.IsNullOrEmpty(path) || path[0] != '/')
if (path.IsEmpty() || path[0] != '/')
return ResultFs.InvalidPathFormat.Log();
ReadOnlySpan<byte> rootPath = new[] { (byte)'/' };
if (StringUtils.Compare(rootPath, path.ToU8Span(), 2) == 0)
if (StringUtils.Compare(rootPath, path, 2) == 0)
{
entryType = DirectoryEntryType.Directory;
return Result.Success;
}
if (MetaData.FindEntry(path.ToU8Span().Slice(1)) >= 0)
if (MetaData.FindEntry(path.Slice(1)) >= 0)
{
entryType = DirectoryEntryType.File;
return Result.Success;
@ -100,14 +100,14 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log();
private class PartitionFile : FileBase
{

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem
{
@ -11,12 +12,12 @@ namespace LibHac.FsSystem
BaseFs = baseFileSystem;
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
return BaseFs.OpenDirectory(out directory, path, mode);
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
@ -27,12 +28,12 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
return BaseFs.GetEntryType(out entryType, path);
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
freeSpace = 0;
return Result.Success;
@ -41,7 +42,7 @@ namespace LibHac.FsSystem
// return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log();
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
return BaseFs.GetTotalSpaceSize(out totalSpace, path);
@ -49,7 +50,7 @@ namespace LibHac.FsSystem
// return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log();
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
return BaseFs.GetFileTimeStampRaw(out timeStamp, path);
@ -62,20 +63,20 @@ namespace LibHac.FsSystem
return Result.Success;
}
protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log();
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem.RomFs
@ -36,7 +37,7 @@ namespace LibHac.FsSystem.RomFs
foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
{
input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure();
input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
AddFile(entry.FullPath, file);
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem.RomFs
{
@ -22,18 +23,17 @@ namespace LibHac.FsSystem.RomFs
FileTable = new HierarchicalRomFileTable<RomFileInfo>(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable);
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
entryType = default;
path = PathTools.Normalize(path);
if (FileTable.TryOpenFile(path, out RomFileInfo _))
if (FileTable.TryOpenFile(path.ToString(), out RomFileInfo _))
{
entryType = DirectoryEntryType.File;
return Result.Success;
}
if (FileTable.TryOpenDirectory(path, out FindPosition _))
if (FileTable.TryOpenDirectory(path.ToString(), out FindPosition _))
{
entryType = DirectoryEntryType.Directory;
return Result.Success;
@ -47,12 +47,11 @@ namespace LibHac.FsSystem.RomFs
return Result.Success;
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
path = PathTools.Normalize(path);
if (!FileTable.TryOpenDirectory(path, out FindPosition position))
if (!FileTable.TryOpenDirectory(path.ToString(), out FindPosition position))
{
return ResultFs.PathNotFound.Log();
}
@ -61,12 +60,11 @@ namespace LibHac.FsSystem.RomFs
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
path = PathTools.Normalize(path);
if (!FileTable.TryOpenFile(path, out RomFileInfo info))
if (!FileTable.TryOpenFile(path.ToString(), out RomFileInfo info))
{
return ResultFs.PathNotFound.Log();
}
@ -86,22 +84,22 @@ namespace LibHac.FsSystem.RomFs
return BaseStorage;
}
protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log();
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
freeSpace = default;
return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log();
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
totalSpace = default;
return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log();

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem.Save
@ -16,9 +17,9 @@ namespace LibHac.FsSystem.Save
DirectoryTable = new SaveFsList<TableEntry<SaveFindPosition>>(dirTable);
}
public bool TryOpenFile(string path, out SaveFileInfo fileInfo)
public bool TryOpenFile(U8Span path, out SaveFileInfo fileInfo)
{
if (!FindPathRecursive(Util.GetUtf8Bytes(path), out SaveEntryKey key))
if (!FindPathRecursive(path, out SaveEntryKey key))
{
fileInfo = default;
return false;
@ -89,24 +90,18 @@ namespace LibHac.FsSystem.Save
return true;
}
public void AddFile(string path, ref SaveFileInfo fileInfo)
public void AddFile(U8Span path, ref SaveFileInfo fileInfo)
{
path = PathTools.Normalize(path);
ReadOnlySpan<byte> pathBytes = Util.GetUtf8Bytes(path);
if (path.Length == 1 && path[0] == '/') throw new ArgumentException("Path cannot be empty");
if (path == "/") throw new ArgumentException("Path cannot be empty");
CreateFileRecursive(pathBytes, ref fileInfo);
CreateFileRecursive(path, ref fileInfo);
}
public void AddDirectory(string path)
public void AddDirectory(U8Span path)
{
path = PathTools.Normalize(path);
ReadOnlySpan<byte> pathBytes = Util.GetUtf8Bytes(path);
if (path.Length == 1 && path[0] == '/') throw new ArgumentException("Path cannot be empty");
if (path == "/") throw new ArgumentException("Path cannot be empty");
CreateDirectoryRecursive(pathBytes);
CreateDirectoryRecursive(path);
}
private void CreateFileRecursive(ReadOnlySpan<byte> path, ref SaveFileInfo fileInfo)
@ -269,12 +264,9 @@ namespace LibHac.FsSystem.Save
}
}
public void DeleteFile(string path)
public void DeleteFile(U8Span path)
{
path = PathTools.Normalize(path);
ReadOnlySpan<byte> pathBytes = Util.GetUtf8Bytes(path);
FindPathRecursive(pathBytes, out SaveEntryKey key);
FindPathRecursive(path, out SaveEntryKey key);
int parentIndex = key.Parent;
int toDeleteIndex = FileTable.GetIndexFromKey(ref key).Index;
@ -285,12 +277,9 @@ namespace LibHac.FsSystem.Save
FileTable.Remove(ref key);
}
public void DeleteDirectory(string path)
public void DeleteDirectory(U8Span path)
{
path = PathTools.Normalize(path);
ReadOnlySpan<byte> pathBytes = Util.GetUtf8Bytes(path);
FindPathRecursive(pathBytes, out SaveEntryKey key);
FindPathRecursive(path, out SaveEntryKey key);
int parentIndex = key.Parent;
int toDeleteIndex = DirectoryTable.GetIndexFromKey(ref key).Index;
@ -308,24 +297,21 @@ namespace LibHac.FsSystem.Save
DirectoryTable.Remove(ref key);
}
public void RenameFile(string srcPath, string dstPath)
public void RenameFile(U8Span srcPath, U8Span dstPath)
{
if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _))
if (srcPath.Value == dstPath.Value || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _))
{
throw new IOException("Destination path already exists.");
}
ReadOnlySpan<byte> oldPathBytes = Util.GetUtf8Bytes(srcPath);
ReadOnlySpan<byte> newPathBytes = Util.GetUtf8Bytes(dstPath);
if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey))
if (!FindPathRecursive(srcPath, out SaveEntryKey oldKey))
{
throw new FileNotFoundException();
}
int fileIndex = FileTable.GetIndexFromKey(ref oldKey).Index;
if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey))
if (!FindPathRecursive(dstPath, out SaveEntryKey newKey))
{
throw new FileNotFoundException();
}
@ -339,29 +325,26 @@ namespace LibHac.FsSystem.Save
FileTable.ChangeKey(ref oldKey, ref newKey);
}
public Result RenameDirectory(string srcPath, string dstPath)
public Result RenameDirectory(U8Span srcPath, U8Span dstPath)
{
if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _))
if (srcPath.Value == dstPath.Value || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _))
{
return ResultFs.PathAlreadyExists.Log();
}
ReadOnlySpan<byte> oldPathBytes = Util.GetUtf8Bytes(srcPath);
ReadOnlySpan<byte> newPathBytes = Util.GetUtf8Bytes(dstPath);
if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey))
if (!FindPathRecursive(srcPath, out SaveEntryKey oldKey))
{
return ResultFs.PathNotFound.Log();
}
int dirIndex = DirectoryTable.GetIndexFromKey(ref oldKey).Index;
if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey))
if (!FindPathRecursive(dstPath, out SaveEntryKey newKey))
{
return ResultFs.PathNotFound.Log();
}
if (PathTools.IsSubPath(oldPathBytes, newPathBytes))
if (PathTools.IsSubPath(srcPath, dstPath))
{
return ResultFs.DestinationIsSubPathOfSource.Log();
}
@ -377,9 +360,9 @@ namespace LibHac.FsSystem.Save
return Result.Success;
}
public bool TryOpenDirectory(string path, out SaveFindPosition position)
public bool TryOpenDirectory(U8Span path, out SaveFindPosition position)
{
if (!FindPathRecursive(Util.GetUtf8Bytes(path), out SaveEntryKey key))
if (!FindPathRecursive(path, out SaveEntryKey key))
{
position = default;
return false;

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem.Save
@ -7,16 +8,16 @@ namespace LibHac.FsSystem.Save
public class SaveDataFile : FileBase
{
private AllocationTableStorage BaseStorage { get; }
private string Path { get; }
private U8String Path { get; }
private HierarchicalSaveFileTable FileTable { get; }
private long Size { get; set; }
private OpenMode Mode { get; }
public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode)
public SaveDataFile(AllocationTableStorage baseStorage, U8Span path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode)
{
Mode = mode;
BaseStorage = baseStorage;
Path = path;
Path = path.ToU8String();
FileTable = fileTable;
Size = size;
}

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using LibHac.Common;
using LibHac.Crypto;
using LibHac.Fs;
@ -143,91 +144,91 @@ namespace LibHac.FsSystem.Save
IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
Result result = SaveDataFileSystemCore.CreateDirectory(path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
Result result = SaveDataFileSystemCore.CreateFile(path, size, options);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
Result result = SaveDataFileSystemCore.DeleteDirectory(path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
Result result = SaveDataFileSystemCore.DeleteFile(path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
Result result = SaveDataFileSystemCore.RenameDirectory(oldPath, newPath);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
Result result = SaveDataFileSystemCore.RenameFile(oldPath, newPath);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path);
return SaveResults.ConvertToExternalResult(result).LogConverted(result);
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path);

View File

@ -1,4 +1,5 @@
using System.IO;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSystem.Save
@ -27,23 +28,31 @@ namespace LibHac.FsSystem.Save
FileTable = new HierarchicalSaveFileTable(dirTableStorage, fileTableStorage);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
path = PathTools.Normalize(path);
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
FileTable.AddDirectory(path);
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
FileTable.AddDirectory(normalizedPath);
return Result.Success;
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
path = PathTools.Normalize(path);
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
if (size == 0)
{
var emptyFileEntry = new SaveFileInfo { StartBlock = int.MinValue, Length = size };
FileTable.AddFile(path, ref emptyFileEntry);
FileTable.AddFile(normalizedPath, ref emptyFileEntry);
return Result.Success;
}
@ -58,46 +67,63 @@ namespace LibHac.FsSystem.Save
var fileEntry = new SaveFileInfo { StartBlock = startBlock, Length = size };
FileTable.AddFile(path, ref fileEntry);
FileTable.AddFile(normalizedPath, ref fileEntry);
return Result.Success;
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
path = PathTools.Normalize(path);
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
FileTable.DeleteDirectory(path);
return Result.Success;
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
{
path = PathTools.Normalize(path);
Result rc = CleanDirectoryRecursively(path);
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
DeleteDirectory(path);
FileTable.DeleteDirectory(normalizedPath);
return Result.Success;
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
path = PathTools.Normalize(path);
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
FileSystemExtensions.CleanDirectoryRecursivelyGeneric(this, path);
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
rc = CleanDirectoryRecursively(normalizedPath);
if (rc.IsFailure()) return rc;
rc = DeleteDirectory(normalizedPath);
if (rc.IsFailure()) return rc;
return Result.Success;
}
protected override Result DeleteFileImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
path = PathTools.Normalize(path);
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo))
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
FileSystemExtensions.CleanDirectoryRecursivelyGeneric(this, normalizedPath.ToString());
return Result.Success;
}
protected override Result DeleteFileImpl(U8Span path)
{
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
if (!FileTable.TryOpenFile(normalizedPath, out SaveFileInfo fileInfo))
{
return ResultFs.PathNotFound.Log();
}
@ -107,17 +133,22 @@ namespace LibHac.FsSystem.Save
AllocationTable.Free(fileInfo.StartBlock);
}
FileTable.DeleteFile(path);
FileTable.DeleteFile(normalizedPath);
return Result.Success;
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
path = PathTools.Normalize(path);
if (!FileTable.TryOpenDirectory(path, out SaveFindPosition position))
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
if (!FileTable.TryOpenDirectory(normalizedPath, out SaveFindPosition position))
{
return ResultFs.PathNotFound.Log();
}
@ -127,52 +158,79 @@ namespace LibHac.FsSystem.Save
return Result.Success;
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
path = PathTools.Normalize(path);
if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo))
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
if (!FileTable.TryOpenFile(normalizedPath, out SaveFileInfo fileInfo))
{
return ResultFs.PathNotFound.Log();
}
AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock);
file = new SaveDataFile(storage, path, FileTable, fileInfo.Length, mode);
file = new SaveDataFile(storage, normalizedPath, FileTable, fileInfo.Length, mode);
return Result.Success;
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
FsPath normalizedCurrentPath;
FsPath normalizedNewPath;
unsafe { _ = &normalizedCurrentPath; } // workaround for CS0165
unsafe { _ = &normalizedNewPath; } // workaround for CS0165
return FileTable.RenameDirectory(oldPath, newPath);
Result rc = PathTool.Normalize(normalizedCurrentPath.Str, out _, oldPath, false, false);
if (rc.IsFailure()) return rc;
rc = PathTool.Normalize(normalizedNewPath.Str, out _, newPath, false, false);
if (rc.IsFailure()) return rc;
return FileTable.RenameDirectory(normalizedCurrentPath, normalizedNewPath);
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
oldPath = PathTools.Normalize(oldPath);
newPath = PathTools.Normalize(newPath);
FsPath normalizedCurrentPath;
FsPath normalizedNewPath;
unsafe { _ = &normalizedCurrentPath; } // workaround for CS0165
unsafe { _ = &normalizedNewPath; } // workaround for CS0165
FileTable.RenameFile(oldPath, newPath);
Result rc = PathTool.Normalize(normalizedCurrentPath.Str, out _, oldPath, false, false);
if (rc.IsFailure()) return rc;
rc = PathTool.Normalize(normalizedNewPath.Str, out _, newPath, false, false);
if (rc.IsFailure()) return rc;
FileTable.RenameFile(normalizedCurrentPath, normalizedNewPath);
return Result.Success;
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
path = PathTools.Normalize(path);
entryType = default;
if (FileTable.TryOpenFile(path, out SaveFileInfo _))
FsPath normalizedPath;
unsafe { _ = &normalizedPath; } // workaround for CS0165
Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false);
if (rc.IsFailure()) return rc;
if (FileTable.TryOpenFile(normalizedPath, out SaveFileInfo _))
{
entryType = DirectoryEntryType.File;
return Result.Success;
}
if (FileTable.TryOpenDirectory(path, out SaveFindPosition _))
if (FileTable.TryOpenDirectory(normalizedPath, out SaveFindPosition _))
{
entryType = DirectoryEntryType.Directory;
return Result.Success;
@ -182,7 +240,7 @@ namespace LibHac.FsSystem.Save
return ResultFs.PathNotFound.Log();
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
int freeBlockCount = AllocationTable.GetFreeListLength();
freeSpace = Header.BlockSize * freeBlockCount;
@ -190,7 +248,7 @@ namespace LibHac.FsSystem.Save
return Result.Success;
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
totalSpace = Header.BlockSize * Header.BlockCount;
@ -211,7 +269,7 @@ namespace LibHac.FsSystem.Save
foreach (DirectoryEntryEx file in this.EnumerateEntries("*", SearchOptions.RecurseSubdirectories))
{
if (FileTable.TryOpenFile(file.FullPath, out SaveFileInfo fileInfo) && fileInfo.StartBlock >= 0)
if (FileTable.TryOpenFile(file.FullPath.ToU8Span(), out SaveFileInfo fileInfo) && fileInfo.StartBlock >= 0)
{
AllocationTable.FsTrimList(fileInfo.StartBlock);

View File

@ -72,140 +72,121 @@ namespace LibHac.FsSystem
return PathTool.Normalize(outPath.Slice(RootPath.Length - 2), out _, relativePath, PreserveUnc, false);
}
protected override Result CreateDirectoryImpl(string path)
protected override Result CreateDirectoryImpl(U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.CreateDirectory(StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.CreateDirectory(new U8Span(fullPath));
}
protected override Result CreateFileImpl(string path, long size, CreateFileOptions options)
protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.CreateFile(StringUtils.Utf8ZToString(fullPath), size, options);
return BaseFileSystem.CreateFile(new U8Span(fullPath), size, options);
}
protected override Result DeleteDirectoryImpl(string path)
protected override Result DeleteDirectoryImpl(U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.DeleteDirectory(StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.DeleteDirectory(new U8Span(fullPath));
}
protected override Result DeleteDirectoryRecursivelyImpl(string path)
protected override Result DeleteDirectoryRecursivelyImpl(U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.DeleteDirectoryRecursively(StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.DeleteDirectoryRecursively(new U8Span(fullPath));
}
protected override Result CleanDirectoryRecursivelyImpl(string path)
protected override Result CleanDirectoryRecursivelyImpl(U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.CleanDirectoryRecursively(StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.CleanDirectoryRecursively(new U8Span(fullPath));
}
protected override Result DeleteFileImpl(string path)
protected override Result DeleteFileImpl(U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.DeleteFile(StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.DeleteFile(new U8Span(fullPath));
}
protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode)
protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode)
{
directory = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.OpenDirectory(out directory, StringUtils.Utf8ZToString(fullPath), mode);
return BaseFileSystem.OpenDirectory(out directory, new U8Span(fullPath), mode);
}
protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode)
protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode)
{
file = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.OpenFile(out file, StringUtils.Utf8ZToString(fullPath), mode);
return BaseFileSystem.OpenFile(out file, new U8Span(fullPath), mode);
}
protected override Result RenameDirectoryImpl(string oldPath, string newPath)
protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath)
{
var u8OldPath = new U8String(oldPath);
var u8NewPath = new U8String(newPath);
Span<byte> fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1];
Span<byte> fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullOldPath, u8OldPath);
Result rc = ResolveFullPath(fullOldPath, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(fullNewPath, u8NewPath);
rc = ResolveFullPath(fullNewPath, newPath);
if (rc.IsFailure()) return rc;
return BaseFileSystem.RenameDirectory(StringUtils.Utf8ZToString(fullOldPath), StringUtils.Utf8ZToString(fullNewPath));
return BaseFileSystem.RenameDirectory(new U8Span(fullOldPath), new U8Span(fullNewPath));
}
protected override Result RenameFileImpl(string oldPath, string newPath)
protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath)
{
var u8OldPath = new U8String(oldPath);
var u8NewPath = new U8String(newPath);
Span<byte> fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1];
Span<byte> fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullOldPath, u8OldPath);
Result rc = ResolveFullPath(fullOldPath, oldPath);
if (rc.IsFailure()) return rc;
rc = ResolveFullPath(fullNewPath, u8NewPath);
rc = ResolveFullPath(fullNewPath, newPath);
if (rc.IsFailure()) return rc;
return BaseFileSystem.RenameFile(StringUtils.Utf8ZToString(fullOldPath), StringUtils.Utf8ZToString(fullNewPath));
return BaseFileSystem.RenameFile(new U8Span(fullOldPath), new U8Span(fullNewPath));
}
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path)
protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path)
{
entryType = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
FsPath fullPath;
unsafe { _ = &fullPath; } // workaround for CS0165
Result rc = ResolveFullPath(fullPath.Str, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.GetEntryType(out entryType, StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.GetEntryType(out entryType, fullPath);
}
protected override Result CommitImpl()
@ -213,51 +194,47 @@ namespace LibHac.FsSystem
return BaseFileSystem.Commit();
}
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path)
protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path)
{
freeSpace = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.GetFreeSpaceSize(out freeSpace, StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.GetFreeSpaceSize(out freeSpace, new U8Span(fullPath));
}
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path)
protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path)
{
totalSpace = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.GetTotalSpaceSize(out totalSpace, StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.GetTotalSpaceSize(out totalSpace, new U8Span(fullPath));
}
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path)
protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
{
timeStamp = default;
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, new U8Span(fullPath));
}
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, string path)
protected override Result QueryEntryImpl(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
U8Span path)
{
var u8Path = new U8String(path);
Span<byte> fullPath = stackalloc byte[PathTools.MaxPathLength + 1];
Result rc = ResolveFullPath(fullPath, u8Path);
Result rc = ResolveFullPath(fullPath, path);
if (rc.IsFailure()) return rc;
return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, StringUtils.Utf8ZToString(fullPath));
return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, new U8Span(fullPath));
}
}
}

View File

@ -13,16 +13,16 @@ namespace LibHac.Kvdb
private Dictionary<TKey, byte[]> KvDict { get; } = new Dictionary<TKey, byte[]>();
private FileSystemClient FsClient { get; }
private string FileName { get; }
private U8String FileName { get; }
public int Count => KvDict.Count;
public KeyValueDatabase() { }
public KeyValueDatabase(FileSystemClient fsClient, string fileName)
public KeyValueDatabase(FileSystemClient fsClient, U8Span fileName)
{
FsClient = fsClient;
FileName = fileName;
FileName = fileName.ToU8String();
}
public Result Get(ref TKey key, Span<byte> valueBuffer)
@ -109,7 +109,7 @@ namespace LibHac.Kvdb
public Result ReadDatabaseFromFile()
{
if (FsClient == null || FileName == null)
if (FsClient == null || FileName.IsNull())
return ResultFs.PreconditionViolation.Log();
Result rc = ReadFile(out byte[] data);
@ -124,7 +124,7 @@ namespace LibHac.Kvdb
public Result WriteDatabaseToFile()
{
if (FsClient == null || FileName == null)
if (FsClient == null || FileName.IsNull())
return ResultFs.PreconditionViolation.Log();
var buffer = new byte[GetExportedSize()];
@ -157,7 +157,7 @@ namespace LibHac.Kvdb
private Result ReadFile(out byte[] data)
{
Debug.Assert(FsClient != null);
Debug.Assert(!string.IsNullOrWhiteSpace(FileName));
Debug.Assert(!FileName.IsEmpty());
data = default;
@ -180,7 +180,7 @@ namespace LibHac.Kvdb
private Result WriteFile(ReadOnlySpan<byte> data)
{
Debug.Assert(FsClient != null);
Debug.Assert(!string.IsNullOrWhiteSpace(FileName));
Debug.Assert(!FileName.IsEmpty());
FsClient.DeleteFile(FileName);

View File

@ -84,7 +84,7 @@ namespace LibHac
SwitchFsNca nca = null;
try
{
ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
nca = new SwitchFsNca(new Nca(Keyset, ncaFile.AsStorage()));
@ -122,7 +122,7 @@ namespace LibHac
try
{
SaveFs.OpenFile(out IFile file, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure();
SaveFs.OpenFile(out IFile file, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
save = new SaveDataFileSystem(Keyset, file.AsStorage(), IntegrityCheckLevel.None, true);
}
@ -149,7 +149,7 @@ namespace LibHac
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
fs.OpenFile(out IFile file, cnmtPath, OpenMode.Read).ThrowIfFailure();
fs.OpenFile(out IFile file, cnmtPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
var metadata = new Cnmt(file.AsStream());
title.Id = metadata.TitleId;
@ -193,7 +193,7 @@ namespace LibHac
foreach (Title title in Titles.Values.Where(x => x.ControlNca != null))
{
IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
romfs.OpenFile(out IFile control, "control.nacp", OpenMode.Read).ThrowIfFailure();
romfs.OpenFile(out IFile control, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
title.Control = new Nacp(control.AsStream());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
namespace LibHac
@ -29,7 +30,7 @@ namespace LibHac
XciPartition root = GetRootPartition();
if (type == XciPartitionType.Root) return root;
root.OpenFile(out IFile partitionFile, type.GetFileName(), OpenMode.Read).ThrowIfFailure();
root.OpenFile(out IFile partitionFile, type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure();
return new XciPartition(partitionFile.AsStorage());
}

View File

@ -1,6 +1,7 @@
using System;
using System.Buffers;
using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
@ -8,14 +9,14 @@ namespace hactoolnet
{
public static class FsUtils
{
public static void CopyDirectoryWithProgress(FileSystemClient fs, string sourcePath, string destPath,
public static Result CopyDirectoryWithProgress(FileSystemClient fs, U8Span sourcePath, U8Span destPath,
CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null)
{
try
{
logger?.SetTotal(GetTotalSize(fs, sourcePath));
CopyDirectoryWithProgressInternal(fs, sourcePath, destPath, options, logger);
return CopyDirectoryWithProgressInternal(fs, sourcePath, destPath, options, logger);
}
finally
{
@ -23,41 +24,51 @@ namespace hactoolnet
}
}
private static void CopyDirectoryWithProgressInternal(FileSystemClient fs, string sourcePath, string destPath,
private static Result CopyDirectoryWithProgressInternal(FileSystemClient fs, U8Span sourcePath, U8Span destPath,
CreateFileOptions options, IProgressReport logger)
{
fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure();
string sourcePathStr = sourcePath.ToString();
string destPathStr = destPath.ToString();
Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All);
if (rc.IsFailure()) return rc;
using (sourceHandle)
{
foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default))
foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePathStr, "*", SearchOptions.Default))
{
string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name));
string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name));
string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePathStr, entry.Name));
string subDstPath = PathTools.Normalize(PathTools.Combine(destPathStr, entry.Name));
if (entry.Type == DirectoryEntryType.Directory)
{
fs.EnsureDirectoryExists(subDstPath);
CopyDirectoryWithProgressInternal(fs, subSrcPath, subDstPath, options, logger);
rc = CopyDirectoryWithProgressInternal(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), options, logger);
if (rc.IsFailure()) return rc;
}
if (entry.Type == DirectoryEntryType.File)
{
logger?.LogMessage(subSrcPath);
fs.CreateOrOverwriteFile(subDstPath, entry.Size, options);
CopyFileWithProgress(fs, subSrcPath, subDstPath, logger);
rc = fs.CreateOrOverwriteFile(subDstPath, entry.Size, options);
if (rc.IsFailure()) return rc;
rc = CopyFileWithProgress(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), logger);
if (rc.IsFailure()) return rc;
}
}
}
return Result.Success;
}
public static long GetTotalSize(FileSystemClient fs, string path, string searchPattern = "*")
public static long GetTotalSize(FileSystemClient fs, U8Span path, string searchPattern = "*")
{
long size = 0;
foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path, searchPattern))
foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path.ToString(), searchPattern))
{
size += entry.Size;
}
@ -65,7 +76,7 @@ namespace hactoolnet
return size;
}
public static Result CopyFileWithProgress(FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null)
public static Result CopyFileWithProgress(FileSystemClient fs, U8Span sourcePath, U8Span destPath, IProgressReport logger = null)
{
Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read);
if (rc.IsFailure()) return rc;

View File

@ -2,6 +2,7 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
@ -34,7 +35,7 @@ namespace hactoolnet
throw new FileNotFoundException("Specified NCA does not contain a delta fragment");
}
fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName, OpenMode.Read).ThrowIfFailure();
fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName.ToU8String(), OpenMode.Read).ThrowIfFailure();
deltaStorage = deltaFragmentFile.AsStorage();
}

View File

@ -27,7 +27,7 @@ namespace hactoolnet
try
{
xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath, kekSource, validationKey, 0x4000);
xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath.ToU8String(), kekSource, validationKey, 0x4000);
contentType = i;
break;

View File

@ -51,10 +51,10 @@ namespace hactoolnet
fs.Register(mountName.ToU8Span(), OpenFileSystem(i));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i]));
FsUtils.CopyDirectoryWithProgress(fs, mountName + ":/", "output:/", logger: ctx.Logger);
FsUtils.CopyDirectoryWithProgress(fs, (mountName + ":/").ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
fs.Unmount(mountName);
fs.Unmount("output");
fs.Unmount(mountName.ToU8Span());
fs.Unmount("output".ToU8Span());
}
if (ctx.Options.Validate && nca.SectionExists(i))
@ -100,10 +100,10 @@ namespace hactoolnet
fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir));
FsUtils.CopyDirectoryWithProgress(fs, "rom:/", "output:/", logger: ctx.Logger);
FsUtils.CopyDirectoryWithProgress(fs, "rom:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
fs.Unmount("rom");
fs.Unmount("output");
fs.Unmount("rom".ToU8Span());
fs.Unmount("output".ToU8Span());
}
if (ctx.Options.ReadBench)
@ -157,10 +157,10 @@ namespace hactoolnet
fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code));
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir));
FsUtils.CopyDirectoryWithProgress(fs, "code:/", "output:/", logger: ctx.Logger);
FsUtils.CopyDirectoryWithProgress(fs, "code:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
fs.Unmount("code");
fs.Unmount("output");
fs.Unmount("code".ToU8Span());
fs.Unmount("output".ToU8Span());
}
}
@ -211,7 +211,7 @@ namespace hactoolnet
IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid);
if (!pfs.FileExists("main.npdm")) return Validity.Unchecked;
pfs.OpenFile(out IFile npdmFile, "main.npdm", OpenMode.Read).ThrowIfFailure();
pfs.OpenFile(out IFile npdmFile, "main.npdm".ToU8String(), OpenMode.Read).ThrowIfFailure();
var npdm = new NpdmBinary(npdmFile.AsStream());
return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus);
@ -234,7 +234,7 @@ namespace hactoolnet
PrintItem(sb, colLen, "TitleID:", $"{nca.Header.TitleId:X16}");
if (nca.CanOpenSection(NcaSectionType.Code)) {
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None);
Result r = fs.OpenFile(out IFile file, "/main.npdm", OpenMode.Read);
Result r = fs.OpenFile(out IFile file, "/main.npdm".ToU8String(), OpenMode.Read);
if (r.IsSuccess()) {
var npdm = new NpdmBinary(file.AsStream(), null);
PrintItem(sb, colLen, "Title Name:", npdm.TitleName);

View File

@ -42,9 +42,9 @@ namespace hactoolnet
{
fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.OutDir));
FsUtils.CopyDirectoryWithProgress(fs, "save:/", "output:/", logger: ctx.Logger);
FsUtils.CopyDirectoryWithProgress(fs, "save:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
fs.Unmount("output");
fs.Unmount("output".ToU8Span());
}
if (ctx.Options.DebugOutDir != null)
@ -63,7 +63,7 @@ namespace hactoolnet
using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read))
{
save.OpenFile(out IFile outFile, destFilename, OpenMode.ReadWrite).ThrowIfFailure();
save.OpenFile(out IFile outFile, destFilename.ToU8String(), OpenMode.ReadWrite).ThrowIfFailure();
using (outFile)
{
@ -88,13 +88,13 @@ namespace hactoolnet
{
fs.Register("input".ToU8Span(), new LocalFileSystem(ctx.Options.RepackSource));
fs.CleanDirectoryRecursively("save:/");
fs.Commit("save");
fs.CleanDirectoryRecursively("save:/".ToU8Span());
fs.Commit("save".ToU8Span());
FsUtils.CopyDirectoryWithProgress(fs, "input:/", "save:/", logger: ctx.Logger);
FsUtils.CopyDirectoryWithProgress(fs, "input:/".ToU8Span(), "save:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure();
fs.Commit("save");
fs.Unmount("input");
fs.Commit("save".ToU8Span());
fs.Unmount("input".ToU8Span());
signNeeded = true;
}
@ -134,7 +134,7 @@ namespace hactoolnet
ctx.Logger.LogMessage("Unable to sign save file. Do you have all the required keys?");
}
fs.Unmount("save");
fs.Unmount("save".ToU8Span());
return;
}
@ -149,7 +149,7 @@ namespace hactoolnet
ctx.Logger.LogMessage(save.Print(ctx.Keyset));
//ctx.Logger.LogMessage(PrintFatLayout(save.SaveDataFileSystemCore));
fs.Unmount("save");
fs.Unmount("save".ToU8Span());
}
}
@ -239,7 +239,7 @@ namespace hactoolnet
foreach (DirectoryEntryEx entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File))
{
save.FileTable.TryOpenFile(entry.FullPath, out SaveFileInfo fileInfo);
save.FileTable.TryOpenFile(entry.FullPath.ToU8Span(), out SaveFileInfo fileInfo);
if (fileInfo.StartBlock < 0) continue;
IEnumerable<(int block, int length)> chain = save.AllocationTable.DumpChain(fileInfo.StartBlock);
@ -321,7 +321,7 @@ namespace hactoolnet
var sb = new StringBuilder();
sb.AppendLine();
save.GetFreeSpaceSize(out long freeSpace, "").ThrowIfFailure();
save.GetFreeSpaceSize(out long freeSpace, "".ToU8String()).ThrowIfFailure();
sb.AppendLine("Savefile:");
PrintItem(sb, colLen, "CMAC Key Used:", keyset.SaveMacKey);

View File

@ -16,7 +16,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
fs.CreateCacheStorage(applicationId, SaveDataSpaceId.User, applicationId, 0, 0, SaveDataFlags.None);
Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId));
Assert.Success(fs.MountCacheStorage("cache".ToU8Span(), applicationId));
}
[Fact]
@ -26,14 +26,14 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
fs.CreateCacheStorage(applicationId, SaveDataSpaceId.SdCache, applicationId, 0, 0, SaveDataFlags.None);
fs.MountCacheStorage("cache".ToU8String(), applicationId);
fs.MountCacheStorage("cache".ToU8Span(), applicationId);
fs.CreateFile("cache:/file", 0);
fs.Commit("cache");
fs.Unmount("cache");
fs.CreateFile("cache:/file".ToU8Span(), 0);
fs.Commit("cache".ToU8Span());
fs.Unmount("cache".ToU8Span());
Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId));
Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "cache:/file"));
Assert.Success(fs.MountCacheStorage("cache".ToU8Span(), applicationId));
Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "cache:/file".ToU8Span()));
Assert.Equal(DirectoryEntryType.File, type);
}
[Fact]
@ -43,25 +43,25 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
fs.CreateCacheStorage(applicationId, SaveDataSpaceId.SdCache, applicationId, 0, 0, SaveDataFlags.None);
fs.MountCacheStorage("cache".ToU8String(), applicationId);
fs.CreateFile("cache:/sd", 0);
fs.Commit("cache");
fs.Unmount("cache");
fs.MountCacheStorage("cache".ToU8Span(), applicationId);
fs.CreateFile("cache:/sd".ToU8Span(), 0);
fs.Commit("cache".ToU8Span());
fs.Unmount("cache".ToU8Span());
// Turn off the SD card so the User save is mounted
fs.SetSdCardAccessibility(false);
fs.CreateCacheStorage(applicationId, SaveDataSpaceId.User, applicationId, 0, 0, SaveDataFlags.None);
fs.MountCacheStorage("cache".ToU8String(), applicationId);
fs.CreateFile("cache:/bis", 0);
fs.Commit("cache");
fs.Unmount("cache");
fs.MountCacheStorage("cache".ToU8Span(), applicationId);
fs.CreateFile("cache:/bis".ToU8Span(), 0);
fs.Commit("cache".ToU8Span());
fs.Unmount("cache".ToU8Span());
fs.SetSdCardAccessibility(true);
Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId));
Assert.Success(fs.GetEntryType(out _, "cache:/sd"));
Assert.Failure(fs.GetEntryType(out _, "cache:/bis"));
Assert.Success(fs.GetEntryType(out _, "cache:/sd".ToU8Span()));
Assert.Failure(fs.GetEntryType(out _, "cache:/bis".ToU8Span()));
}
}
}

View File

@ -12,7 +12,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
{
FileSystemClient fs = FileSystemServerFactory.CreateClient(true);
Assert.Success(fs.MountSdCard("sdcard".ToU8String()));
Assert.Success(fs.MountSdCard("sdcard".ToU8Span()));
}
[Fact]
@ -20,7 +20,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
{
FileSystemClient fs = FileSystemServerFactory.CreateClient(false);
Assert.Result(ResultFs.SdCardNotFound, fs.MountSdCard("sdcard".ToU8String()));
Assert.Result(ResultFs.SdCardNotFound, fs.MountSdCard("sdcard".ToU8Span()));
}
[Fact]
@ -30,7 +30,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests
fs.MountSdCard("sdcard".ToU8String());
Assert.Success(fs.CreateFile("sdcard:/file", 100, CreateFileOptions.None));
Assert.Success(fs.CreateFile("sdcard:/file".ToU8Span(), 100, CreateFileOptions.None));
}
[Fact]

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -12,9 +13,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.None).IsSuccess());
Assert.True(fs.CreateDirectory("/dir".ToU8Span(), NxFileAttributes.None).IsSuccess());
Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess());
Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()).IsSuccess());
Assert.Equal(NxFileAttributes.Directory, attributes);
}
@ -23,9 +24,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.Archive).IsSuccess());
Assert.True(fs.CreateDirectory("/dir".ToU8Span(), NxFileAttributes.Archive).IsSuccess());
Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess());
Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()).IsSuccess());
Assert.Equal(NxFileAttributes.Directory | NxFileAttributes.Archive, attributes);
}
@ -33,9 +34,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void GetFileAttributes_AttributesOnNewFileAreEmpty()
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/file");
Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/file".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(NxFileAttributes.None, attributes);
@ -45,9 +46,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void GetFileAttributes_AttributesOnNewDirHaveOnlyDirFlagSet()
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir");
Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(NxFileAttributes.Directory, attributes);
@ -58,7 +59,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
Result rc = fs.GetFileAttributes(out _, "/path");
Result rc = fs.GetFileAttributes(out _, "/path".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -68,7 +69,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
Result rc = fs.SetFileAttributes("/path", NxFileAttributes.None);
Result rc = fs.SetFileAttributes("/path".ToU8Span(), NxFileAttributes.None);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -77,10 +78,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void SetFileAttributes_SetAttributeOnFile()
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rcSet = fs.SetFileAttributes("/file", NxFileAttributes.Archive);
Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/file");
Result rcSet = fs.SetFileAttributes("/file".ToU8Span(), NxFileAttributes.Archive);
Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/file".ToU8Span());
Assert.True(rcSet.IsSuccess());
Assert.True(rcGet.IsSuccess());
@ -91,10 +92,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void SetFileAttributes_SetAttributeOnDirectory()
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rcSet = fs.SetFileAttributes("/dir", NxFileAttributes.Archive);
Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir");
Result rcSet = fs.SetFileAttributes("/dir".ToU8Span(), NxFileAttributes.Archive);
Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span());
Assert.True(rcSet.IsSuccess());
Assert.True(rcGet.IsSuccess());
@ -106,9 +107,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateFile("/file", 845, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 845, CreateFileOptions.None);
Assert.True(fs.GetFileSize(out long fileSize, "/file").IsSuccess());
Assert.True(fs.GetFileSize(out long fileSize, "/file".ToU8Span()).IsSuccess());
Assert.Equal(845, fileSize);
}
@ -117,7 +118,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
Result rc = fs.GetFileSize(out _, "/path");
Result rc = fs.GetFileSize(out _, "/path".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -126,9 +127,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void GetFileSize_PathIsDirectory_ReturnsPathNotFound()
{
IAttributeFileSystem fs = CreateAttributeFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.GetFileSize(out _, "/dir");
Result rc = fs.GetFileSize(out _, "/dir".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,15 +11,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir/dir2");
fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
fs.CreateDirectory("/dir/dir2".ToU8Span());
fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None);
Result rcDelete = fs.CleanDirectoryRecursively("/dir");
Result rcDelete = fs.CleanDirectoryRecursively("/dir".ToU8Span());
Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir");
Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir".ToU8Span());
Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2".ToU8Span());
Result rcFileType = fs.GetEntryType(out _, "/dir/file1".ToU8Span());
Assert.True(rcDelete.IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,8 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.Directory, type);
@ -22,9 +23,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.CreateDirectory("/dir");
Result rc = fs.CreateDirectory("/dir".ToU8Span());
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.CreateDirectory("/file");
Result rc = fs.CreateDirectory("/file".ToU8Span());
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -46,7 +47,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.CreateFile("/dir1/dir2", 0, CreateFileOptions.None);
Result rc = fs.CreateFile("/dir1/dir2".ToU8Span(), 0, CreateFileOptions.None);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -56,8 +57,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir/");
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/");
fs.CreateDirectory("/dir/".ToU8Span());
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.Directory, type);
@ -68,11 +69,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir2".ToU8Span());
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1");
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2");
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1".ToU8Span());
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2".ToU8Span());
Assert.True(rc1.IsSuccess());
Assert.True(rc2.IsSuccess());
@ -85,14 +86,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir2".ToU8Span());
fs.CreateDirectory("/dir1/dir1a");
fs.CreateDirectory("/dir2/dir2a");
fs.CreateDirectory("/dir1/dir1a".ToU8Span());
fs.CreateDirectory("/dir2/dir2a".ToU8Span());
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a");
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a");
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a".ToU8Span());
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a".ToU8Span());
Assert.True(rc1.IsSuccess());
Assert.True(rc2.IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,8 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file");
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.File, type);
@ -22,9 +23,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.CreateFile("/dir", 0, CreateFileOptions.None);
Result rc = fs.CreateFile("/dir".ToU8Span(), 0, CreateFileOptions.None);
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.CreateFile("/file", 0, CreateFileOptions.None);
Result rc = fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -46,7 +47,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
Result rc = fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -56,8 +57,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file/", 0, CreateFileOptions.None);
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/");
fs.CreateFile("/file/".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.File, type);
@ -70,9 +71,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", expectedSize, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), expectedSize, CreateFileOptions.None);
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
Result rc = file.GetSize(out long fileSize);
Assert.True(rc.IsSuccess());
@ -84,11 +85,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateFile("/file2", 0, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None);
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/file1");
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/file2");
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/file1".ToU8Span());
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/file2".ToU8Span());
Assert.True(rc1.IsSuccess());
Assert.True(rc2.IsSuccess());
@ -101,14 +102,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir2".ToU8Span());
fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None);
fs.CreateFile("/dir2/file2", 0, CreateFileOptions.None);
fs.CreateFile("/dir1/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/dir2/file2".ToU8Span(), 0, CreateFileOptions.None);
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/file1");
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/file2");
Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/file1".ToU8Span());
Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/file2".ToU8Span());
Assert.True(rc1.IsSuccess());
Assert.True(rc2.IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,7 +11,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.DeleteDirectory("/dir");
Result rc = fs.DeleteDirectory("/dir".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -20,10 +21,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rcDelete = fs.DeleteDirectory("/dir");
Result rcEntry = fs.GetEntryType(out _, "/dir");
Result rcDelete = fs.DeleteDirectory("/dir".ToU8Span());
Result rcEntry = fs.GetEntryType(out _, "/dir".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.DeleteDirectory("/file");
Result rc = fs.DeleteDirectory("/file".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -46,12 +47,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir2".ToU8Span());
Result rcDelete = fs.DeleteDirectory("/dir2");
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
Result rcDelete = fs.DeleteDirectory("/dir2".ToU8Span());
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span());
Result rcEntry2 = fs.GetEntryType(out _, "/dir2".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.True(rcEntry1.IsSuccess());
@ -65,12 +66,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2".ToU8Span());
fs.CreateDirectory("/dir1".ToU8Span());
Result rcDelete = fs.DeleteDirectory("/dir2");
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
Result rcEntry2 = fs.GetEntryType(out _, "/dir2");
Result rcDelete = fs.DeleteDirectory("/dir2".ToU8Span());
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span());
Result rcEntry2 = fs.GetEntryType(out _, "/dir2".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.True(rcEntry1.IsSuccess());
@ -84,10 +85,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateFile("/dir/file", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.DeleteDirectory("/dir");
Result rc = fs.DeleteDirectory("/dir".ToU8Span());
Assert.Equal(ResultFs.DirectoryNotEmpty.Value, rc);
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,15 +11,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir/dir2");
fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
fs.CreateDirectory("/dir/dir2".ToU8Span());
fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None);
Result rcDelete = fs.DeleteDirectoryRecursively("/dir");
Result rcDelete = fs.DeleteDirectoryRecursively("/dir".ToU8Span());
Result rcDir1Type = fs.GetEntryType(out _, "/dir");
Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2");
Result rcFileType = fs.GetEntryType(out _, "/dir/file1");
Result rcDir1Type = fs.GetEntryType(out _, "/dir".ToU8Span());
Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2".ToU8Span());
Result rcFileType = fs.GetEntryType(out _, "/dir/file1".ToU8Span());
Assert.True(rcDelete.IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,7 +11,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.DeleteFile("/file");
Result rc = fs.DeleteFile("/file".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -19,10 +20,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rcDelete = fs.DeleteFile("/file");
Result rcEntry = fs.GetEntryType(out _, "/file");
Result rcDelete = fs.DeleteFile("/file".ToU8Span());
Result rcEntry = fs.GetEntryType(out _, "/file".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.Equal(ResultFs.PathNotFound.Value, rcEntry);
@ -33,9 +34,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.DeleteFile("/dir");
Result rc = fs.DeleteFile("/dir".ToU8Span());
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}
@ -45,12 +46,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateFile("/file2", 0, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None);
Result rcDelete = fs.DeleteFile("/file2");
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
Result rcEntry2 = fs.GetEntryType(out _, "/file2");
Result rcDelete = fs.DeleteFile("/file2".ToU8Span());
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1".ToU8Span());
Result rcEntry2 = fs.GetEntryType(out _, "/file2".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.True(rcEntry1.IsSuccess());
@ -64,12 +65,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file2", 0, CreateFileOptions.None);
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
Result rcDelete = fs.DeleteFile("/file2");
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1");
Result rcEntry2 = fs.GetEntryType(out _, "/file2");
Result rcDelete = fs.DeleteFile("/file2".ToU8Span());
Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1".ToU8Span());
Result rcEntry2 = fs.GetEntryType(out _, "/file2".ToU8Span());
Assert.True(rcDelete.IsSuccess());
Assert.True(rcEntry1.IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,9 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.GetEntryType(out DirectoryEntryType type, "/");
Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "/".ToU8Span()));
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.Directory, type);
}
@ -21,9 +21,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Result rc = fs.GetEntryType(out _, "/path");
Assert.Equal(ResultFs.PathNotFound.Value, rc);
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/path".ToU8Span()));
}
}
}

View File

@ -13,7 +13,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
IFileSystem fs = CreateFileSystem();
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[1];
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.Read(out long entriesRead, entries));
Assert.Equal(0, entriesRead);
@ -24,7 +24,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.GetEntryCount(out long entryCount));
Assert.Equal(0, entryCount);
@ -34,13 +34,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void IDirectoryRead_AllEntriesAreReturned()
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir/dir1");
fs.CreateFile("/dir/dir1/file1", 0, CreateFileOptions.None);
fs.CreateFile("/dir/file1", 0, CreateFileOptions.None);
fs.CreateFile("/dir/file2", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
fs.CreateDirectory("/dir/dir1".ToU8Span());
fs.CreateFile("/dir/dir1/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/dir/file2".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All);
Result rc = fs.OpenDirectory(out IDirectory dir, "/dir".ToU8Span(), OpenDirectoryMode.All);
Assert.True(rc.IsSuccess());
var entry1 = new DirectoryEntry();

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
@ -11,10 +12,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 100, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None);
var buffer = new byte[20];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Assert.True(file.Read(out long bytesRead, 50, buffer, ReadOption.None).IsSuccess());
@ -27,10 +28,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Result rc = file.Read(out _, 1, buffer, ReadOption.None);
@ -43,10 +44,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
using (file)
{
Result rc = file.Read(out _, 0, buffer, ReadOption.None);
@ -59,10 +60,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
using (file)
{
Result rc = file.Read(out _, -5, buffer, ReadOption.None);
@ -75,10 +76,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
using (file)
{
Result rc = file.Read(out _, long.MaxValue - 5, buffer, ReadOption.None);
@ -91,10 +92,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 100, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None);
var buffer = new byte[200];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Assert.True(file.Read(out long bytesRead, 90, buffer, ReadOption.None).IsSuccess());
@ -107,10 +108,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 100, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None);
// The contents of a created file are undefined, so zero the file
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
using (file)
{
file.Write(0, new byte[100], WriteOption.None);
@ -122,7 +123,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
var buffer = new byte[200];
buffer.AsSpan().Fill(0xCC);
fs.OpenFile(out file, "/file", OpenMode.Read);
fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Assert.True(file.Read(out _, 90, buffer, ReadOption.None).IsSuccess());

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -9,13 +10,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
public void SetSize_FileSizeModified()
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
fs.OpenFile(out IFile file, "/file", OpenMode.All);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All);
Result rc = file.SetSize(54321);
file.Dispose();
fs.OpenFile(out file, "/file", OpenMode.All);
fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.All);
file.GetSize(out long fileSize);
file.Dispose();

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
@ -13,15 +14,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), data.Length, CreateFileOptions.None);
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
file.Write(0, data, WriteOption.None);
file.Dispose();
var readData = new byte[data.Length];
fs.OpenFile(out file, "/file", OpenMode.Read);
fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Assert.True(file.Read(out long bytesRead, 0, readData, ReadOption.None).IsSuccess());
@ -36,10 +37,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
using (file)
{
Result rc = file.Write(5, buffer, WriteOption.None);
@ -52,10 +53,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Result rc = file.Write(5, buffer, WriteOption.None);
@ -68,10 +69,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Result rc = file.Write(-5, buffer, WriteOption.None);
@ -84,10 +85,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.Read);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
Result rc = file.Write(long.MaxValue - 5, buffer, WriteOption.None);
@ -100,10 +101,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.All);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All);
using (file)
{
Assert.True(file.Write(5, buffer, WriteOption.None).IsSuccess());
@ -118,10 +119,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var buffer = new byte[10];
fs.OpenFile(out IFile file, "/file", OpenMode.All);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All);
using (file)
{
Assert.True(file.Write(15, buffer, WriteOption.None).IsSuccess());
@ -136,7 +137,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 10, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None);
var bufferExpected = new byte[25];
bufferExpected.AsSpan(15).Fill(0xCC);
@ -144,7 +145,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
var writeBuffer = new byte[10];
writeBuffer.AsSpan().Fill(0xCC);
fs.OpenFile(out IFile file, "/file", OpenMode.All);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All);
using (file)
{
Assert.True(file.Write(15, writeBuffer, WriteOption.None).IsSuccess());
@ -155,7 +156,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
var readBuffer = new byte[25];
fs.OpenFile(out file, "/file", OpenMode.Read);
fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read);
using (file)
{
file.Read(out _, 0, readBuffer, ReadOption.None);

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,9 +11,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.OpenDirectory(out _, "/file", OpenDirectoryMode.All);
Result rc = fs.OpenDirectory(out _, "/file".ToU8Span(), OpenDirectoryMode.All);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,9 +11,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir");
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.OpenFile(out _, "/dir", OpenMode.All);
Result rc = fs.OpenFile(out _, "/dir".ToU8Span(), OpenMode.All);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,11 +11,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span());
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
Result rcDir1 = fs.GetEntryType(out _, "/dir1");
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span());
Result rcDir1 = fs.GetEntryType(out _, "/dir1".ToU8Span());
Assert.True(rcRename.IsSuccess());
@ -29,21 +30,21 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir1/dirC");
fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir1/dirC".ToU8Span());
fs.CreateFile("/dir1/file1".ToU8Span(), 0, CreateFileOptions.None);
Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span());
// Check that renamed structure exists
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC");
Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1");
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span());
Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC".ToU8Span());
Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1".ToU8Span());
// Check that old structure doesn't exist
Result rcDir1 = fs.GetEntryType(out _, "/dir1");
Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC");
Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1");
Result rcDir1 = fs.GetEntryType(out _, "/dir1".ToU8Span());
Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC".ToU8Span());
Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1".ToU8Span());
Assert.True(rcRename.IsSuccess());
@ -65,14 +66,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/parent1");
fs.CreateDirectory("/parent2");
fs.CreateDirectory("/parent1/dir1");
fs.CreateDirectory("/parent1".ToU8Span());
fs.CreateDirectory("/parent2".ToU8Span());
fs.CreateDirectory("/parent1/dir1".ToU8Span());
Result rcRename = fs.RenameDirectory("/parent1/dir1", "/parent2/dir2");
Result rcRename = fs.RenameDirectory("/parent1/dir1".ToU8Span(), "/parent2/dir2".ToU8Span());
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2");
Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1");
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2".ToU8Span());
Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1".ToU8Span());
Assert.True(rcRename.IsSuccess());
@ -88,13 +89,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateDirectory("/dir1");
fs.CreateDirectory("/dir2");
fs.CreateDirectory("/dir1".ToU8Span());
fs.CreateDirectory("/dir2".ToU8Span());
Result rcRename = fs.RenameDirectory("/dir1", "/dir2");
Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span());
Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1");
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2");
Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span());
Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span());
Assert.Equal(ResultFs.PathAlreadyExists.Value, rcRename);

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using Xunit;
namespace LibHac.Tests.Fs.IFileSystemTestBase
@ -10,12 +11,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
Assert.True(fs.RenameFile("/file1", "/file2").IsSuccess());
Assert.True(fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span()).IsSuccess());
Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/file2").IsSuccess());
Result rc = fs.GetEntryType(out _, "/file1");
Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/file2".ToU8Span()).IsSuccess());
Result rc = fs.GetEntryType(out _, "/file1".ToU8Span());
Assert.Equal(DirectoryEntryType.File, type);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
@ -25,13 +26,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir");
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
Assert.True(fs.RenameFile("/file1", "/dir/file2").IsSuccess());
Assert.True(fs.RenameFile("/file1".ToU8Span(), "/dir/file2".ToU8Span()).IsSuccess());
Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/dir/file2").IsSuccess());
Result rc = fs.GetEntryType(out _, "/file1");
Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/dir/file2".ToU8Span()).IsSuccess());
Result rc = fs.GetEntryType(out _, "/file1".ToU8Span());
Assert.Equal(DirectoryEntryType.File, type);
Assert.Equal(ResultFs.PathNotFound.Value, rc);
@ -42,10 +43,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 0, CreateFileOptions.None);
fs.CreateFile("/file2", 0, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None);
Result rc = fs.RenameFile("/file1", "/file2");
Result rc = fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span());
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -55,10 +56,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", 0, CreateFileOptions.None);
fs.CreateDirectory("/dir");
fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
fs.CreateDirectory("/dir".ToU8Span());
Result rc = fs.RenameFile("/file", "/dir");
Result rc = fs.RenameFile("/file".ToU8Span(), "/dir".ToU8Span());
Assert.Equal(ResultFs.PathAlreadyExists.Value, rc);
}
@ -68,13 +69,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
{
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file1", 54321, CreateFileOptions.None);
fs.CreateFile("/file2", 12345, CreateFileOptions.None);
fs.CreateFile("/file1".ToU8Span(), 54321, CreateFileOptions.None);
fs.CreateFile("/file2".ToU8Span(), 12345, CreateFileOptions.None);
fs.RenameFile("/file1", "/file2");
fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span());
Assert.True(fs.OpenFile(out IFile file1, "/file1", OpenMode.Read).IsSuccess());
Assert.True(fs.OpenFile(out IFile file2, "/file2", OpenMode.Read).IsSuccess());
Assert.True(fs.OpenFile(out IFile file1, "/file1".ToU8Span(), OpenMode.Read).IsSuccess());
Assert.True(fs.OpenFile(out IFile file2, "/file2".ToU8Span(), OpenMode.Read).IsSuccess());
using (file1)
using (file2)
@ -94,17 +95,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase
IFileSystem fs = CreateFileSystem();
fs.CreateFile("/file", data.Length, CreateFileOptions.None);
fs.CreateFile("/file".ToU8Span(), data.Length, CreateFileOptions.None);
fs.OpenFile(out IFile file, "/file", OpenMode.Write);
fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write);
file.Write(0, data, WriteOption.None);
file.Dispose();
fs.RenameFile("/file", "/renamed");
fs.RenameFile("/file".ToU8Span(), "/renamed".ToU8Span());
var readData = new byte[data.Length];
fs.OpenFile(out file, "/renamed", OpenMode.Read);
fs.OpenFile(out file, "/renamed".ToU8Span(), OpenMode.Read);
Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None);
file.Dispose();

View File

@ -15,30 +15,30 @@ namespace LibHac.Tests.Fs
var layeredFs = new LayeredFileSystem(lowerLayerFs, upperLayerFs);
lowerLayerFs.CreateDirectory("/dir").ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir").ThrowIfFailure();
lowerLayerFs.CreateDirectory("/dir2").ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir2").ThrowIfFailure();
lowerLayerFs.CreateDirectory("/dir3").ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir3").ThrowIfFailure();
lowerLayerFs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure();
lowerLayerFs.CreateDirectory("/dir2".ToU8Span()).ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir2".ToU8Span()).ThrowIfFailure();
lowerLayerFs.CreateDirectory("/dir3".ToU8Span()).ThrowIfFailure();
upperLayerFs.CreateDirectory("/dir3".ToU8Span()).ThrowIfFailure();
lowerLayerFs.CreateDirectory("/lowerDir").ThrowIfFailure();
upperLayerFs.CreateDirectory("/upperDir").ThrowIfFailure();
lowerLayerFs.CreateDirectory("/lowerDir".ToU8Span()).ThrowIfFailure();
upperLayerFs.CreateDirectory("/upperDir".ToU8Span()).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir/replacedFile".ToU8Span(), 1, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir/replacedFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir2/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir2/upperFile", 0, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir2/lowerFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir2/upperFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir3/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir3/upperFile", 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir3/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir3/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir3/lowerFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir3/upperFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/dir3/replacedFile".ToU8Span(), 1, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateFile("/dir3/replacedFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/replacedWithDir", 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateDirectory("/replacedWithDir").ThrowIfFailure();
upperLayerFs.CreateFile("/replacedWithDir/subFile", 0, CreateFileOptions.None).ThrowIfFailure();
lowerLayerFs.CreateFile("/replacedWithDir".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
upperLayerFs.CreateDirectory("/replacedWithDir".ToU8Span()).ThrowIfFailure();
upperLayerFs.CreateFile("/replacedWithDir/subFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
return layeredFs;
}
@ -56,7 +56,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Result(ResultFs.PathNotFound, fs.OpenFile(out _, "/fakefile", OpenMode.All));
Assert.Result(ResultFs.PathNotFound, fs.OpenFile(out _, "/fakefile".ToU8Span(), OpenMode.All));
}
[Fact]
@ -64,7 +64,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile", OpenMode.All));
Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile".ToU8Span(), OpenMode.All));
Assert.Success(file.GetSize(out long fileSize));
Assert.Equal(2, fileSize);
@ -75,8 +75,8 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile", OpenMode.All));
Assert.Success(fs.OpenFile(out _, "/dir2/upperFile", OpenMode.All));
Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile".ToU8Span(), OpenMode.All));
Assert.Success(fs.OpenFile(out _, "/dir2/upperFile".ToU8Span(), OpenMode.All));
}
[Fact]
@ -84,7 +84,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(out _, "/fakedir", OpenDirectoryMode.All));
Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(out _, "/fakedir".ToU8Span(), OpenDirectoryMode.All));
}
[Fact]
@ -92,7 +92,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir".ToU8Span(), OpenDirectoryMode.All));
Assert.Equal(typeof(InMemoryFileSystem), dir.GetType().DeclaringType);
}
@ -101,7 +101,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir".ToU8Span(), OpenDirectoryMode.All));
Assert.Equal(typeof(LayeredFileSystem), dir.GetType().DeclaringType);
}
@ -110,8 +110,8 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.GetEntryType(out _, "/dir2/lowerFile"));
Assert.Success(fs.GetEntryType(out _, "/dir2/upperFile"));
Assert.Success(fs.GetEntryType(out _, "/dir2/lowerFile".ToU8Span()));
Assert.Success(fs.GetEntryType(out _, "/dir2/upperFile".ToU8Span()));
}
[Fact]
@ -120,7 +120,7 @@ namespace LibHac.Tests.Fs
IFileSystem fs = CreateFileSystem();
Span<DirectoryEntry> entries = stackalloc DirectoryEntry[4];
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.Read(out long entriesRead, entries));
Assert.Equal(3, entriesRead);
@ -132,7 +132,7 @@ namespace LibHac.Tests.Fs
IFileSystem fs = CreateFileSystem();
var entry = new DirectoryEntry();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.Read(out _, SpanHelpers.AsSpan(ref entry)));
Assert.Equal("replacedFile", StringUtils.Utf8ZToString(entry.Name));
@ -145,7 +145,7 @@ namespace LibHac.Tests.Fs
IFileSystem fs = CreateEmptyFileSystem();
var entry = new DirectoryEntry();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref entry)));
Assert.Equal(0, entriesRead);
@ -156,7 +156,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateFileSystem();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.GetEntryCount(out long entryCount));
Assert.Equal(3, entryCount);
@ -168,7 +168,7 @@ namespace LibHac.Tests.Fs
IFileSystem fs = CreateFileSystem();
var entry = new DirectoryEntry();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All));
// Read all entries
long entriesRead;
@ -186,7 +186,7 @@ namespace LibHac.Tests.Fs
{
IFileSystem fs = CreateEmptyFileSystem();
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All));
Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All));
Assert.Success(directory.GetEntryCount(out long entryCount));
Assert.Equal(0, entryCount);

View File

@ -16,8 +16,8 @@ namespace LibHac.Tests.Fs
private (IFileSystem baseFs, IFileSystem subDirFs) CreateFileSystemInternal()
{
var baseFs = new InMemoryFileSystem();
baseFs.CreateDirectory("/sub");
baseFs.CreateDirectory("/sub/path");
baseFs.CreateDirectory("/sub".ToU8Span());
baseFs.CreateDirectory("/sub/path".ToU8Span());
SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subFs, baseFs, "/sub/path".ToU8String()).ThrowIfFailure();
return (baseFs, subFs);
@ -28,8 +28,8 @@ namespace LibHac.Tests.Fs
{
(IFileSystem baseFs, IFileSystem subDirFs) = CreateFileSystemInternal();
subDirFs.CreateFile("/file", 0, CreateFileOptions.None);
Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/file");
subDirFs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None);
Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/file".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.File, type);
@ -40,8 +40,8 @@ namespace LibHac.Tests.Fs
{
(IFileSystem baseFs, IFileSystem subDirFs) = CreateFileSystemInternal();
subDirFs.CreateDirectory("/dir");
Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/dir");
subDirFs.CreateDirectory("/dir".ToU8Span());
Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/dir".ToU8Span());
Assert.True(rc.IsSuccess());
Assert.Equal(DirectoryEntryType.Directory, type);