diff --git a/src/LibHac/Fs/FileSystemManager.cs b/src/LibHac/Fs/FileSystemManager.cs index a6ffe2fd..710e3ab0 100644 --- a/src/LibHac/Fs/FileSystemManager.cs +++ b/src/LibHac/Fs/FileSystemManager.cs @@ -138,7 +138,7 @@ namespace LibHac.Fs return new DirectoryHandle(dir); } - long GetFreeSpaceSize(string path) + public long GetFreeSpaceSize(string path) { FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) .ThrowIfFailure(); @@ -146,7 +146,7 @@ namespace LibHac.Fs return fileSystem.GetFreeSpaceSize(subPath.ToString()); } - long GetTotalSpaceSize(string path) + public long GetTotalSpaceSize(string path) { FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) .ThrowIfFailure(); @@ -154,7 +154,7 @@ namespace LibHac.Fs return fileSystem.GetTotalSpaceSize(subPath.ToString()); } - FileTimeStampRaw GetFileTimeStamp(string path) + public FileTimeStampRaw GetFileTimeStamp(string path) { FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) .ThrowIfFailure(); diff --git a/src/LibHac/Fs/PathTools.cs b/src/LibHac/Fs/PathTools.cs index 45b2e26d..129eb5b2 100644 --- a/src/LibHac/Fs/PathTools.cs +++ b/src/LibHac/Fs/PathTools.cs @@ -230,6 +230,7 @@ namespace LibHac.Fs switch (state) { case NormalizeState.Initial when c == '/': state = NormalizeState.Delimiter; break; + case NormalizeState.Initial when IsValidMountNameChar(c): state = NormalizeState.MountName; break; case NormalizeState.Initial: return false; case NormalizeState.Normal when c == '/': state = NormalizeState.Delimiter; break; @@ -244,6 +245,13 @@ namespace LibHac.Fs case NormalizeState.DoubleDot when c == '/': return false; case NormalizeState.DoubleDot: state = NormalizeState.Normal; break; + + case NormalizeState.MountName when IsValidMountNameChar(c): break; + case NormalizeState.MountName when c == ':': state = NormalizeState.MountDelimiter; break; + case NormalizeState.MountName: return false; + + case NormalizeState.MountDelimiter when c == '/': state = NormalizeState.Delimiter; break; + case NormalizeState.MountDelimiter: return false; } } @@ -259,6 +267,7 @@ namespace LibHac.Fs switch (state) { case NormalizeState.Initial when c == '/': state = NormalizeState.Delimiter; break; + case NormalizeState.Initial when IsValidMountNameChar(c): state = NormalizeState.MountName; break; case NormalizeState.Initial: return false; case NormalizeState.Normal when c == '/': state = NormalizeState.Delimiter; break; @@ -273,6 +282,13 @@ namespace LibHac.Fs case NormalizeState.DoubleDot when c == '/': return false; case NormalizeState.DoubleDot: state = NormalizeState.Normal; break; + + case NormalizeState.MountName when IsValidMountNameChar(c): break; + case NormalizeState.MountName when c == ':': state = NormalizeState.MountDelimiter; break; + case NormalizeState.MountName: return false; + + case NormalizeState.MountDelimiter when c == '/': state = NormalizeState.Delimiter; break; + case NormalizeState.MountDelimiter: return false; } } @@ -365,13 +381,23 @@ namespace LibHac.Fs return ResultFsInvalidMountName; } + private static bool IsValidMountNameChar(char c) + { + c |= (char)0x20; + return c >= 'a' && c <= 'z'; + } + + private static bool IsValidMountNameChar(byte c) => IsValidMountNameChar((char)c); + private enum NormalizeState { Initial, Normal, Delimiter, Dot, - DoubleDot + DoubleDot, + MountName, + MountDelimiter } } } diff --git a/tests/LibHac.Tests/PathToolsTests.cs b/tests/LibHac.Tests/PathToolsTests.cs index 1b95bbd8..c3802d04 100644 --- a/tests/LibHac.Tests/PathToolsTests.cs +++ b/tests/LibHac.Tests/PathToolsTests.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using LibHac.Fs; using Xunit; @@ -68,62 +70,9 @@ namespace LibHac.Tests new object[] {"/a/b/c/", "/a/b/cd", false}, }; - public static object[][] IsNormalizedTestItems = - { - new object[] {"", "/"}, - new object[] {"/"}, - new object[] {"/a/b/c"}, - new object[] {"/a/c"}, - new object[] {"/a/b"}, - new object[] {"/a/b/c"}, - new object[] {"/"}, - new object[] {"/a/b/c"}, + public static object[][] IsNormalizedTestItems = GetNormalizedPaths(true); - new object[] {"/a/b/c/"}, - new object[] {"/a/c/"}, - new object[] {"/c/"}, - - new object[] {"/a"}, - - new object[] {"a:/a/b/c"}, - new object[] {"mount:/a/c"}, - new object[] {"mount:/"}, - }; - - public static object[][] IsNotNormalizedTestItems = - { - new object[] {""}, - new object[] {"/."}, - new object[] {"/a/b/../c", "/a/c"}, - new object[] {"/a/b/c/..", "/a/b"}, - new object[] {"/a/b/c/.", "/a/b/c"}, - new object[] {"/a/../../..", "/"}, - new object[] {"/a/../../../a/b/c", "/a/b/c"}, - new object[] {"//a/b//.//c", "/a/b/c"}, - new object[] {"/../a/b/c/.", "/a/b/c"}, - new object[] {"/./a/b/c/.", "/a/b/c"}, - - new object[] {"/a/b/c/", "/a/b/c/"}, - new object[] {"/a/./b/../c/", "/a/c/"}, - new object[] {"/./b/../c/", "/c/"}, - new object[] {"/a/../../../", "/"}, - new object[] {"//a/b//.//c/", "/a/b/c/"}, - new object[] {"/tmp/../", "/"}, - - new object[] {"a", "/a"}, - new object[] {"a/../../../a/b/c", "/a/b/c"}, - new object[] {"./b/../c/", "/c/"}, - new object[] {".", "/"}, - new object[] {"..", "/"}, - new object[] {"../a/b/c/.", "/a/b/c"}, - new object[] {"./a/b/c/.", "/a/b/c"}, - - new object[] {"a:/a/b/c", "a:/a/b/c"}, - new object[] {"mount:/a/b/../c", "mount:/a/c"}, - new object[] {"mount:/a/b/../c", "mount:/a/c"}, - new object[] {"mount:", "mount:/"}, - new object[] {"abc:/a/../../../a/b/c", "abc:/a/b/c"}, - }; + public static object[][] IsNotNormalizedTestItems = GetNormalizedPaths(false); [Theory] [MemberData(nameof(NormalizedPathTestItems))] @@ -135,12 +84,17 @@ namespace LibHac.Tests } [Theory] - [MemberData(nameof(NormalizedPathTestItems))] - public static void IsNormalized(string path, string expected) + [MemberData(nameof(IsNormalizedTestItems))] + public static void IsNormalized(string path) { - string actual = PathTools.Normalize(path); + Assert.True(PathTools.IsNormalized(path.AsSpan())); + } - Assert.Equal(expected, actual); + [Theory] + [MemberData(nameof(IsNotNormalizedTestItems))] + public static void IsNotNormalized(string path) + { + Assert.False(PathTools.IsNormalized(path.AsSpan())); } [Theory] @@ -151,5 +105,24 @@ namespace LibHac.Tests Assert.Equal(expected, actual); } + + private static object[][] GetNormalizedPaths(bool getNormalized) + { + var normalizedPaths = new HashSet(); + var notNormalizedPaths = new HashSet(); + + foreach (object[] pair in NormalizedPathTestItems) + { + string pathNotNorm = (string)pair[0]; + string pathNorm = (string)pair[1]; + + if (pathNorm != pathNotNorm) notNormalizedPaths.Add(pathNotNorm); + normalizedPaths.Add(pathNorm); + } + + HashSet paths = getNormalized ? normalizedPaths : notNormalizedPaths; + + return paths.Select(x => new object[] { x }).ToArray(); + } } }