mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Remove old path code
This commit is contained in:
parent
aad87ec845
commit
689549fed7
@ -23,7 +23,7 @@ namespace LibHac.Fs.Common
|
||||
{
|
||||
Span<byte> pathBuffer = path.GetWriteBufferLength() != 0 ? path.GetWriteBuffer() : Span<byte>.Empty;
|
||||
|
||||
int windowsSkipLength = WindowsPath12.GetWindowsSkipLength(pathBuffer);
|
||||
int windowsSkipLength = WindowsPath.GetWindowsSkipLength(pathBuffer);
|
||||
_buffer = pathBuffer.Slice(windowsSkipLength);
|
||||
|
||||
if (windowsSkipLength != 0)
|
||||
|
@ -310,7 +310,7 @@ namespace LibHac.Fs
|
||||
Result rc = Initialize(path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (_string.At(0) != NullTerminator && !WindowsPath12.IsWindowsPath(_string, false) &&
|
||||
if (_string.At(0) != NullTerminator && !WindowsPath.IsWindowsPath(_string, false) &&
|
||||
_string.At(0) != DirectorySeparator)
|
||||
{
|
||||
var flags = new PathFlags();
|
||||
@ -319,7 +319,7 @@ namespace LibHac.Fs
|
||||
rc = Normalize(flags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else if (WindowsPath12.IsWindowsPath(_string, true))
|
||||
else if (WindowsPath.IsWindowsPath(_string, true))
|
||||
{
|
||||
var flags = new PathFlags();
|
||||
flags.AllowWindowsPath();
|
||||
@ -329,7 +329,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = PathNormalizer12.IsNormalized(out _isNormalized, out _, _string);
|
||||
rc = PathNormalizer.IsNormalized(out _isNormalized, out _, _string);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ namespace LibHac.Fs
|
||||
Result rc = Initialize(path, length);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (_string.At(0) != NullTerminator && !WindowsPath12.IsWindowsPath(_string, false) &&
|
||||
if (_string.At(0) != NullTerminator && !WindowsPath.IsWindowsPath(_string, false) &&
|
||||
_string.At(0) != DirectorySeparator)
|
||||
{
|
||||
var flags = new PathFlags();
|
||||
@ -363,7 +363,7 @@ namespace LibHac.Fs
|
||||
rc = Normalize(flags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else if (WindowsPath12.IsWindowsPath(_string, true))
|
||||
else if (WindowsPath.IsWindowsPath(_string, true))
|
||||
{
|
||||
var flags = new PathFlags();
|
||||
flags.AllowWindowsPath();
|
||||
@ -373,7 +373,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = PathNormalizer12.IsNormalized(out _isNormalized, out _, _string);
|
||||
rc = PathNormalizer.IsNormalized(out _isNormalized, out _, _string);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ namespace LibHac.Fs
|
||||
|
||||
if (_writeBufferLength > 1)
|
||||
{
|
||||
PathUtility12.Replace(GetWriteBuffer().Slice(0, _writeBufferLength - 1), AltDirectorySeparator,
|
||||
PathUtility.Replace(GetWriteBuffer().Slice(0, _writeBufferLength - 1), AltDirectorySeparator,
|
||||
DirectorySeparator);
|
||||
}
|
||||
|
||||
@ -468,7 +468,7 @@ namespace LibHac.Fs
|
||||
if (parent.Length == 0 || parent[0] == NullTerminator)
|
||||
return Result.Success;
|
||||
|
||||
if (WindowsPath12.IsWindowsPath(_string, false))
|
||||
if (WindowsPath.IsWindowsPath(_string, false))
|
||||
return ResultFs.NotImplemented.Log();
|
||||
|
||||
// Remove a trailing separator from the parent and a leading one from the child so we can
|
||||
@ -631,6 +631,9 @@ namespace LibHac.Fs
|
||||
if (childBytesCopied != childLength)
|
||||
return ResultFs.UnexpectedInPathA.Log();
|
||||
|
||||
// Note: Nintendo does not reset the "_isNormalized" field on the Path.
|
||||
// This can result in the field and the actual normalization state being out of sync.
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
@ -755,10 +758,10 @@ namespace LibHac.Fs
|
||||
|
||||
int bufferLength = _writeBufferLength;
|
||||
|
||||
if (flags.IsRelativePathAllowed() && PathUtility12.IsPathRelative(_string))
|
||||
if (flags.IsRelativePathAllowed() && PathUtility.IsPathRelative(_string))
|
||||
bufferLength += 2;
|
||||
|
||||
if (flags.IsWindowsPathAllowed() && WindowsPath12.IsWindowsPath(_string, true))
|
||||
if (flags.IsWindowsPathAllowed() && WindowsPath.IsWindowsPath(_string, true))
|
||||
bufferLength += 1;
|
||||
|
||||
int alignedBufferLength = Alignment.AlignUpPow2(bufferLength, WriteBufferAlignmentLength);
|
||||
@ -794,7 +797,7 @@ namespace LibHac.Fs
|
||||
{
|
||||
public static Result SetUpFixedPath(ref Path path, ReadOnlySpan<byte> pathBuffer)
|
||||
{
|
||||
Result rc = PathNormalizer12.IsNormalized(out bool isNormalized, out _, pathBuffer);
|
||||
Result rc = PathNormalizer.IsNormalized(out bool isNormalized, out _, pathBuffer);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!isNormalized)
|
||||
|
@ -11,6 +11,10 @@ using static LibHac.Fs.StringTraits;
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for working with path formatting and normalization.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public static class PathFormatter
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -133,7 +137,7 @@ namespace LibHac.Fs
|
||||
|
||||
currentPath = path.Slice(1);
|
||||
}
|
||||
else if (path.Length != 0 && WindowsPath12.IsWindowsDrive(path.Slice(1)))
|
||||
else if (path.Length != 0 && WindowsPath.IsWindowsDrive(path.Slice(1)))
|
||||
{
|
||||
if (normalizeBuffer.Length == 0)
|
||||
return ResultFs.NotNormalized.Log();
|
||||
@ -142,7 +146,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
if (WindowsPath12.IsWindowsDrive(currentPath))
|
||||
if (WindowsPath.IsWindowsDrive(currentPath))
|
||||
{
|
||||
int winPathLength;
|
||||
for (winPathLength = 2; currentPath.At(winPathLength) != NullTerminator; winPathLength++)
|
||||
@ -170,7 +174,7 @@ namespace LibHac.Fs
|
||||
|
||||
currentPath.Slice(0, winPathLength).CopyTo(normalizeBuffer);
|
||||
normalizeBuffer[winPathLength] = NullTerminator;
|
||||
PathUtility12.Replace(normalizeBuffer.Slice(0, winPathLength), AltDirectorySeparator,
|
||||
PathUtility.Replace(normalizeBuffer.Slice(0, winPathLength), AltDirectorySeparator,
|
||||
DirectorySeparator);
|
||||
}
|
||||
|
||||
@ -179,11 +183,11 @@ namespace LibHac.Fs
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (WindowsPath12.IsDosDevicePath(currentPath))
|
||||
if (WindowsPath.IsDosDevicePath(currentPath))
|
||||
{
|
||||
int dosPathLength = WindowsPath12.GetDosDevicePathPrefixLength();
|
||||
int dosPathLength = WindowsPath.GetDosDevicePathPrefixLength();
|
||||
|
||||
if (WindowsPath12.IsWindowsDrive(currentPath.Slice(dosPathLength)))
|
||||
if (WindowsPath.IsWindowsDrive(currentPath.Slice(dosPathLength)))
|
||||
{
|
||||
dosPathLength += 2;
|
||||
}
|
||||
@ -199,7 +203,7 @@ namespace LibHac.Fs
|
||||
|
||||
currentPath.Slice(0, dosPathLength).CopyTo(normalizeBuffer);
|
||||
normalizeBuffer[dosPathLength] = NullTerminator;
|
||||
PathUtility12.Replace(normalizeBuffer.Slice(0, dosPathLength), DirectorySeparator,
|
||||
PathUtility.Replace(normalizeBuffer.Slice(0, dosPathLength), DirectorySeparator,
|
||||
AltDirectorySeparator);
|
||||
}
|
||||
|
||||
@ -208,7 +212,7 @@ namespace LibHac.Fs
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (WindowsPath12.IsUncPath(currentPath, false, true))
|
||||
if (WindowsPath.IsUncPath(currentPath, false, true))
|
||||
{
|
||||
Result rc;
|
||||
|
||||
@ -274,7 +278,7 @@ namespace LibHac.Fs
|
||||
|
||||
currentPath.Slice(0, uncPrefixLength).CopyTo(normalizeBuffer);
|
||||
normalizeBuffer[uncPrefixLength] = NullTerminator;
|
||||
PathUtility12.Replace(normalizeBuffer.Slice(0, uncPrefixLength), DirectorySeparator, AltDirectorySeparator);
|
||||
PathUtility.Replace(normalizeBuffer.Slice(0, uncPrefixLength), DirectorySeparator, AltDirectorySeparator);
|
||||
}
|
||||
|
||||
newPath = finalPath;
|
||||
@ -364,7 +368,7 @@ namespace LibHac.Fs
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out isNormalized, out normalizedLength);
|
||||
|
||||
Result rc = PathUtility12.CheckUtf8(path);
|
||||
Result rc = PathUtility.CheckUtf8(path);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ReadOnlySpan<byte> buffer = path;
|
||||
@ -388,7 +392,7 @@ namespace LibHac.Fs
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
}
|
||||
|
||||
if (WindowsPath12.IsWindowsPath(path, false) && !flags.IsWindowsPathAllowed())
|
||||
if (WindowsPath.IsWindowsPath(path, false) && !flags.IsWindowsPathAllowed())
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
bool hasMountName = false;
|
||||
@ -405,10 +409,10 @@ namespace LibHac.Fs
|
||||
hasMountName = true;
|
||||
}
|
||||
|
||||
if (buffer.At(0) != DirectorySeparator && !PathUtility12.IsPathStartWithCurrentDirectory(buffer) &&
|
||||
!WindowsPath12.IsWindowsPath(buffer, false))
|
||||
if (buffer.At(0) != DirectorySeparator && !PathUtility.IsPathStartWithCurrentDirectory(buffer) &&
|
||||
!WindowsPath.IsWindowsPath(buffer, false))
|
||||
{
|
||||
if (!flags.IsRelativePathAllowed() || !PathUtility12.CheckInvalidCharacter(buffer.At(0)).IsSuccess())
|
||||
if (!flags.IsRelativePathAllowed() || !PathUtility.CheckInvalidCharacter(buffer.At(0)).IsSuccess())
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
isNormalized = false;
|
||||
@ -475,10 +479,10 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
if (PathNormalizer12.IsParentDirectoryPathReplacementNeeded(buffer))
|
||||
if (PathNormalizer.IsParentDirectoryPathReplacementNeeded(buffer))
|
||||
return ResultFs.DirectoryUnobtainable.Log();
|
||||
|
||||
rc = PathUtility12.CheckInvalidBackslash(out bool isBackslashContained, buffer,
|
||||
rc = PathUtility.CheckInvalidBackslash(out bool isBackslashContained, buffer,
|
||||
flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -488,7 +492,7 @@ namespace LibHac.Fs
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
rc = PathNormalizer12.IsNormalized(out isNormalized, out int length, buffer);
|
||||
rc = PathNormalizer.IsNormalized(out isNormalized, out int length, buffer);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
totalLength += length;
|
||||
@ -528,10 +532,10 @@ namespace LibHac.Fs
|
||||
|
||||
bool isDriveRelative = false;
|
||||
|
||||
if (src.At(0) != DirectorySeparator && !PathUtility12.IsPathStartWithCurrentDirectory(src) &&
|
||||
!WindowsPath12.IsWindowsPath(src, false))
|
||||
if (src.At(0) != DirectorySeparator && !PathUtility.IsPathStartWithCurrentDirectory(src) &&
|
||||
!WindowsPath.IsWindowsPath(src, false))
|
||||
{
|
||||
if (!flags.IsRelativePathAllowed() || !PathUtility12.CheckInvalidCharacter(src.At(0)).IsSuccess())
|
||||
if (!flags.IsRelativePathAllowed() || !PathUtility.CheckInvalidCharacter(src.At(0)).IsSuccess())
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
outputBuffer[currentPos++] = Dot;
|
||||
@ -589,7 +593,7 @@ namespace LibHac.Fs
|
||||
isWindowsPath = true;
|
||||
}
|
||||
|
||||
rc = PathUtility12.CheckInvalidBackslash(out bool isBackslashContained, src,
|
||||
rc = PathUtility.CheckInvalidBackslash(out bool isBackslashContained, src,
|
||||
flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
@ -601,7 +605,7 @@ namespace LibHac.Fs
|
||||
srcBufferSlashReplaced = ArrayPool<byte>.Shared.Rent(path.Length);
|
||||
|
||||
StringUtils.Copy(srcBufferSlashReplaced, path);
|
||||
PathUtility12.Replace(srcBufferSlashReplaced, AltDirectorySeparator, DirectorySeparator);
|
||||
PathUtility.Replace(srcBufferSlashReplaced, AltDirectorySeparator, DirectorySeparator);
|
||||
|
||||
int srcOffset = (int)Unsafe.ByteOffset(ref MemoryMarshal.GetReference(path),
|
||||
ref MemoryMarshal.GetReference(src));
|
||||
@ -609,7 +613,7 @@ namespace LibHac.Fs
|
||||
src = srcBufferSlashReplaced.AsSpan(srcOffset);
|
||||
}
|
||||
|
||||
rc = PathNormalizer12.Normalize(outputBuffer.Slice(currentPos), out _, src, isWindowsPath, isDriveRelative);
|
||||
rc = PathNormalizer.Normalize(outputBuffer.Slice(currentPos), out _, src, isWindowsPath, isDriveRelative);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return Result.Success;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,368 +0,0 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.FsSystem;
|
||||
using static LibHac.Fs.PathUtility12;
|
||||
using static LibHac.Fs.StringTraits;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public static class PathNormalizer12
|
||||
{
|
||||
private enum PathState
|
||||
{
|
||||
Initial,
|
||||
Normal,
|
||||
FirstSeparator,
|
||||
Separator,
|
||||
CurrentDir,
|
||||
ParentDir
|
||||
}
|
||||
|
||||
public static Result Normalize(Span<byte> outputBuffer, out int length, ReadOnlySpan<byte> path, bool isWindowsPath,
|
||||
bool isDriveRelativePath)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out length);
|
||||
|
||||
ReadOnlySpan<byte> currentPath = path;
|
||||
int totalLength = 0;
|
||||
int i = 0;
|
||||
|
||||
if (!IsSeparator(path.At(0)))
|
||||
{
|
||||
if (!isDriveRelativePath)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
outputBuffer[totalLength++] = DirectorySeparator;
|
||||
}
|
||||
|
||||
var convertedPath = new RentedArray<byte>();
|
||||
try
|
||||
{
|
||||
// Check if parent directory path replacement is needed.
|
||||
if (IsParentDirectoryPathReplacementNeeded(currentPath))
|
||||
{
|
||||
// Allocate a buffer to hold the replacement path.
|
||||
convertedPath = new RentedArray<byte>(PathTools.MaxPathLength + 1);
|
||||
|
||||
// Replace the path.
|
||||
ReplaceParentDirectoryPath(convertedPath.Span, currentPath);
|
||||
|
||||
// Set current path to be the replacement path.
|
||||
currentPath = new U8Span(convertedPath.Span);
|
||||
}
|
||||
|
||||
bool skipNextSeparator = false;
|
||||
|
||||
while (!IsNul(currentPath.At(i)))
|
||||
{
|
||||
if (IsSeparator(currentPath[i]))
|
||||
{
|
||||
do
|
||||
{
|
||||
i++;
|
||||
} while (IsSeparator(currentPath.At(i)));
|
||||
|
||||
if (IsNul(currentPath.At(i)))
|
||||
break;
|
||||
|
||||
if (!skipNextSeparator)
|
||||
{
|
||||
if (totalLength + 1 == outputBuffer.Length)
|
||||
{
|
||||
outputBuffer[totalLength] = NullTerminator;
|
||||
length = totalLength;
|
||||
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
outputBuffer[totalLength++] = DirectorySeparator;
|
||||
}
|
||||
|
||||
skipNextSeparator = false;
|
||||
}
|
||||
|
||||
int dirLen = 0;
|
||||
while (!IsSeparator(currentPath.At(i + dirLen)) && !IsNul(currentPath.At(i + dirLen)))
|
||||
{
|
||||
dirLen++;
|
||||
}
|
||||
|
||||
if (IsCurrentDirectory(currentPath.Slice(i)))
|
||||
{
|
||||
skipNextSeparator = true;
|
||||
}
|
||||
else if (IsParentDirectory(currentPath.Slice(i)))
|
||||
{
|
||||
Assert.SdkAssert(outputBuffer[totalLength - 1] == DirectorySeparator);
|
||||
|
||||
if (!isWindowsPath)
|
||||
Assert.SdkAssert(outputBuffer[0] == DirectorySeparator);
|
||||
|
||||
if (totalLength == 1)
|
||||
{
|
||||
if (!isWindowsPath)
|
||||
return ResultFs.DirectoryUnobtainable.Log();
|
||||
|
||||
totalLength--;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalLength -= 2;
|
||||
|
||||
do
|
||||
{
|
||||
if (outputBuffer[totalLength] == DirectorySeparator)
|
||||
break;
|
||||
|
||||
totalLength--;
|
||||
} while (totalLength != 0);
|
||||
}
|
||||
|
||||
if (!isWindowsPath)
|
||||
Assert.SdkAssert(outputBuffer[totalLength] == DirectorySeparator);
|
||||
|
||||
Assert.SdkAssert(totalLength < outputBuffer.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalLength + dirLen + 1 > outputBuffer.Length)
|
||||
{
|
||||
int copyLen = outputBuffer.Length - 1 - totalLength;
|
||||
|
||||
for (int j = 0; j < copyLen; j++)
|
||||
{
|
||||
outputBuffer[totalLength++] = currentPath[i + j];
|
||||
}
|
||||
|
||||
outputBuffer[totalLength] = NullTerminator;
|
||||
length = totalLength;
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
for (int j = 0; j < dirLen; j++)
|
||||
{
|
||||
outputBuffer[totalLength++] = currentPath[i + j];
|
||||
}
|
||||
}
|
||||
|
||||
i += dirLen;
|
||||
}
|
||||
|
||||
if (skipNextSeparator)
|
||||
totalLength--;
|
||||
|
||||
if (totalLength == 0 && outputBuffer.Length != 0)
|
||||
{
|
||||
totalLength = 1;
|
||||
outputBuffer[0] = DirectorySeparator;
|
||||
}
|
||||
|
||||
// Note: This bug is in the original code. They probably meant to put "totalLength + 1"
|
||||
if (totalLength - 1 > outputBuffer.Length)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
outputBuffer[totalLength] = NullTerminator;
|
||||
|
||||
Result rc = IsNormalized(out bool isNormalized, out _, outputBuffer);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Assert.SdkAssert(isNormalized);
|
||||
|
||||
length = totalLength;
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
convertedPath.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given path is normalized. Path must be a basic path, starting with a directory separator
|
||||
/// and not containing any sort of prefix such as a mount name.
|
||||
/// </summary>
|
||||
/// <param name="isNormalized">When this function returns <see cref="Result.Success"/>,
|
||||
/// contains <see langword="true"/> if the path is normalized or <see langword="false"/> if it is not.
|
||||
/// Contents are undefined if the function does not return <see cref="Result.Success"/>.
|
||||
/// </param>
|
||||
/// <param name="length">When this function returns <see cref="Result.Success"/> and
|
||||
/// <paramref name="isNormalized"/> is <see langword="true"/>, contains the length of the normalized path.
|
||||
/// Contents are undefined if the function does not return <see cref="Result.Success"/>
|
||||
/// or <paramref name="isNormalized"/> is <see langword="false"/>.
|
||||
/// </param>
|
||||
/// <param name="path">The path to check.</param>
|
||||
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
|
||||
/// <see cref="ResultFs.InvalidCharacter"/>: The path contains an invalid character.<br/>
|
||||
/// <see cref="ResultFs.InvalidPathFormat"/>: The path is not in a valid format.</returns>
|
||||
public static Result IsNormalized(out bool isNormalized, out int length, ReadOnlySpan<byte> path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out isNormalized, out length);
|
||||
|
||||
var state = PathState.Initial;
|
||||
int pathLength = 0;
|
||||
|
||||
for (int i = 0; i < path.Length; i++)
|
||||
{
|
||||
byte c = path[i];
|
||||
if (c == NullTerminator) break;
|
||||
|
||||
pathLength++;
|
||||
|
||||
if (state != PathState.Initial)
|
||||
{
|
||||
Result rc = CheckInvalidCharacter(c);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PathState.Initial:
|
||||
if (c != DirectorySeparator)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
state = PathState.FirstSeparator;
|
||||
|
||||
break;
|
||||
case PathState.Normal:
|
||||
|
||||
if (c == DirectorySeparator)
|
||||
state = PathState.Separator;
|
||||
|
||||
break;
|
||||
case PathState.FirstSeparator:
|
||||
case PathState.Separator:
|
||||
if (c == DirectorySeparator)
|
||||
{
|
||||
isNormalized = false;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
state = c == Dot ? PathState.CurrentDir : PathState.Normal;
|
||||
break;
|
||||
case PathState.CurrentDir:
|
||||
if (c == DirectorySeparator)
|
||||
{
|
||||
isNormalized = false;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
state = c == Dot ? PathState.ParentDir : PathState.Normal;
|
||||
break;
|
||||
case PathState.ParentDir:
|
||||
if (c == DirectorySeparator)
|
||||
{
|
||||
isNormalized = false;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
state = PathState.Normal;
|
||||
break;
|
||||
// ReSharper disable once UnreachableSwitchCaseDueToIntegerAnalysis
|
||||
default:
|
||||
Abort.UnexpectedDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PathState.Initial:
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
case PathState.Normal:
|
||||
case PathState.FirstSeparator:
|
||||
isNormalized = true;
|
||||
break;
|
||||
case PathState.Separator:
|
||||
case PathState.CurrentDir:
|
||||
case PathState.ParentDir:
|
||||
isNormalized = false;
|
||||
break;
|
||||
// ReSharper disable once UnreachableSwitchCaseDueToIntegerAnalysis
|
||||
default:
|
||||
Abort.UnexpectedDefault();
|
||||
break;
|
||||
}
|
||||
|
||||
length = pathLength;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a path begins with / or \ and contains any of these patterns:
|
||||
/// "/..\", "\..\", "\../", "\..0" where '0' is the null terminator.
|
||||
/// </summary>
|
||||
public static bool IsParentDirectoryPathReplacementNeeded(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (path.Length == 0 || (path[0] != DirectorySeparator && path[0] != AltDirectorySeparator))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < path.Length - 2 && path[i] != NullTerminator; i++)
|
||||
{
|
||||
byte c3 = path.At(i + 3);
|
||||
|
||||
if (path[i] == AltDirectorySeparator &&
|
||||
path[i + 1] == Dot &&
|
||||
path[i + 2] == Dot &&
|
||||
(c3 == DirectorySeparator || c3 == AltDirectorySeparator || c3 == NullTerminator))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((path[i] == DirectorySeparator || path[i] == AltDirectorySeparator) &&
|
||||
path[i + 1] == Dot &&
|
||||
path[i + 2] == Dot &&
|
||||
c3 == AltDirectorySeparator)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ReplaceParentDirectoryPath(Span<byte> dest, ReadOnlySpan<byte> source)
|
||||
{
|
||||
dest[0] = DirectorySeparator;
|
||||
|
||||
int i = 1;
|
||||
while (source.Length > i && source[i] != NullTerminator)
|
||||
{
|
||||
if (source.Length > i + 2 &&
|
||||
(source[i - 1] == DirectorySeparator || source[i - 1] == AltDirectorySeparator) &&
|
||||
source[i + 0] == Dot &&
|
||||
source[i + 1] == Dot &&
|
||||
(source[i + 2] == DirectorySeparator || source[i + 2] == AltDirectorySeparator))
|
||||
{
|
||||
dest[i - 1] = DirectorySeparator;
|
||||
dest[i + 0] = Dot;
|
||||
dest[i + 1] = Dot;
|
||||
dest[i + 2] = DirectorySeparator;
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (source.Length > i + 1 &&
|
||||
source[i - 1] == AltDirectorySeparator &&
|
||||
source[i + 0] == Dot &&
|
||||
source[i + 1] == Dot &&
|
||||
(source.Length == i + 2 || source[i + 2] == NullTerminator))
|
||||
{
|
||||
dest[i - 1] = DirectorySeparator;
|
||||
dest[i + 0] = Dot;
|
||||
dest[i + 1] = Dot;
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
dest[i] = source[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
dest[i] = NullTerminator;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +1,13 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Util;
|
||||
using static LibHac.Fs.StringTraits;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
internal struct PathUtilityGlobals
|
||||
{
|
||||
public PathVerifier PathVerifier;
|
||||
|
||||
public void Initialize(FileSystemClient _)
|
||||
{
|
||||
PathVerifier.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
internal struct PathVerifier
|
||||
{
|
||||
public void Initialize()
|
||||
{
|
||||
// Todo
|
||||
}
|
||||
|
||||
public static Result Verify(U8Span path, int maxPathLength, int maxNameLength)
|
||||
{
|
||||
Debug.Assert(!path.IsNull());
|
||||
|
||||
int nameLength = 0;
|
||||
|
||||
for (int i = 0; i < path.Length && i <= maxPathLength && nameLength <= maxNameLength; i++)
|
||||
{
|
||||
byte c = path[i];
|
||||
|
||||
if (c == 0)
|
||||
return Result.Success;
|
||||
|
||||
// todo: Compare path based on their Unicode code points
|
||||
|
||||
if (c == ':' || c == '*' || c == '?' || c == '<' || c == '>' || c == '|')
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
|
||||
nameLength++;
|
||||
if (c == '\\' || c == '/')
|
||||
{
|
||||
nameLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public static class PathUtility
|
||||
{
|
||||
public static void Replace(Span<byte> buffer, byte currentChar, byte newChar)
|
||||
@ -68,62 +23,223 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the extra functions that nn::fs::FspPathPrintf does on the string buffer.
|
||||
/// </summary>
|
||||
/// <param name="builder">The string builder to process.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public static Result ToSfPath(in this U8StringBuilder builder)
|
||||
public static bool IsCurrentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (builder.Overflowed)
|
||||
if (path.Length < 1)
|
||||
return false;
|
||||
|
||||
return path[0] == Dot &&
|
||||
(path.Length < 2 || path[1] == NullTerminator || path[1] == DirectorySeparator);
|
||||
}
|
||||
|
||||
public static bool IsParentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (path.Length < 2)
|
||||
return false;
|
||||
|
||||
return path[0] == Dot &&
|
||||
path[1] == Dot &&
|
||||
(path.Length < 3 || path[2] == NullTerminator || path[2] == DirectorySeparator);
|
||||
}
|
||||
|
||||
public static bool IsSeparator(byte c)
|
||||
{
|
||||
return c == DirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsNul(byte c)
|
||||
{
|
||||
return c == NullTerminator;
|
||||
}
|
||||
|
||||
public static Result ConvertToFspPath(out FspPath fspPath, ReadOnlySpan<byte> path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out fspPath);
|
||||
|
||||
int length = StringUtils.Copy(SpanHelpers.AsByteSpan(ref fspPath), path, PathTool.EntryNameLengthMax + 1);
|
||||
|
||||
if (length >= PathTool.EntryNameLengthMax + 1)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
Replace(builder.Buffer.Slice(builder.Capacity),
|
||||
AltDirectorySeparator,
|
||||
DirectorySeparator);
|
||||
Result rc = PathFormatter.SkipMountName(out ReadOnlySpan<byte> pathWithoutMountName, out _,
|
||||
new U8Span(path));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!WindowsPath.IsWindowsPath(pathWithoutMountName, true))
|
||||
{
|
||||
Replace(SpanHelpers.AsByteSpan(ref fspPath).Slice(0, 0x300), AltDirectorySeparator, DirectorySeparator);
|
||||
}
|
||||
else if (fspPath.Str[0] == DirectorySeparator && fspPath.Str[1] == DirectorySeparator)
|
||||
{
|
||||
SpanHelpers.AsByteSpan(ref fspPath)[0] = AltDirectorySeparator;
|
||||
SpanHelpers.AsByteSpan(ref fspPath)[1] = AltDirectorySeparator;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result VerifyPath(this FileSystemClient fs, U8Span path, int maxPathLength, int maxNameLength)
|
||||
public static bool IsDirectoryPath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return PathVerifier.Verify(path, maxPathLength, maxNameLength);
|
||||
}
|
||||
|
||||
public static bool IsSubPath(U8Span lhs, U8Span rhs)
|
||||
{
|
||||
Assert.SdkRequires(!lhs.IsNull());
|
||||
Assert.SdkRequires(!rhs.IsNull());
|
||||
|
||||
bool isUncLhs = WindowsPath.IsUnc(lhs);
|
||||
bool isUncRhs = WindowsPath.IsUnc(rhs);
|
||||
|
||||
if (isUncLhs && !isUncRhs || !isUncLhs && isUncRhs)
|
||||
if (path.Length < 1 || path[0] == NullTerminator)
|
||||
return false;
|
||||
|
||||
if (lhs.GetOrNull(0) == DirectorySeparator && lhs.GetOrNull(1) == NullTerminator &&
|
||||
rhs.GetOrNull(0) == DirectorySeparator && rhs.GetOrNull(1) != NullTerminator)
|
||||
int length = StringUtils.GetLength(path);
|
||||
return path[length - 1] == DirectorySeparator || path[length - 1] == AltDirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsDirectoryPath(in FspPath path)
|
||||
{
|
||||
return IsDirectoryPath(SpanHelpers.AsReadOnlyByteSpan(in path));
|
||||
}
|
||||
|
||||
public static Result CheckUtf8(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
uint utf8Buffer = 0;
|
||||
Span<byte> utf8BufferSpan = SpanHelpers.AsByteSpan(ref utf8Buffer);
|
||||
|
||||
ReadOnlySpan<byte> currentChar = path;
|
||||
|
||||
while (currentChar.Length > 0 && currentChar[0] != NullTerminator)
|
||||
{
|
||||
utf8BufferSpan.Clear();
|
||||
|
||||
CharacterEncodingResult result =
|
||||
CharacterEncoding.PickOutCharacterFromUtf8String(utf8BufferSpan, ref currentChar);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
result = CharacterEncoding.ConvertCharacterUtf8ToUtf32(out _, utf8BufferSpan);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckInvalidCharacter(byte c)
|
||||
{
|
||||
/*
|
||||
The optimized code is equivalent to this:
|
||||
|
||||
ReadOnlySpan<byte> invalidChars = new[]
|
||||
{(byte) ':', (byte) '*', (byte) '?', (byte) '<', (byte) '>', (byte) '|'};
|
||||
|
||||
for (int i = 0; i < invalidChars.Length; i++)
|
||||
{
|
||||
if (c == invalidChars[i])
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
*/
|
||||
|
||||
const ulong mask = (1ul << (byte)':') |
|
||||
(1ul << (byte)'*') |
|
||||
(1ul << (byte)'?') |
|
||||
(1ul << (byte)'<') |
|
||||
(1ul << (byte)'>');
|
||||
|
||||
if (c <= 0x3Fu && ((1ul << c) & mask) != 0 || c == (byte)'|')
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckInvalidBackslash(out bool containsBackslash, ReadOnlySpan<byte> path, bool allowBackslash)
|
||||
{
|
||||
containsBackslash = false;
|
||||
|
||||
for (int i = 0; i < path.Length && path[i] != NullTerminator; i++)
|
||||
{
|
||||
if (path[i] == '\\')
|
||||
{
|
||||
containsBackslash = true;
|
||||
|
||||
if (!allowBackslash)
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckEntryNameBytes(ReadOnlySpan<byte> path, int maxEntryLength)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int currentEntryLength = 0;
|
||||
|
||||
for (int i = 0; i < path.Length && path[i] != NullTerminator; i++)
|
||||
{
|
||||
currentEntryLength++;
|
||||
|
||||
if (path[i] == DirectorySeparator || path[i] == AltDirectorySeparator)
|
||||
currentEntryLength = 0;
|
||||
|
||||
// Note: The original does use >= instead of >
|
||||
if (currentEntryLength >= maxEntryLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static bool IsSubPath(ReadOnlySpan<byte> lhs, ReadOnlySpan<byte> rhs)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(lhs);
|
||||
Assert.SdkRequiresNotNull(rhs);
|
||||
|
||||
if (WindowsPath.IsUncPath(lhs) && !WindowsPath.IsUncPath(rhs))
|
||||
return false;
|
||||
|
||||
if (!WindowsPath.IsUncPath(lhs) && WindowsPath.IsUncPath(rhs))
|
||||
return false;
|
||||
|
||||
if (lhs.At(0) == DirectorySeparator && lhs.At(1) == NullTerminator &&
|
||||
rhs.At(0) == DirectorySeparator && rhs.At(1) != NullTerminator)
|
||||
return true;
|
||||
|
||||
if (rhs.GetOrNull(0) == DirectorySeparator && rhs.GetOrNull(1) == NullTerminator &&
|
||||
lhs.GetOrNull(0) == DirectorySeparator && lhs.GetOrNull(1) != NullTerminator)
|
||||
if (rhs.At(0) == DirectorySeparator && rhs.At(1) == NullTerminator &&
|
||||
lhs.At(0) == DirectorySeparator && lhs.At(1) != NullTerminator)
|
||||
return true;
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
if (lhs.GetOrNull(i) == NullTerminator)
|
||||
if (lhs.At(i) == NullTerminator)
|
||||
{
|
||||
return rhs.GetOrNull(i) == DirectorySeparator;
|
||||
return rhs.At(i) == DirectorySeparator;
|
||||
}
|
||||
else if (rhs.GetOrNull(i) == NullTerminator)
|
||||
else if (rhs.At(i) == NullTerminator)
|
||||
{
|
||||
return lhs.GetOrNull(i) == DirectorySeparator;
|
||||
return lhs.At(i) == DirectorySeparator;
|
||||
}
|
||||
else if (lhs.GetOrNull(i) != rhs.GetOrNull(i))
|
||||
else if (lhs.At(i) != rhs.At(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPathAbsolute(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (WindowsPath.IsWindowsPath(path, false))
|
||||
return true;
|
||||
|
||||
return path.At(0) == DirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsPathRelative(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return path.At(0) != NullTerminator && !IsPathAbsolute(path);
|
||||
}
|
||||
|
||||
public static bool IsPathStartWithCurrentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsCurrentDirectory(path) || IsParentDirectory(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,245 +0,0 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Util;
|
||||
using static LibHac.Fs.StringTraits;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public static class PathUtility12
|
||||
{
|
||||
public static void Replace(Span<byte> buffer, byte currentChar, byte newChar)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(buffer);
|
||||
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
if (buffer[i] == currentChar)
|
||||
{
|
||||
buffer[i] = newChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCurrentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (path.Length < 1)
|
||||
return false;
|
||||
|
||||
return path[0] == Dot &&
|
||||
(path.Length < 2 || path[1] == NullTerminator || path[1] == DirectorySeparator);
|
||||
}
|
||||
|
||||
public static bool IsParentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (path.Length < 2)
|
||||
return false;
|
||||
|
||||
return path[0] == Dot &&
|
||||
path[1] == Dot &&
|
||||
(path.Length < 3 || path[2] == NullTerminator || path[2] == DirectorySeparator);
|
||||
}
|
||||
|
||||
public static bool IsSeparator(byte c)
|
||||
{
|
||||
return c == DirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsNul(byte c)
|
||||
{
|
||||
return c == NullTerminator;
|
||||
}
|
||||
|
||||
public static Result ConvertToFspPath(out FspPath fspPath, ReadOnlySpan<byte> path)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out fspPath);
|
||||
|
||||
int length = StringUtils.Copy(SpanHelpers.AsByteSpan(ref fspPath), path, PathTool.EntryNameLengthMax + 1);
|
||||
|
||||
if (length >= PathTool.EntryNameLengthMax + 1)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
Result rc = PathFormatter.SkipMountName(out ReadOnlySpan<byte> pathWithoutMountName, out _,
|
||||
new U8Span(path));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!WindowsPath12.IsWindowsPath(pathWithoutMountName, true))
|
||||
{
|
||||
Replace(SpanHelpers.AsByteSpan(ref fspPath).Slice(0, 0x300), AltDirectorySeparator, DirectorySeparator);
|
||||
}
|
||||
else if (fspPath.Str[0] == DirectorySeparator && fspPath.Str[1] == DirectorySeparator)
|
||||
{
|
||||
SpanHelpers.AsByteSpan(ref fspPath)[0] = AltDirectorySeparator;
|
||||
SpanHelpers.AsByteSpan(ref fspPath)[1] = AltDirectorySeparator;
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static bool IsDirectoryPath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (path.Length < 1 || path[0] == NullTerminator)
|
||||
return false;
|
||||
|
||||
int length = StringUtils.GetLength(path);
|
||||
return path[length - 1] == DirectorySeparator || path[length - 1] == AltDirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsDirectoryPath(in FspPath path)
|
||||
{
|
||||
return IsDirectoryPath(SpanHelpers.AsReadOnlyByteSpan(in path));
|
||||
}
|
||||
|
||||
public static Result CheckUtf8(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
uint utf8Buffer = 0;
|
||||
Span<byte> utf8BufferSpan = SpanHelpers.AsByteSpan(ref utf8Buffer);
|
||||
|
||||
ReadOnlySpan<byte> currentChar = path;
|
||||
|
||||
while (currentChar.Length > 0 && currentChar[0] != NullTerminator)
|
||||
{
|
||||
utf8BufferSpan.Clear();
|
||||
|
||||
CharacterEncodingResult result =
|
||||
CharacterEncoding.PickOutCharacterFromUtf8String(utf8BufferSpan, ref currentChar);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
result = CharacterEncoding.ConvertCharacterUtf8ToUtf32(out _, utf8BufferSpan);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckInvalidCharacter(byte c)
|
||||
{
|
||||
/*
|
||||
The optimized code is equivalent to this:
|
||||
|
||||
ReadOnlySpan<byte> invalidChars = new[]
|
||||
{(byte) ':', (byte) '*', (byte) '?', (byte) '<', (byte) '>', (byte) '|'};
|
||||
|
||||
for (int i = 0; i < invalidChars.Length; i++)
|
||||
{
|
||||
if (c == invalidChars[i])
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
*/
|
||||
|
||||
const ulong mask = (1ul << (byte)':') |
|
||||
(1ul << (byte)'*') |
|
||||
(1ul << (byte)'?') |
|
||||
(1ul << (byte)'<') |
|
||||
(1ul << (byte)'>');
|
||||
|
||||
if (c <= 0x3Fu && ((1ul << c) & mask) != 0 || c == (byte)'|')
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckInvalidBackslash(out bool containsBackslash, ReadOnlySpan<byte> path, bool allowBackslash)
|
||||
{
|
||||
containsBackslash = false;
|
||||
|
||||
for (int i = 0; i < path.Length && path[i] != NullTerminator; i++)
|
||||
{
|
||||
if (path[i] == '\\')
|
||||
{
|
||||
containsBackslash = true;
|
||||
|
||||
if (!allowBackslash)
|
||||
return ResultFs.InvalidCharacter.Log();
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result CheckEntryNameBytes(ReadOnlySpan<byte> path, int maxEntryLength)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int currentEntryLength = 0;
|
||||
|
||||
for (int i = 0; i < path.Length && path[i] != NullTerminator; i++)
|
||||
{
|
||||
currentEntryLength++;
|
||||
|
||||
if (path[i] == DirectorySeparator || path[i] == AltDirectorySeparator)
|
||||
currentEntryLength = 0;
|
||||
|
||||
// Note: The original does use >= instead of >
|
||||
if (currentEntryLength >= maxEntryLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static bool IsSubPath(ReadOnlySpan<byte> lhs, ReadOnlySpan<byte> rhs)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(lhs);
|
||||
Assert.SdkRequiresNotNull(rhs);
|
||||
|
||||
if (WindowsPath12.IsUncPath(lhs) && !WindowsPath12.IsUncPath(rhs))
|
||||
return false;
|
||||
|
||||
if (!WindowsPath12.IsUncPath(lhs) && WindowsPath12.IsUncPath(rhs))
|
||||
return false;
|
||||
|
||||
if (lhs.At(0) == DirectorySeparator && lhs.At(1) == NullTerminator &&
|
||||
rhs.At(0) == DirectorySeparator && rhs.At(1) != NullTerminator)
|
||||
return true;
|
||||
|
||||
if (rhs.At(0) == DirectorySeparator && rhs.At(1) == NullTerminator &&
|
||||
lhs.At(0) == DirectorySeparator && lhs.At(1) != NullTerminator)
|
||||
return true;
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
if (lhs.At(i) == NullTerminator)
|
||||
{
|
||||
return rhs.At(i) == DirectorySeparator;
|
||||
}
|
||||
else if (rhs.At(i) == NullTerminator)
|
||||
{
|
||||
return lhs.At(i) == DirectorySeparator;
|
||||
}
|
||||
else if (lhs.At(i) != rhs.At(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPathAbsolute(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (WindowsPath12.IsWindowsPath(path, false))
|
||||
return true;
|
||||
|
||||
return path.At(0) == DirectorySeparator;
|
||||
}
|
||||
|
||||
public static bool IsPathRelative(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return path.At(0) != NullTerminator && !IsPathAbsolute(path);
|
||||
}
|
||||
|
||||
public static bool IsPathStartWithCurrentDirectory(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsCurrentDirectory(path) || IsParentDirectory(path);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,82 +1,157 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using static LibHac.Fs.StringTraits;
|
||||
using LibHac.Util;
|
||||
using static LibHac.Util.CharacterEncoding;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for working with Windows paths.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||
public static class WindowsPath
|
||||
{
|
||||
private const int WindowsDriveLength = 2;
|
||||
private const int UncPathPrefixLength = 2;
|
||||
private const int DosDevicePathPrefixLength = 4;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsWindowsDrive(U8Span path)
|
||||
public static int GetCodePointByteLength(byte firstCodeUnit)
|
||||
{
|
||||
Assert.SdkRequires(!path.IsNull());
|
||||
|
||||
return (uint)path.Length > 1 &&
|
||||
IsWindowsDriveCharacter(path[0]) &&
|
||||
path[1] == DriveSeparator;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsWindowsDriveCharacter(byte c)
|
||||
{
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return (0b1101_1111 & c) - 'A' <= 'Z' - 'A';
|
||||
// return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z';
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsUnc(U8Span path)
|
||||
{
|
||||
return (uint)path.Length >= UncPathPrefixLength &&
|
||||
(path.GetUnsafe(0) == DirectorySeparator && path.GetUnsafe(1) == DirectorySeparator ||
|
||||
path.GetUnsafe(0) == AltDirectorySeparator && path.GetUnsafe(1) == AltDirectorySeparator);
|
||||
}
|
||||
|
||||
public static bool IsUnc(string path)
|
||||
{
|
||||
return (uint)path.Length >= UncPathPrefixLength &&
|
||||
(path[0] == DirectorySeparator && path[1] == DirectorySeparator ||
|
||||
path[0] == AltDirectorySeparator && path[1] == AltDirectorySeparator);
|
||||
}
|
||||
|
||||
public static int GetWindowsPathSkipLength(U8Span path)
|
||||
{
|
||||
if (IsWindowsDrive(path))
|
||||
return WindowsDriveLength;
|
||||
|
||||
if (!IsUnc(path))
|
||||
return 0;
|
||||
|
||||
for (int i = UncPathPrefixLength; i < path.Length && path[i] != NullTerminator; i++)
|
||||
{
|
||||
if (path[i] == (byte)'$' || path[i] == DriveSeparator)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((firstCodeUnit & 0x80) == 0x00) return 1;
|
||||
if ((firstCodeUnit & 0xE0) == 0xC0) return 2;
|
||||
if ((firstCodeUnit & 0xF0) == 0xE0) return 3;
|
||||
if ((firstCodeUnit & 0xF8) == 0xF0) return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool IsDosDelimiter(char c)
|
||||
private static bool IsUncPathImpl(ReadOnlySpan<byte> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < UncPathPrefixLength)
|
||||
return false;
|
||||
|
||||
if (checkForwardSlash && path[0] == '/' && path[1] == '/')
|
||||
return true;
|
||||
|
||||
return checkBackSlash && path[0] == '\\' && path[1] == '\\';
|
||||
}
|
||||
|
||||
public static bool IsDosDevicePath(ReadOnlySpan<char> path)
|
||||
private static bool IsUncPathImpl(ReadOnlySpan<char> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
return path.Length >= DosDevicePathPrefixLength
|
||||
&& IsDosDelimiter(path[0])
|
||||
&& path[1] == '\\'
|
||||
&& (path[2] == '.' || path[2] == '?')
|
||||
&& IsDosDelimiter(path[3]);
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < UncPathPrefixLength)
|
||||
return false;
|
||||
|
||||
if (checkForwardSlash && path[0] == '/' && path[1] == '/')
|
||||
return true;
|
||||
|
||||
return checkBackSlash && path[0] == '\\' && path[1] == '\\';
|
||||
}
|
||||
|
||||
private static int GetUncPathPrefixLengthImpl(ReadOnlySpan<byte> path, bool checkForwardSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int length;
|
||||
int separatorCount = 0;
|
||||
|
||||
for (length = 0; length < path.Length && path[length] != 0; length++)
|
||||
{
|
||||
if (checkForwardSlash && path[length] == '/')
|
||||
++separatorCount;
|
||||
|
||||
if (path[length] == '\\')
|
||||
++separatorCount;
|
||||
|
||||
if (separatorCount == 4)
|
||||
return length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static int GetUncPathPrefixLengthImpl(ReadOnlySpan<char> path, bool checkForwardSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int length;
|
||||
int separatorCount = 0;
|
||||
|
||||
for (length = 0; length < path.Length && path[length] != 0; length++)
|
||||
{
|
||||
if (checkForwardSlash && path[length] == '/')
|
||||
++separatorCount;
|
||||
|
||||
if (path[length] == '\\')
|
||||
++separatorCount;
|
||||
|
||||
if (separatorCount == 4)
|
||||
return length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static bool IsDosDevicePathImpl(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < DosDevicePathPrefixLength)
|
||||
return false;
|
||||
|
||||
return path[0] == '\\' &&
|
||||
path[1] == '\\' &&
|
||||
(path[2] == '.' || path[2] == '?') &&
|
||||
(path[3] == '/' || path[3] == '\\');
|
||||
}
|
||||
|
||||
private static bool IsDosDevicePathImpl(ReadOnlySpan<char> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < DosDevicePathPrefixLength)
|
||||
return false;
|
||||
|
||||
return path[0] == '\\' &&
|
||||
path[1] == '\\' &&
|
||||
(path[2] == '.' || path[2] == '?') &&
|
||||
(path[3] == '/' || path[3] == '\\');
|
||||
}
|
||||
|
||||
public static bool IsWindowsDrive(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < WindowsDriveLength)
|
||||
return false;
|
||||
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return ((0b1101_1111 & path[0]) - 'A' <= 'Z' - 'A') && path[1] == ':';
|
||||
// return ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') && path[1] == ':';
|
||||
}
|
||||
|
||||
public static bool IsUncPath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsUncPathImpl(path, true, true);
|
||||
}
|
||||
|
||||
public static bool IsUncPath(ReadOnlySpan<byte> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
return IsUncPathImpl(path, checkForwardSlash, checkBackSlash);
|
||||
}
|
||||
|
||||
public static int GetUncPathPrefixLength(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return GetUncPathPrefixLengthImpl(path, true);
|
||||
}
|
||||
|
||||
public static bool IsDosDevicePath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsDosDevicePathImpl(path);
|
||||
}
|
||||
|
||||
public static int GetDosDevicePathPrefixLength()
|
||||
@ -84,37 +159,100 @@ namespace LibHac.Fs
|
||||
return DosDevicePathPrefixLength;
|
||||
}
|
||||
|
||||
public static bool IsDriveName(ReadOnlySpan<char> path)
|
||||
public static bool IsWindowsPath(ReadOnlySpan<byte> path, bool checkForwardSlash)
|
||||
{
|
||||
return path.Length == WindowsDriveLength && path[1] == ':';
|
||||
return IsWindowsDrive(path) || IsDosDevicePath(path) || IsUncPath(path, checkForwardSlash, true);
|
||||
}
|
||||
|
||||
public static bool IsUncPath(ReadOnlySpan<char> path)
|
||||
public static int GetWindowsSkipLength(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return !IsDosDevicePath(path) && path.Length >= UncPathPrefixLength && IsDosDelimiter(path[0]) &&
|
||||
IsDosDelimiter(path[1]);
|
||||
if (IsDosDevicePath(path))
|
||||
return GetDosDevicePathPrefixLength();
|
||||
|
||||
if (IsWindowsDrive(path))
|
||||
return WindowsDriveLength;
|
||||
|
||||
if (IsUncPath(path))
|
||||
return GetUncPathPrefixLength(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetUncPathPrefixLength(ReadOnlySpan<char> path)
|
||||
public static bool IsDosDelimiterW(char c)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < path.Length; i++)
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
public static bool IsWindowsDriveW(ReadOnlySpan<char> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < WindowsDriveLength)
|
||||
return false;
|
||||
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return ((0b1101_1111 & path[0]) - 'A' <= 'Z' - 'A') && path[1] == ':';
|
||||
// return ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') && path[1] == ':';
|
||||
}
|
||||
|
||||
public static bool IsUncPathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsUncPathImpl(path, true, true);
|
||||
}
|
||||
|
||||
public static int GetUncPathPrefixLengthW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return GetUncPathPrefixLengthImpl(path, true);
|
||||
}
|
||||
|
||||
public static bool IsDosDevicePathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsDosDevicePathImpl(path);
|
||||
}
|
||||
|
||||
public static bool IsWindowsPathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsWindowsDriveW(path) || IsUncPathW(path) || IsDosDevicePathW(path);
|
||||
}
|
||||
|
||||
public static Result CheckCharacterCountForWindows(ReadOnlySpan<byte> path, int maxNameLength, int maxPathLength)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
ReadOnlySpan<byte> currentChar = path;
|
||||
int currentNameLength = 0;
|
||||
int currentPathLength = 0;
|
||||
|
||||
while (currentChar.Length > 1 && currentChar[0] != 0)
|
||||
{
|
||||
if (path[i] == '\0')
|
||||
break;
|
||||
int utf16CodeUnitCount = GetCodePointByteLength(currentChar[0]) < 4 ? 1 : 2;
|
||||
|
||||
if (IsDosDelimiter(path[i]) && i + 1 == DosDevicePathPrefixLength)
|
||||
break;
|
||||
int utf8Buffer = 0;
|
||||
CharacterEncodingResult result =
|
||||
PickOutCharacterFromUtf8String(SpanHelpers.AsByteSpan(ref utf8Buffer), ref currentChar);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
result = ConvertCharacterUtf8ToUtf32(out uint pathChar, SpanHelpers.AsReadOnlyByteSpan(in utf8Buffer));
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
currentNameLength += utf16CodeUnitCount;
|
||||
currentPathLength += utf16CodeUnitCount;
|
||||
|
||||
if (pathChar == '/' || pathChar == '\\')
|
||||
currentNameLength = 0;
|
||||
|
||||
if (maxNameLength > 0 && currentNameLength > maxNameLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
if (maxPathLength > 0 && currentPathLength > maxPathLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public static bool IsPathRooted(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsDriveName(path.Slice(0, Math.Min(WindowsDriveLength, path.Length)))
|
||||
|| IsDosDevicePath(path.Slice(0, Math.Min(DosDevicePathPrefixLength, path.Length)))
|
||||
|| IsUncPath(path.Slice(0, Math.Min(DosDevicePathPrefixLength, path.Length)));
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,250 +0,0 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Util;
|
||||
using static LibHac.Util.CharacterEncoding;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public static class WindowsPath12
|
||||
{
|
||||
public static int GetCodePointByteLength(byte firstCodeUnit)
|
||||
{
|
||||
if ((firstCodeUnit & 0x80) == 0x00) return 1;
|
||||
if ((firstCodeUnit & 0xE0) == 0xC0) return 2;
|
||||
if ((firstCodeUnit & 0xF0) == 0xE0) return 3;
|
||||
if ((firstCodeUnit & 0xF8) == 0xF0) return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static bool IsUncPathImpl(ReadOnlySpan<byte> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 2)
|
||||
return false;
|
||||
|
||||
if (checkForwardSlash && path[0] == '/' && path[1] == '/')
|
||||
return true;
|
||||
|
||||
return checkBackSlash && path[0] == '\\' && path[1] == '\\';
|
||||
}
|
||||
|
||||
private static bool IsUncPathImpl(ReadOnlySpan<char> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 2)
|
||||
return false;
|
||||
|
||||
if (checkForwardSlash && path[0] == '/' && path[1] == '/')
|
||||
return true;
|
||||
|
||||
return checkBackSlash && path[0] == '\\' && path[1] == '\\';
|
||||
}
|
||||
|
||||
private static int GetUncPathPrefixLengthImpl(ReadOnlySpan<byte> path, bool checkForwardSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int length;
|
||||
int separatorCount = 0;
|
||||
|
||||
for (length = 0; length < path.Length && path[length] != 0; length++)
|
||||
{
|
||||
if (checkForwardSlash && path[length] == '/')
|
||||
++separatorCount;
|
||||
|
||||
if (path[length] == '\\')
|
||||
++separatorCount;
|
||||
|
||||
if (separatorCount == 4)
|
||||
return length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static int GetUncPathPrefixLengthImpl(ReadOnlySpan<char> path, bool checkForwardSlash)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
int length;
|
||||
int separatorCount = 0;
|
||||
|
||||
for (length = 0; length < path.Length && path[length] != 0; length++)
|
||||
{
|
||||
if (checkForwardSlash && path[length] == '/')
|
||||
++separatorCount;
|
||||
|
||||
if (path[length] == '\\')
|
||||
++separatorCount;
|
||||
|
||||
if (separatorCount == 4)
|
||||
return length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private static bool IsDosDevicePathImpl(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 4)
|
||||
return false;
|
||||
|
||||
return path[0] == '\\' &&
|
||||
path[1] == '\\' &&
|
||||
(path[2] == '.' || path[2] == '?') &&
|
||||
(path[3] == '/' || path[3] == '\\');
|
||||
}
|
||||
|
||||
private static bool IsDosDevicePathImpl(ReadOnlySpan<char> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 4)
|
||||
return false;
|
||||
|
||||
return path[0] == '\\' &&
|
||||
path[1] == '\\' &&
|
||||
(path[2] == '.' || path[2] == '?') &&
|
||||
(path[3] == '/' || path[3] == '\\');
|
||||
}
|
||||
|
||||
public static bool IsWindowsDrive(ReadOnlySpan<byte> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 2)
|
||||
return false;
|
||||
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return ((0b1101_1111 & path[0]) - 'A' <= 'Z' - 'A') && path[1] == ':';
|
||||
// return ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') && path[1] == ':';
|
||||
}
|
||||
|
||||
public static bool IsUncPath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsUncPathImpl(path, true, true);
|
||||
}
|
||||
|
||||
public static bool IsUncPath(ReadOnlySpan<byte> path, bool checkForwardSlash, bool checkBackSlash)
|
||||
{
|
||||
return IsUncPathImpl(path, checkForwardSlash, checkBackSlash);
|
||||
}
|
||||
|
||||
public static int GetUncPathPrefixLength(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return GetUncPathPrefixLengthImpl(path, true);
|
||||
}
|
||||
|
||||
public static bool IsDosDevicePath(ReadOnlySpan<byte> path)
|
||||
{
|
||||
return IsDosDevicePathImpl(path);
|
||||
}
|
||||
|
||||
public static int GetDosDevicePathPrefixLength()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
public static bool IsWindowsPath(ReadOnlySpan<byte> path, bool checkForwardSlash)
|
||||
{
|
||||
return IsWindowsDrive(path) || IsDosDevicePath(path) || IsUncPath(path, checkForwardSlash, true);
|
||||
}
|
||||
|
||||
public static int GetWindowsSkipLength(ReadOnlySpan<byte> path)
|
||||
{
|
||||
if (IsDosDevicePath(path))
|
||||
return GetDosDevicePathPrefixLength();
|
||||
|
||||
if (IsWindowsDrive(path))
|
||||
return 2;
|
||||
|
||||
if (IsUncPath(path))
|
||||
return GetUncPathPrefixLength(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool IsDosDelimiterW(char c)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
public static bool IsWindowsDriveW(ReadOnlySpan<char> path)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
if ((uint)path.Length < 2)
|
||||
return false;
|
||||
|
||||
// Mask lowercase letters to uppercase and check if it's in range
|
||||
return ((0b1101_1111 & path[0]) - 'A' <= 'Z' - 'A') && path[1] == ':';
|
||||
// return ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') && path[1] == ':';
|
||||
}
|
||||
|
||||
public static bool IsUncPathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsUncPathImpl(path, true, true);
|
||||
}
|
||||
|
||||
public static int GetUncPathPrefixLengthW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return GetUncPathPrefixLengthImpl(path, true);
|
||||
}
|
||||
|
||||
public static bool IsDosDevicePathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsDosDevicePathImpl(path);
|
||||
}
|
||||
|
||||
public static bool IsWindowsPathW(ReadOnlySpan<char> path)
|
||||
{
|
||||
return IsWindowsDriveW(path) || IsUncPathW(path) || IsDosDevicePathW(path);
|
||||
}
|
||||
|
||||
public static Result CheckCharacterCountForWindows(ReadOnlySpan<byte> path, int maxNameLength, int maxPathLength)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(path);
|
||||
|
||||
ReadOnlySpan<byte> currentChar = path;
|
||||
int currentNameLength = 0;
|
||||
int currentPathLength = 0;
|
||||
|
||||
while (currentChar.Length > 1 && currentChar[0] != 0)
|
||||
{
|
||||
int utf16CodeUnitCount = GetCodePointByteLength(currentChar[0]) < 4 ? 1 : 2;
|
||||
|
||||
int utf8Buffer = 0;
|
||||
CharacterEncodingResult result =
|
||||
PickOutCharacterFromUtf8String(SpanHelpers.AsByteSpan(ref utf8Buffer), ref currentChar);
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
result = ConvertCharacterUtf8ToUtf32(out uint pathChar, SpanHelpers.AsReadOnlyByteSpan(in utf8Buffer));
|
||||
|
||||
if (result != CharacterEncodingResult.Success)
|
||||
return ResultFs.InvalidPathFormat.Log();
|
||||
|
||||
currentNameLength += utf16CodeUnitCount;
|
||||
currentPathLength += utf16CodeUnitCount;
|
||||
|
||||
if (pathChar == '/' || pathChar == '\\')
|
||||
currentNameLength = 0;
|
||||
|
||||
if (maxNameLength > 0 && currentNameLength > maxNameLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
|
||||
if (maxPathLength > 0 && currentPathLength > maxPathLength)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -26,7 +26,6 @@ namespace LibHac.Fs
|
||||
public FileSystemProxyServiceObjectGlobals FileSystemProxyServiceObject;
|
||||
public FsContextHandlerGlobals FsContextHandler;
|
||||
public ResultHandlingUtilityGlobals ResultHandlingUtility;
|
||||
public PathUtilityGlobals PathUtility;
|
||||
public DirectorySaveDataFileSystemGlobals DirectorySaveDataFileSystem;
|
||||
|
||||
public void Initialize(FileSystemClient fsClient, HorizonClient horizonClient)
|
||||
@ -36,7 +35,6 @@ namespace LibHac.Fs
|
||||
AccessLog.Initialize(fsClient);
|
||||
UserMountTable.Initialize(fsClient);
|
||||
FsContextHandler.Initialize(fsClient);
|
||||
PathUtility.Initialize(fsClient);
|
||||
DirectorySaveDataFileSystem.Initialize(fsClient);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace LibHac.Fs.Fsa
|
||||
int mountLen = 0;
|
||||
int maxMountLen = Math.Min(path.Length, PathTools.MountNameLengthMax);
|
||||
|
||||
if (WindowsPath.IsWindowsDrive(path) || WindowsPath.IsUnc(path))
|
||||
if (WindowsPath.IsWindowsDrive(path) || WindowsPath.IsUncPath(path))
|
||||
{
|
||||
StringUtils.Copy(mountName.Name, CommonPaths.HostRootFileSystemMountName);
|
||||
mountName.Name[PathTools.MountNameLengthMax] = StringTraits.NullTerminator;
|
||||
|
@ -157,7 +157,7 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
public static Result SetBisRootForHost(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
|
||||
{
|
||||
Unsafe.SkipInit(out FsPath path);
|
||||
Unsafe.SkipInit(out FsPath pathBuffer);
|
||||
Result rc;
|
||||
|
||||
int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);
|
||||
@ -173,16 +173,19 @@ namespace LibHac.Fs.Shim
|
||||
? StringTraits.NullTerminator
|
||||
: StringTraits.DirectorySeparator;
|
||||
|
||||
var sb = new U8StringBuilder(path.Str);
|
||||
rc = sb.Append(rootPath).Append(endingSeparator).ToSfPath();
|
||||
if (rc.IsFailure()) return rc;
|
||||
var sb = new U8StringBuilder(pathBuffer.Str);
|
||||
sb.Append(rootPath).Append(endingSeparator);
|
||||
|
||||
if (sb.Overflowed)
|
||||
return ResultFs.TooLongPath.Log();
|
||||
}
|
||||
else
|
||||
{
|
||||
path.Str[0] = StringTraits.NullTerminator;
|
||||
pathBuffer.Str[0] = StringTraits.NullTerminator;
|
||||
}
|
||||
|
||||
FspPath.FromSpan(out FspPath sfPath, path.Str);
|
||||
rc = PathUtility.ConvertToFspPath(out FspPath sfPath, pathBuffer.Str);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
||||
|
||||
|
@ -450,7 +450,7 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = SetUpPath(ref newPathNormalized, in newPath);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (PathUtility12.IsSubPath(currentPathNormalized.GetString(), newPathNormalized.GetString()))
|
||||
if (PathUtility.IsSubPath(currentPathNormalized.GetString(), newPathNormalized.GetString()))
|
||||
return ResultFs.DirectoryNotRenamable.Log();
|
||||
|
||||
rc = _baseFileSystem.Target.RenameDirectory(in currentPathNormalized, in newPathNormalized);
|
||||
|
@ -168,7 +168,7 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = resolver.ResolveApplicationHtmlDocumentPath(out Lr.Path path, applicationId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||
isDirectory = PathUtility.IsDirectoryPath(path.Str);
|
||||
|
||||
return SetUpFsPath(ref outPath, in path);
|
||||
}
|
||||
@ -183,7 +183,7 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = resolver.ResolveProgramPath(out Lr.Path path, programId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||
isDirectory = PathUtility.IsDirectoryPath(path.Str);
|
||||
|
||||
return SetUpFsPath(ref outPath, in path);
|
||||
}
|
||||
@ -198,7 +198,7 @@ namespace LibHac.FsSrv.Impl
|
||||
rc = resolver.ResolveProgramPathForDebug(out Lr.Path path, programId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||
isDirectory = PathUtility.IsDirectoryPath(path.Str);
|
||||
|
||||
return SetUpFsPath(ref outPath, in path);
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
public ref struct PathNormalizer
|
||||
{
|
||||
private readonly U8Span _path;
|
||||
private byte[] _rentedArray;
|
||||
|
||||
public U8Span Path => _path;
|
||||
|
||||
public Result Result { get; }
|
||||
|
||||
public PathNormalizer(U8Span path, Option option)
|
||||
{
|
||||
|
||||
if (option.HasFlag(Option.AcceptEmpty) && path.IsEmpty())
|
||||
{
|
||||
_path = path;
|
||||
_rentedArray = null;
|
||||
Result = Result.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool preserveUnc = option.HasFlag(Option.PreserveUnc);
|
||||
bool preserveTrailingSeparator = option.HasFlag(Option.PreserveTrailingSeparator);
|
||||
bool hasMountName = option.HasFlag(Option.HasMountName);
|
||||
Result = Normalize(out _path, out _rentedArray, path, preserveUnc, preserveTrailingSeparator,
|
||||
hasMountName);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_rentedArray is not null)
|
||||
ArrayPool<byte>.Shared.Return(_rentedArray);
|
||||
}
|
||||
|
||||
private static Result Normalize(out U8Span normalizedPath, out byte[] rentedBuffer, U8Span path,
|
||||
bool preserveUnc, bool preserveTailSeparator, bool hasMountName)
|
||||
{
|
||||
Assert.SdkRequiresNotNullOut(out rentedBuffer);
|
||||
|
||||
normalizedPath = default;
|
||||
rentedBuffer = null;
|
||||
|
||||
Result rc = Fs.PathNormalizer.IsNormalized(out bool isNormalized, path, preserveUnc, hasMountName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (isNormalized)
|
||||
{
|
||||
normalizedPath = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] buffer = null;
|
||||
try
|
||||
{
|
||||
buffer = ArrayPool<byte>.Shared.Rent(PathTool.EntryNameLengthMax + 1);
|
||||
|
||||
rc = Fs.PathNormalizer.Normalize(buffer.AsSpan(0, PathTool.EntryNameLengthMax + 1),
|
||||
out long normalizedLength, path, preserveUnc, hasMountName);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Add the tail separator if needed
|
||||
if (preserveTailSeparator)
|
||||
{
|
||||
int pathLength = StringUtils.GetLength(path, PathTool.EntryNameLengthMax);
|
||||
if (Fs.PathNormalizer.IsSeparator(path[pathLength - 1]) &&
|
||||
!Fs.PathNormalizer.IsSeparator(buffer[normalizedLength - 1]))
|
||||
{
|
||||
Assert.SdkLess(normalizedLength, PathTool.EntryNameLengthMax);
|
||||
|
||||
buffer[(int)normalizedLength] = StringTraits.DirectorySeparator;
|
||||
buffer[(int)normalizedLength + 1] = StringTraits.NullTerminator;
|
||||
}
|
||||
}
|
||||
|
||||
normalizedPath = new U8Span(Shared.Move(ref buffer));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (buffer is not null)
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum Option
|
||||
{
|
||||
None = 0,
|
||||
PreserveUnc = (1 << 0),
|
||||
PreserveTrailingSeparator = (1 << 1),
|
||||
HasMountName = (1 << 2),
|
||||
AcceptEmpty = (1 << 3)
|
||||
}
|
||||
}
|
||||
}
|
@ -243,7 +243,7 @@ namespace LibHac.FsSrv
|
||||
rc = pathNormalized.Normalize(pathFlags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bool isDirectory = PathUtility12.IsDirectoryPath(in path);
|
||||
bool isDirectory = PathUtility.IsDirectoryPath(in path);
|
||||
|
||||
ReferenceCountedDisposable<IFileSystem> fileSystem = null;
|
||||
|
||||
@ -375,7 +375,7 @@ namespace LibHac.FsSrv
|
||||
rc = pathNormalized.Normalize(pathFlags);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (PathUtility12.IsDirectoryPath(in path))
|
||||
if (PathUtility.IsDirectoryPath(in path))
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
||||
rc = ServiceImpl.GetRightsId(out RightsId rightsId, out byte keyGeneration, in pathNormalized,
|
||||
|
@ -834,8 +834,8 @@ namespace LibHac.FsSystem
|
||||
|
||||
for (int i = 0; i < path.Length; i++)
|
||||
{
|
||||
if (!(path[i] == caseSensitivePath[i] || WindowsPath.IsDosDelimiter(path[i]) &&
|
||||
WindowsPath.IsDosDelimiter(caseSensitivePath[i])))
|
||||
if (!(path[i] == caseSensitivePath[i] || WindowsPath.IsDosDelimiterW(path[i]) &&
|
||||
WindowsPath.IsDosDelimiterW(caseSensitivePath[i])))
|
||||
{
|
||||
return ResultFs.PathNotFound.Log();
|
||||
}
|
||||
@ -853,7 +853,7 @@ namespace LibHac.FsSystem
|
||||
string fullPath;
|
||||
int workingDirectoryPathLength;
|
||||
|
||||
if (WindowsPath.IsPathRooted(path))
|
||||
if (WindowsPath.IsWindowsPathW(path))
|
||||
{
|
||||
fullPath = path;
|
||||
workingDirectoryPathLength = 0;
|
||||
@ -862,7 +862,7 @@ namespace LibHac.FsSystem
|
||||
{
|
||||
// We only want to send back the relative part of the path starting with a '/', so
|
||||
// track where the root path ends.
|
||||
if (WindowsPath.IsDosDelimiter(workingDirectoryPath[^1]))
|
||||
if (WindowsPath.IsDosDelimiterW(workingDirectoryPath[^1]))
|
||||
{
|
||||
workingDirectoryPathLength = workingDirectoryPath.Length - 1;
|
||||
}
|
||||
@ -888,8 +888,8 @@ namespace LibHac.FsSystem
|
||||
if (string.IsNullOrEmpty(path1)) return path2;
|
||||
if (string.IsNullOrEmpty(path2)) return path1;
|
||||
|
||||
bool path1HasSeparator = WindowsPath.IsDosDelimiter(path1[path1.Length - 1]);
|
||||
bool path2HasSeparator = WindowsPath.IsDosDelimiter(path2[0]);
|
||||
bool path1HasSeparator = WindowsPath.IsDosDelimiterW(path1[path1.Length - 1]);
|
||||
bool path2HasSeparator = WindowsPath.IsDosDelimiterW(path2[0]);
|
||||
|
||||
if (!path1HasSeparator && !path2HasSeparator)
|
||||
{
|
||||
@ -914,7 +914,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
string exactPath = string.Empty;
|
||||
int itemsToSkip = 0;
|
||||
if (WindowsPath.IsUnc(path))
|
||||
if (WindowsPath.IsUncPathW(path))
|
||||
{
|
||||
// With the Split method, a UNC path like \\server\share, we need to skip
|
||||
// trying to enumerate the server and share, so skip the first two empty
|
||||
|
@ -33,7 +33,7 @@ namespace LibHac.FsSystem.Save
|
||||
|
||||
private Result CheckIfNormalized(in Path path)
|
||||
{
|
||||
Result rc = PathNormalizer12.IsNormalized(out bool isNormalized, out _, path.GetString());
|
||||
Result rc = PathNormalizer.IsNormalized(out bool isNormalized, out _, path.GetString());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!isNormalized)
|
||||
|
@ -52,7 +52,7 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
byte[] buffer = new byte[0x301];
|
||||
|
||||
Result result = PathNormalizer12.Normalize(buffer, out int normalizedLength, path.ToU8Span(), isWindowsPath,
|
||||
Result result = PathNormalizer.Normalize(buffer, out int normalizedLength, path.ToU8Span(), isWindowsPath,
|
||||
isDriveRelativePath);
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
@ -86,7 +86,7 @@ namespace LibHac.Tests.Fs
|
||||
{
|
||||
byte[] buffer = new byte[bufferLength];
|
||||
|
||||
Result result = PathNormalizer12.Normalize(buffer, out int normalizedLength, path.ToU8Span(), false, false);
|
||||
Result result = PathNormalizer.Normalize(buffer, out int normalizedLength, path.ToU8Span(), false, false);
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
Assert.Equal(expectedNormalized, StringUtils.Utf8ZToString(buffer));
|
||||
@ -133,7 +133,7 @@ namespace LibHac.Tests.Fs
|
||||
[Theory, MemberData(nameof(TestData_IsNormalized))]
|
||||
public static void IsNormalized(string path, bool expectedIsNormalized, long expectedLength, Result expectedResult)
|
||||
{
|
||||
Result result = PathNormalizer12.IsNormalized(out bool isNormalized, out int length, path.ToU8Span());
|
||||
Result result = PathNormalizer.IsNormalized(out bool isNormalized, out int length, path.ToU8Span());
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
Assert.Equal(expectedLength, length);
|
||||
|
@ -1,327 +0,0 @@
|
||||
// Uses GLoat to run code in nnsdk https://github.com/h1k421/GLoat
|
||||
#include <gloat.hpp>
|
||||
|
||||
static char Buf[0x80000];
|
||||
static int BufPos = 0;
|
||||
|
||||
static char ResultNameBuf[0x100];
|
||||
|
||||
namespace nn::fs::detail {
|
||||
bool IsEnabledAccessLog();
|
||||
}
|
||||
|
||||
namespace nn::fs::PathTool {
|
||||
// SDK < 7
|
||||
nn::Result Normalize(char* buffer, uint64_t* outNormalizedPathLength, const char* path, uint64_t bufferLength, bool preserveUnc);
|
||||
nn::Result IsNormalized(bool* outIsNormalized, const char* path);
|
||||
|
||||
// SDK >= 7 < 11
|
||||
nn::Result Normalize(char* buffer, uint64_t* outNormalizedPathLength, const char* path, uint64_t bufferLength, bool preserveUnc, bool hasMountName);
|
||||
nn::Result IsNormalized(bool* outIsNormalized, const char* path, bool preserveUnc, bool hasMountName);
|
||||
|
||||
bool IsSubpath(const char* path1, const char* path2);
|
||||
}
|
||||
|
||||
namespace nn::fs {
|
||||
// SDK >= 11
|
||||
bool IsSubPath(const char* path1, const char* path2);
|
||||
}
|
||||
|
||||
namespace nn::fs::PathNormalizer {
|
||||
// SDK >= 11
|
||||
nn::Result Normalize(char* buffer, uint64_t* outNormalizedPathLength, const char* path, uint64_t bufferLength, bool preserveUnc, bool hasMountName);
|
||||
nn::Result IsNormalized(bool* outIsNormalized, const char* path, bool preserveUnc, bool hasMountName);
|
||||
}
|
||||
|
||||
void* allocate(size_t size)
|
||||
{
|
||||
void* ptr = malloc(size);
|
||||
|
||||
char buffer[0x40];
|
||||
sprintf(buffer, "Allocating %ld. 0x%p", size, ptr);
|
||||
svcOutputDebugString(buffer, sizeof(buffer));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void deallocate(void* ptr, size_t size)
|
||||
{
|
||||
char buffer[0x40];
|
||||
sprintf(buffer, "Deallocating %ld. 0x%p", size, ptr);
|
||||
svcOutputDebugString(buffer, sizeof(buffer));
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void setAllocators(void) {
|
||||
nn::fs::SetAllocator(allocate, deallocate);
|
||||
}
|
||||
|
||||
const char* GetResultName(nn::Result result) {
|
||||
switch (result.GetValue()) {
|
||||
case 0: return "Result.Success";
|
||||
case 0x2EE402: return "ResultFs.InvalidPath.Value";
|
||||
case 0x2EE602: return "ResultFs.TooLongPath.Value";
|
||||
case 0x2EE802: return "ResultFs.InvalidCharacter.Value";
|
||||
case 0x2EEA02: return "ResultFs.InvalidPathFormat.Value";
|
||||
case 0x2EEC02: return "ResultFs.DirectoryUnobtainable.Value";
|
||||
default:
|
||||
sprintf(ResultNameBuf, "0x%x", result.GetValue());
|
||||
return ResultNameBuf;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNormalizeTestItem(char const* path, bool preserveUnc, bool hasMountName) {
|
||||
char normalized[0x200];
|
||||
uint64_t normalizedLen = 0;
|
||||
memset(normalized, 0, 0x200);
|
||||
|
||||
//svcOutputDebugString(path, strnlen(path, 0x200));
|
||||
|
||||
nn::Result result = nn::fs::PathNormalizer::Normalize(normalized, &normalizedLen, path, 0x200, preserveUnc, hasMountName);
|
||||
|
||||
const char* preserveUncStr = preserveUnc ? "true" : "false";
|
||||
const char* hasMountNameStr = hasMountName ? "true" : "false";
|
||||
BufPos += sprintf(&Buf[BufPos], "new object[] {@\"%s\", %s, %s, @\"%s\", %ld, %s},\n",
|
||||
path, preserveUncStr, hasMountNameStr, normalized, normalizedLen, GetResultName(result));
|
||||
}
|
||||
|
||||
void CreateIsNormalizedTestItem(char const* path, bool preserveUnc, bool hasMountName) {
|
||||
bool isNormalized = false;
|
||||
|
||||
nn::Result result = nn::fs::PathNormalizer::IsNormalized(&isNormalized, path, preserveUnc, hasMountName);
|
||||
|
||||
const char* preserveUncStr = preserveUnc ? "true" : "false";
|
||||
const char* hasMountNameStr = hasMountName ? "true" : "false";
|
||||
const char* isNormalizedStr = isNormalized ? "true" : "false";
|
||||
BufPos += sprintf(&Buf[BufPos], "new object[] {@\"%s\", %s, %s, %s, %s},\n",
|
||||
path, preserveUncStr, hasMountNameStr, isNormalizedStr, GetResultName(result));
|
||||
}
|
||||
|
||||
void CreateIsSubpathTestItem(const char* path1, const char* path2) {
|
||||
bool result = nn::fs::IsSubPath(path1, path2);
|
||||
|
||||
const char* resultStr = result ? "true" : "false";
|
||||
BufPos += sprintf(&Buf[BufPos], "new object[] {@\"%s\", @\"%s\", %s},\n",
|
||||
path1, path2, resultStr);
|
||||
}
|
||||
|
||||
void CreateTestItemWithParentDirs(char const* path, bool preserveUnc, bool hasMountName, void (*func)(char const*, bool, bool), int parentCount) {
|
||||
char parentPath[0x200];
|
||||
memset(parentPath, 0, sizeof(parentPath));
|
||||
|
||||
strcpy(parentPath, path);
|
||||
func(parentPath, preserveUnc, hasMountName);
|
||||
|
||||
for (int i = 0; i < parentCount; i++) {
|
||||
strcat(parentPath, "/..");
|
||||
func(parentPath, preserveUnc, hasMountName);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateTestItemWithParentDirs(char const* path, bool preserveUnc, bool hasMountName, void (*func)(char const*, bool, bool)) {
|
||||
CreateTestItemWithParentDirs(path, preserveUnc, hasMountName, func, 3);
|
||||
}
|
||||
|
||||
void CreateNormalizationTestData(void (*func)(char const*, bool, bool)) {
|
||||
Buf[0] = '\n';
|
||||
BufPos = 1;
|
||||
|
||||
bool preserveUnc = false;
|
||||
|
||||
func("", preserveUnc, false);
|
||||
func("/", preserveUnc, false);
|
||||
func("/.", preserveUnc, false);
|
||||
func("/a/b/c", preserveUnc, false);
|
||||
func("/a/b/../c", preserveUnc, false);
|
||||
func("/a/b/c/..", preserveUnc, false);
|
||||
func("/a/b/c/.", preserveUnc, false);
|
||||
func("/a/../../..", preserveUnc, false);
|
||||
func("/a/../../../a/b/c", preserveUnc, false);
|
||||
func("//a/b//.//c", preserveUnc, false);
|
||||
func("/../a/b/c/.", preserveUnc, false);
|
||||
func("/./aaa/bbb/ccc/.", preserveUnc, false);
|
||||
func("/a/b/c/", preserveUnc, false);
|
||||
func("a/b/c/", preserveUnc, false);
|
||||
func("/aa/./bb/../cc/", preserveUnc, false);
|
||||
func("/./b/../c/", preserveUnc, false);
|
||||
func("/a/../../../", preserveUnc, false);
|
||||
func("//a/b//.//c/", preserveUnc, false);
|
||||
func("/tmp/../", preserveUnc, false);
|
||||
func("a", preserveUnc, false);
|
||||
func("a/../../../a/b/c", preserveUnc, false);
|
||||
func("./b/../c/", preserveUnc, false);
|
||||
func(".", preserveUnc, false);
|
||||
func("..", preserveUnc, false);
|
||||
func("../a/b/c/.", preserveUnc, false);
|
||||
func("./a/b/c/.", preserveUnc, false);
|
||||
func("abc", preserveUnc, false);
|
||||
func("mount:/a/b/../c", preserveUnc, true);
|
||||
func("a:/a/b/c", preserveUnc, true);
|
||||
func("mount:/a/b/../c", preserveUnc, true);
|
||||
func("mount:/a/b/../c", preserveUnc, false);
|
||||
func("mount:\\a/b/../c", preserveUnc, true);
|
||||
func("mount:\\a/b\\../c", preserveUnc, true);
|
||||
func("mount:\\a/b/c", preserveUnc, true);
|
||||
func("mount:/a\\../b\\..c", preserveUnc, true);
|
||||
func("mount:/a\\../b/..cd", preserveUnc, true);
|
||||
func("mount:/a\\..d/b/c\\..", preserveUnc, true);
|
||||
func("mount:", preserveUnc, true);
|
||||
func("abc:/a/../../../a/b/c", preserveUnc, true);
|
||||
func("abc:/./b/../c/", preserveUnc, true);
|
||||
func("abc:/.", preserveUnc, true);
|
||||
func("abc:/..", preserveUnc, true);
|
||||
func("abc:/", preserveUnc, true);
|
||||
func("abc://a/b//.//c", preserveUnc, true);
|
||||
func("abc:/././/././a/b//.//c", preserveUnc, true);
|
||||
func("mount:/d./aa", preserveUnc, true);
|
||||
func("mount:/d/..", preserveUnc, true);
|
||||
func("/path/aaa/bbb\\..\\h/ddd", preserveUnc, false);
|
||||
func("/path/aaa/bbb/../h/ddd", preserveUnc, false);
|
||||
func("/path/aaa/bbb\\.\\h/ddd", preserveUnc, false);
|
||||
func("/path/aaa/bbb\\./h/ddd", preserveUnc, false);
|
||||
func("/path/aaa/bbb/./h/ddd", preserveUnc, false);
|
||||
func("mount:abcd", preserveUnc, true);
|
||||
func("mount:", preserveUnc, true);
|
||||
func("mount:/", preserveUnc, true);
|
||||
func("mount:\\..", preserveUnc, true);
|
||||
func("mount:/a/b\\..", preserveUnc, true);
|
||||
func("mount:/dir", preserveUnc, true);
|
||||
func("mount:/dir/", preserveUnc, true);
|
||||
func("mount:\\", preserveUnc, true);
|
||||
func("mo.unt:\\", preserveUnc, true);
|
||||
func("mount.:\\", preserveUnc, true);
|
||||
func("mount:./aa/bb", preserveUnc, true);
|
||||
//func("mount:../aa/bb", preserveUnc, true); // crashes nnsdk
|
||||
func("mount:.../aa/bb", preserveUnc, true);
|
||||
func("mount:...aa/bb", preserveUnc, true);
|
||||
func("...aa/bb", preserveUnc, false);
|
||||
func("mount01234567890/aa/bb", preserveUnc, true);
|
||||
func("mount01234567890:/aa/bb", preserveUnc, true);
|
||||
func("mount0123456789:/aa/bb", preserveUnc, true);
|
||||
func("mount012345678:/aa/bb", preserveUnc, true);
|
||||
func("mount:aa/..\\bb", preserveUnc, true);
|
||||
func("mount:..\\bb", preserveUnc, true);
|
||||
func("mount:/..\\bb", preserveUnc, true);
|
||||
func("mount:/.\\bb", preserveUnc, true);
|
||||
func("mount:\\..\\bb", preserveUnc, true);
|
||||
func("mount:\\.\\bb", preserveUnc, true);
|
||||
func("mount:/a\\..\\bb", preserveUnc, true);
|
||||
func("mount:/a\\.\\bb", preserveUnc, true);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
preserveUnc = (bool)i;
|
||||
|
||||
CreateTestItemWithParentDirs("//$abc/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//:abc/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("\\\\\\asd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("\\\\/asd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("\\\\//asd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a/b/cc/../d", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("c:/aa/bb", preserveUnc, true, func);
|
||||
CreateTestItemWithParentDirs("mount:\\c:/aa", preserveUnc, true, func);
|
||||
CreateTestItemWithParentDirs("mount:/c:\\aa/bb", preserveUnc, true, func);
|
||||
CreateTestItemWithParentDirs("mount:////c:\\aa/bb", preserveUnc, true, func);
|
||||
CreateTestItemWithParentDirs("mount:/\\aa/bb", preserveUnc, true, func);
|
||||
CreateTestItemWithParentDirs("mount:/c:/aa/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("mount:c:/aa/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("mount:c:/aa/bb", preserveUnc, true, func, 0);
|
||||
CreateTestItemWithParentDirs("mount:/\\aa/../b", preserveUnc, true, func, 2);
|
||||
CreateTestItemWithParentDirs("mount://aa/bb", preserveUnc, true, func, 1);
|
||||
CreateTestItemWithParentDirs("//aa/bb", preserveUnc, true, func, 1);
|
||||
CreateTestItemWithParentDirs("//aa/bb", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("/aa/bb", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("c:/aa", preserveUnc, false, func, 2);
|
||||
CreateTestItemWithParentDirs("c:abcde/aa/bb", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("c:abcde", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("c:abcde/", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("///aa", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa//bb", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//./bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//../bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//.../bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa$abc/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa$/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa:/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb$b/cc$", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc$c", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc$c/dd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc//dd", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc\\/dd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc//dd", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc/dd", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("//aa/bb/cc/\\dd", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("//aa/../", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa//", preserveUnc, false, func, 0);
|
||||
CreateTestItemWithParentDirs("//aa/bb..", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//aa/bb../", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("/\\\\aa/bb/cc/..", preserveUnc, true, func);
|
||||
|
||||
CreateTestItemWithParentDirs("c:aa\\bb/cc", preserveUnc, false, func);
|
||||
CreateTestItemWithParentDirs("c:\\//\\aa\\bb", preserveUnc, false, func, 1);
|
||||
|
||||
CreateTestItemWithParentDirs("mount://////a/bb/c", preserveUnc, true, func, 2);
|
||||
|
||||
CreateTestItemWithParentDirs("//", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a/", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a/b", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a/b/", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("//a/b/c", preserveUnc, false, func, 2);
|
||||
CreateTestItemWithParentDirs("//a/b/c/", preserveUnc, false, func, 2);
|
||||
|
||||
CreateTestItemWithParentDirs("\\\\", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a/", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a/b", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a/b/", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a/b/c", preserveUnc, false, func, 2);
|
||||
CreateTestItemWithParentDirs("\\\\a/b/c/", preserveUnc, false, func, 2);
|
||||
|
||||
CreateTestItemWithParentDirs("\\\\", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a\\", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a\\b", preserveUnc, false, func, 1);
|
||||
CreateTestItemWithParentDirs("\\\\a\\b\\", preserveUnc, false, func, 1); // "\\a\b\/../.." crashes nnsdk
|
||||
CreateTestItemWithParentDirs("\\\\a\\b\\c", preserveUnc, false, func, 2);
|
||||
CreateTestItemWithParentDirs("\\\\a\\b\\c\\", preserveUnc, false, func, 2);
|
||||
}
|
||||
|
||||
svcOutputDebugString(Buf, BufPos);
|
||||
}
|
||||
|
||||
void CreateSubpathTestData() {
|
||||
Buf[0] = '\n';
|
||||
BufPos = 1;
|
||||
|
||||
CreateIsSubpathTestItem("//a/b", "/a");
|
||||
CreateIsSubpathTestItem("/a", "//a/b");
|
||||
CreateIsSubpathTestItem("//a/b", "\\\\a");
|
||||
CreateIsSubpathTestItem("//a/b", "//a");
|
||||
CreateIsSubpathTestItem("/", "/a");
|
||||
CreateIsSubpathTestItem("/a", "/");
|
||||
CreateIsSubpathTestItem("/", "/");
|
||||
CreateIsSubpathTestItem("", "");
|
||||
CreateIsSubpathTestItem("/", "");
|
||||
CreateIsSubpathTestItem("/", "mount:/a");
|
||||
CreateIsSubpathTestItem("mount:/", "mount:/");
|
||||
CreateIsSubpathTestItem("mount:/a/b", "mount:/a/b");
|
||||
CreateIsSubpathTestItem("mount:/a/b", "mount:/a/b/c");
|
||||
CreateIsSubpathTestItem("/a/b", "/a/b/c");
|
||||
CreateIsSubpathTestItem("/a/b/c", "/a/b");
|
||||
CreateIsSubpathTestItem("/a/b", "/a/b");
|
||||
CreateIsSubpathTestItem("/a/b", "/a/b\\c");
|
||||
|
||||
svcOutputDebugString(Buf, BufPos);
|
||||
}
|
||||
|
||||
extern "C" void nnMain(void) {
|
||||
//setAllocators();
|
||||
nn::fs::detail::IsEnabledAccessLog(); // Adds the sdk version to the output when not calling setAllocators
|
||||
CreateNormalizationTestData(CreateNormalizeTestItem);
|
||||
CreateNormalizationTestData(CreateIsNormalizedTestItem);
|
||||
CreateSubpathTestData();
|
||||
}
|
@ -1,850 +0,0 @@
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Util;
|
||||
using Xunit;
|
||||
|
||||
namespace LibHac.Tests.Fs
|
||||
{
|
||||
public class PathToolTests
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(NormalizeTestItems))]
|
||||
public static void Normalize(string path, bool preserveUnc, bool hasMountName, string expectedNormalized,
|
||||
long expectedLength, Result expectedResult)
|
||||
{
|
||||
byte[] buffer = new byte[0x301];
|
||||
|
||||
Result result = PathNormalizer.Normalize(buffer, out long normalizedLength, path.ToU8Span(), preserveUnc,
|
||||
hasMountName);
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
Assert.Equal(expectedNormalized, StringUtils.Utf8ZToString(buffer));
|
||||
Assert.Equal(expectedLength, normalizedLength);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(IsNormalizedTestItems))]
|
||||
public static void IsNormalized(string path, bool preserveUnc, bool hasMountName, bool expectedIsNormalized,
|
||||
Result expectedResult)
|
||||
{
|
||||
Result result = PathNormalizer.IsNormalized(out bool isNormalized, path.ToU8Span(), preserveUnc, hasMountName);
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
Assert.Equal(expectedIsNormalized, isNormalized);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SubpathTestItems))]
|
||||
public static void IsSubPath(string path1, string path2, bool expectedResult)
|
||||
{
|
||||
bool result = PathUtility.IsSubPath(path1.ToU8Span(), path2.ToU8Span());
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
public static object[][] NormalizeTestItems =
|
||||
{
|
||||
new object[] {@"", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"/", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"/.", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"/a/b/c", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"/a/b/../c", false, false, @"/a/c", 4, Result.Success},
|
||||
new object[] {@"/a/b/c/..", false, false, @"/a/b", 4, Result.Success},
|
||||
new object[] {@"/a/b/c/.", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"/a/../../..", false, false, @"/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"/a/../../../a/b/c", false, false, @"/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"//a/b//.//c", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"/../a/b/c/.", false, false, @"/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"/./aaa/bbb/ccc/.", false, false, @"/aaa/bbb/ccc", 12, Result.Success},
|
||||
new object[] {@"/a/b/c/", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"a/b/c/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"/aa/./bb/../cc/", false, false, @"/aa/cc", 6, Result.Success},
|
||||
new object[] {@"/./b/../c/", false, false, @"/c", 2, Result.Success},
|
||||
new object[] {@"/a/../../../", false, false, @"/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"//a/b//.//c/", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"/tmp/../", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"a", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"a/../../../a/b/c", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"./b/../c/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@".", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"../a/b/c/.", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"./a/b/c/.", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"abc", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/a/b/../c", false, true, @"mount:/a/c", 10, Result.Success},
|
||||
new object[] {@"mount:/a/b/../c", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"a:/a/b/c", false, true, @"a:/a/b/c", 8, Result.Success},
|
||||
new object[] {@"mount:/a/b/../c", false, true, @"mount:/a/c", 10, Result.Success},
|
||||
new object[] {@"mount:\a/b/../c", false, true, @"mount:\a/c", 10, Result.Success},
|
||||
new object[] {@"mount:\a/b\../c", false, true, @"mount:/a/c", 10, Result.Success},
|
||||
new object[] {@"mount:\a/b/c", false, true, @"mount:\a/b/c", 12, Result.Success},
|
||||
new object[] {@"mount:/a\../b\..c", false, true, @"mount:/b\..c", 12, Result.Success},
|
||||
new object[] {@"mount:/a\../b/..cd", false, true, @"mount:/b/..cd", 13, Result.Success},
|
||||
new object[] {@"mount:/a\..d/b/c\..", false, true, @"mount:/a\..d/b", 14, Result.Success},
|
||||
new object[] {@"mount:", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"abc:/a/../../../a/b/c", false, true, @"abc:/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"abc:/./b/../c/", false, true, @"abc:/c", 6, Result.Success},
|
||||
new object[] {@"abc:/.", false, true, @"abc:/", 5, Result.Success},
|
||||
new object[] {@"abc:/..", false, true, @"abc:/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"abc:/", false, true, @"abc:/", 5, Result.Success},
|
||||
new object[] {@"abc://a/b//.//c", false, true, @"abc:/a/b/c", 10, Result.Success},
|
||||
new object[] {@"abc:/././/././a/b//.//c", false, true, @"abc:/a/b/c", 10, Result.Success},
|
||||
new object[] {@"mount:/d./aa", false, true, @"mount:/d./aa", 12, Result.Success},
|
||||
new object[] {@"mount:/d/..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\..\h/ddd", false, false, @"/path/aaa/h/ddd", 15, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb/../h/ddd", false, false, @"/path/aaa/h/ddd", 15, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\.\h/ddd", false, false, @"/path/aaa/bbb\.\h/ddd", 21, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\./h/ddd", false, false, @"/path/aaa/bbb\./h/ddd", 21, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb/./h/ddd", false, false, @"/path/aaa/bbb/h/ddd", 19, Result.Success},
|
||||
new object[] {@"mount:abcd", false, true, @"mount:abcd", 10, Result.Success},
|
||||
new object[] {@"mount:", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:\..", false, true, @"mount:/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/a/b\..", false, true, @"mount:/a", 8, Result.Success},
|
||||
new object[] {@"mount:/dir", false, true, @"mount:/dir", 10, Result.Success},
|
||||
new object[] {@"mount:/dir/", false, true, @"mount:/dir", 10, Result.Success},
|
||||
new object[] {@"mount:\", false, true, @"mount:\", 7, Result.Success},
|
||||
new object[] {@"mo.unt:\", false, true, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"mount.:\", false, true, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"mount:./aa/bb", false, true, @"mount:aa/bb", 11, Result.Success},
|
||||
new object[] {@"mount:.../aa/bb", false, true, @"mount:.../aa/bb", 15, Result.Success},
|
||||
new object[] {@"mount:...aa/bb", false, true, @"mount:...aa/bb", 14, Result.Success},
|
||||
new object[] {@"...aa/bb", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount01234567890/aa/bb", false, true, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount01234567890:/aa/bb", false, true, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount0123456789:/aa/bb", false, true, @"mount0123456789:/aa/bb", 22, Result.Success},
|
||||
new object[] {@"mount012345678:/aa/bb", false, true, @"mount012345678:/aa/bb", 21, Result.Success},
|
||||
new object[] {@"mount:aa/..\bb", false, true, @"mount:aa/..\bb", 14, Result.Success},
|
||||
new object[] {@"mount:..\bb", false, true, @"mount:..\bb", 11, Result.Success},
|
||||
new object[] {@"mount:/..\bb", false, true, @"mount:/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/.\bb", false, true, @"mount:/.\bb", 11, Result.Success},
|
||||
new object[] {@"mount:\..\bb", false, true, @"mount:/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:\.\bb", false, true, @"mount:\.\bb", 11, Result.Success},
|
||||
new object[] {@"mount:/a\..\bb", false, true, @"mount:/bb", 9, Result.Success},
|
||||
new object[] {@"mount:/a\.\bb", false, true, @"mount:/a\.\bb", 13, Result.Success},
|
||||
new object[] {@"//$abc/bb", false, false, @"/$abc/bb", 8, Result.Success},
|
||||
new object[] {@"//:abc/bb", false, false, @"/:abc/bb", 8, Result.Success},
|
||||
new object[] {@"\\\asd", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/asd", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\//asd", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"///..", false, false, @"/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"\\a/b/cc/../d", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/../../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/bb", false, true, @"c:/aa/bb", 8, Result.Success},
|
||||
new object[] {@"c:/aa/bb/..", false, true, @"c:/aa", 5, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../..", false, true, @"c:/", 3, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../../..", false, true, @"c:/aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:\c:/aa", false, true, @"mount:\c:/aa", 12, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/..", false, true, @"mount:\c:", 9, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/../..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/../../..", false, true, @"mount:/c:/aa/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/c:\aa/bb", false, true, @"mount:/c:\aa/bb", 15, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/..", false, true, @"mount:/c:\aa", 12, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../../..", false, true, @"mount:/c:\aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:////c:\aa/bb", false, true, @"mount:/c:\aa/bb", 15, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/..", false, true, @"mount:/c:\aa", 12, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../../..", false, true, @"mount:/c:\aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/\aa/bb", false, true, @"mount:/\aa/bb", 13, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/..", false, true, @"mount:/\aa", 10, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../../..", false, true, @"mount:/\aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/c:/aa/bb", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", false, true, @"mount:c:/aa/bb", 14, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b", false, true, @"mount:/b", 8, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/..", false, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/../..", false, true, @"mount:/b/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount://aa/bb", false, true, @"mount:/aa/bb", 12, Result.Success},
|
||||
new object[] {@"mount://aa/bb/..", false, true, @"mount:/aa", 9, Result.Success},
|
||||
new object[] {@"//aa/bb", false, true, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/..", false, true, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/bb", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"/aa/bb", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"/aa/bb/..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"/aa/bb/../..", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"/aa/bb/../../..", false, false, @"/aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"c:/aa", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/../../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"///aa", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa//bb", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa//bb/..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//./bb", false, false, @"/bb", 3, Result.Success},
|
||||
new object[] {@"//../bb", false, false, @"/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"//.../bb", false, false, @"/.../bb", 7, Result.Success},
|
||||
new object[] {@"//aa$abc/bb", false, false, @"/aa$abc/bb", 10, Result.Success},
|
||||
new object[] {@"//aa$/bb", false, false, @"/aa$/bb", 7, Result.Success},
|
||||
new object[] {@"//aa:/bb", false, false, @"/aa:/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb$b/cc$", false, false, @"/aa/bb$b/cc$", 12, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c", false, false, @"/aa/bb/cc$c", 11, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/..", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/dd", false, false, @"/aa/bb/cc$c/dd", 14, Result.Success},
|
||||
new object[] {@"//aa/bb", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", false, false, @"/aa/bb/cc/dd", 12, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/..", false, false, @"/aa/bb/cc", 9, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../..", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../../..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/bb/cc\/dd", false, false, @"/aa/bb/cc\/dd", 13, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", false, false, @"/aa/bb/cc/dd", 12, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd", false, false, @"/aa/bb/cc/dd", 12, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/..", false, false, @"/aa/bb/cc", 9, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../..", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../../..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd", false, false, @"/aa/bb/cc/\dd", 13, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/..", false, false, @"/aa/bb/cc", 9, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../..", false, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../../..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/../", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"//aa//", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/bb..", false, false, @"/aa/bb..", 8, Result.Success},
|
||||
new object[] {@"//aa/bb../..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"//aa/bb../", false, false, @"/aa/bb..", 8, Result.Success},
|
||||
new object[] {@"//aa/bb..//..", false, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/..", false, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../..", false, true, @"/\\aa", 5, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../..", false, true, @"/", 1, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../../..", false, true, @"/\\aa/bb/cc/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"c:aa\bb/cc", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/../../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:\//\aa\bb", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:\//\aa\bb/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount://////a/bb/c", false, true, @"mount:/a/bb/c", 13, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/..", false, true, @"mount:/a/bb", 11, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/../..", false, true, @"mount:/a", 8, Result.Success},
|
||||
new object[] {@"//", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"///..", false, false, @"/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"//a", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/..", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"//a", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/..", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"//a/", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a//..", false, false, @"/", 1, Result.Success},
|
||||
new object[] {@"//a/b", false, false, @"/a/b", 4, Result.Success},
|
||||
new object[] {@"//a/b/..", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/b/", false, false, @"/a/b", 4, Result.Success},
|
||||
new object[] {@"//a/b//..", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/b/c", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"//a/b/c/..", false, false, @"/a/b", 4, Result.Success},
|
||||
new object[] {@"//a/b/c/../..", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/b/c/", false, false, @"/a/b/c", 6, Result.Success},
|
||||
new object[] {@"//a/b/c//..", false, false, @"/a/b", 4, Result.Success},
|
||||
new object[] {@"//a/b/c//../..", false, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"\\", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a//..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b//..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c//..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c//../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\/..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\/../..", false, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//$abc/bb", true, false, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//:abc/bb", true, false, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"\\\asd", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/asd", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\//asd", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//", true, false, @"/", 1, Result.Success},
|
||||
new object[] {@"///..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d", true, false, @"\\a/b/d", 7, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/../../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"c:/aa/bb", true, true, @"c:/aa/bb", 8, Result.Success},
|
||||
new object[] {@"c:/aa/bb/..", true, true, @"c:/aa", 5, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../..", true, true, @"c:/", 3, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../../..", true, true, @"c:/aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:\c:/aa", true, true, @"mount:\c:/aa", 12, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/..", true, true, @"mount:\c:", 9, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/../..", true, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:\c:/aa/../../..", true, true, @"mount:/c:/aa/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/c:\aa/bb", true, true, @"mount:/c:\aa/bb", 15, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/..", true, true, @"mount:/c:\aa", 12, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../..", true, true, @"mount:/c:", 9, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../../..", true, true, @"mount:/c:", 9, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb", true, true, @"mount:////c:\aa/bb", 18, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/..", true, true, @"mount:////c:\aa", 15, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../..", true, true, @"mount:////c:", 12, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../../..", true, true, @"mount:////c:", 12, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb", true, true, @"mount:/\aa/bb", 13, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/..", true, true, @"mount:/\aa", 10, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../..", true, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../../..", true, true, @"mount:/\aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount:/c:/aa/bb", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", true, true, @"mount:c:/aa/bb", 14, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b", true, true, @"mount:/b", 8, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/..", true, true, @"mount:/", 7, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/../..", true, true, @"mount:/b/a/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"mount://aa/bb", true, true, @"mount:/\\aa/bb", 14, Result.Success},
|
||||
new object[] {@"mount://aa/bb/..", true, true, @"mount:/\\aa/bb", 14, Result.Success},
|
||||
new object[] {@"//aa/bb", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"//aa/bb/..", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"//aa/bb", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"/aa/bb", true, false, @"/aa/bb", 6, Result.Success},
|
||||
new object[] {@"/aa/bb/..", true, false, @"/aa", 3, Result.Success},
|
||||
new object[] {@"/aa/bb/../..", true, false, @"/", 1, Result.Success},
|
||||
new object[] {@"/aa/bb/../../..", true, false, @"/aa/bb/", 0, ResultFs.DirectoryUnobtainable.Value},
|
||||
new object[] {@"c:/aa", true, false, @"c:/aa", 5, Result.Success},
|
||||
new object[] {@"c:/aa/..", true, false, @"c:", 2, Result.Success},
|
||||
new object[] {@"c:/aa/../..", true, false, @"c:", 2, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb", true, false, @"c:abcde/aa/bb", 13, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/..", true, false, @"c:abcde/aa", 10, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/../..", true, false, @"c:abcde", 7, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/../../..", true, false, @"c:abcde", 7, Result.Success},
|
||||
new object[] {@"c:abcde", true, false, @"c:abcde", 7, Result.Success},
|
||||
new object[] {@"c:abcde/..", true, false, @"c:abcde", 7, Result.Success},
|
||||
new object[] {@"c:abcde/", true, false, @"c:abcde", 7, Result.Success},
|
||||
new object[] {@"///aa", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//bb", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//bb/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//./bb", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//../bb", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//.../bb", true, false, @"\\.../bb", 8, Result.Success},
|
||||
new object[] {@"//aa$abc/bb", true, false, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa$/bb", true, false, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa:/bb", true, false, @"", 0, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa/bb$b/cc$", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa/bb/cc$c", true, false, @"\\aa/bb/cc$c", 12, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/dd", true, false, @"\\aa/bb/cc$c/dd", 15, Result.Success},
|
||||
new object[] {@"//aa/bb", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", true, false, @"\\aa/bb/cc/dd", 13, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/..", true, false, @"\\aa/bb/cc", 10, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc\/dd", true, false, @"\\aa/bb/cc\/dd", 14, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", true, false, @"\\aa/bb/cc/dd", 13, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd", true, false, @"\\aa/bb/cc/dd", 13, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/..", true, false, @"\\aa/bb/cc", 10, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd", true, false, @"\\aa/bb/cc/\dd", 14, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/..", true, false, @"\\aa/bb/cc", 10, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../../..", true, false, @"\\aa/bb", 7, Result.Success},
|
||||
new object[] {@"//aa/../", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa/bb..", true, false, @"\\aa/bb..", 9, Result.Success},
|
||||
new object[] {@"//aa/bb../..", true, false, @"\\aa/bb..", 9, Result.Success},
|
||||
new object[] {@"//aa/bb../", true, false, @"\\aa/bb..", 9, Result.Success},
|
||||
new object[] {@"//aa/bb..//..", true, false, @"\\aa/bb..", 9, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/..", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../..", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../..", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../../..", true, true, @"/\\aa/bb", 8, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc", true, false, @"c:aa\bb/cc", 10, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/..", true, false, @"c:aa\bb", 7, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/../..", true, false, @"c:aa", 4, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/../../..", true, false, @"c:aa", 4, Result.Success},
|
||||
new object[] {@"c:\//\aa\bb", true, false, @"c:\/\aa\bb", 10, Result.Success},
|
||||
new object[] {@"c:\//\aa\bb/..", true, false, @"c:\", 3, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c", true, true, @"mount:/\\a/bb/c", 15, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/..", true, true, @"mount:/\\a/bb", 13, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/../..", true, true, @"mount:/\\a/bb", 13, Result.Success},
|
||||
new object[] {@"//", true, false, @"/", 1, Result.Success},
|
||||
new object[] {@"///..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a", true, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a", true, false, @"/a", 2, Result.Success},
|
||||
new object[] {@"//a/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a/", true, false, @"\\a/", 4, Result.Success},
|
||||
new object[] {@"//a//..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a/b", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b//..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/c", true, false, @"\\a/b/c", 7, Result.Success},
|
||||
new object[] {@"//a/b/c/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/c/../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/c/", true, false, @"\\a/b/c", 7, Result.Success},
|
||||
new object[] {@"//a/b/c//..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"//a/b/c//../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\", true, false, @"\\", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", true, false, @"\\", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/", true, false, @"\\a/", 4, Result.Success},
|
||||
new object[] {@"\\a//..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b//..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/c", true, false, @"\\a/b/c", 7, Result.Success},
|
||||
new object[] {@"\\a/b/c/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/c/../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/c/", true, false, @"\\a/b/c", 7, Result.Success},
|
||||
new object[] {@"\\a/b/c//..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a/b/c//../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\", true, false, @"\\", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", true, false, @"\\", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\", true, false, @"\\a/", 4, Result.Success},
|
||||
new object[] {@"\\a\/..", true, false, @"", 0, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a\b/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a\b\", true, false, @"\\a/b\", 6, Result.Success},
|
||||
new object[] {@"\\a\b\/..", true, false, @"\\a", 3, Result.Success},
|
||||
new object[] {@"\\a\b\c", true, false, @"\\a/b\c", 7, Result.Success},
|
||||
new object[] {@"\\a\b\c/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a\b\c/../..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a\b\c\", true, false, @"\\a/b\c\", 8, Result.Success},
|
||||
new object[] {@"\\a\b\c\/..", true, false, @"\\a/b", 5, Result.Success},
|
||||
new object[] {@"\\a\b\c\/../..", true, false, @"\\a/b", 5, Result.Success}
|
||||
};
|
||||
|
||||
public static object[][] IsNormalizedTestItems =
|
||||
{
|
||||
new object[] {@"", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"/", false, false, true, Result.Success},
|
||||
new object[] {@"/.", false, false, false, Result.Success},
|
||||
new object[] {@"/a/b/c", false, false, true, Result.Success},
|
||||
new object[] {@"/a/b/../c", false, false, false, Result.Success},
|
||||
new object[] {@"/a/b/c/..", false, false, false, Result.Success},
|
||||
new object[] {@"/a/b/c/.", false, false, false, Result.Success},
|
||||
new object[] {@"/a/../../..", false, false, false, Result.Success},
|
||||
new object[] {@"/a/../../../a/b/c", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b//.//c", false, false, false, Result.Success},
|
||||
new object[] {@"/../a/b/c/.", false, false, false, Result.Success},
|
||||
new object[] {@"/./aaa/bbb/ccc/.", false, false, false, Result.Success},
|
||||
new object[] {@"/a/b/c/", false, false, false, Result.Success},
|
||||
new object[] {@"a/b/c/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"/aa/./bb/../cc/", false, false, false, Result.Success},
|
||||
new object[] {@"/./b/../c/", false, false, false, Result.Success},
|
||||
new object[] {@"/a/../../../", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b//.//c/", false, false, false, Result.Success},
|
||||
new object[] {@"/tmp/../", false, false, false, Result.Success},
|
||||
new object[] {@"a", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"a/../../../a/b/c", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"./b/../c/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@".", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"../a/b/c/.", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"./a/b/c/.", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"abc", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/a/b/../c", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/a/b/../c", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"a:/a/b/c", false, true, true, Result.Success},
|
||||
new object[] {@"mount:/a/b/../c", false, true, false, Result.Success},
|
||||
new object[] {@"mount:\a/b/../c", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\a/b\../c", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\a/b/c", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/a\../b\..c", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/a\../b/..cd", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/a\..d/b/c\..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"abc:/a/../../../a/b/c", false, true, false, Result.Success},
|
||||
new object[] {@"abc:/./b/../c/", false, true, false, Result.Success},
|
||||
new object[] {@"abc:/.", false, true, false, Result.Success},
|
||||
new object[] {@"abc:/..", false, true, false, Result.Success},
|
||||
new object[] {@"abc:/", false, true, true, Result.Success},
|
||||
new object[] {@"abc://a/b//.//c", false, true, false, Result.Success},
|
||||
new object[] {@"abc:/././/././a/b//.//c", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/d./aa", false, true, true, Result.Success},
|
||||
new object[] {@"mount:/d/..", false, true, false, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\..\h/ddd", false, false, false, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb/../h/ddd", false, false, false, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\.\h/ddd", false, false, true, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb\./h/ddd", false, false, true, Result.Success},
|
||||
new object[] {@"/path/aaa/bbb/./h/ddd", false, false, false, Result.Success},
|
||||
new object[] {@"mount:abcd", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/", false, true, true, Result.Success},
|
||||
new object[] {@"mount:\..", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/a/b\..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/dir", false, true, true, Result.Success},
|
||||
new object[] {@"mount:/dir/", false, true, false, Result.Success},
|
||||
new object[] {@"mount:\", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mo.unt:\", false, true, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"mount.:\", false, true, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"mount:./aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:.../aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:...aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"...aa/bb", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount01234567890/aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount01234567890:/aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount0123456789:/aa/bb", false, true, true, Result.Success},
|
||||
new object[] {@"mount012345678:/aa/bb", false, true, true, Result.Success},
|
||||
new object[] {@"mount:aa/..\bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:..\bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/..\bb", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/.\bb", false, true, true, Result.Success},
|
||||
new object[] {@"mount:\..\bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\.\bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/a\..\bb", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/a\.\bb", false, true, true, Result.Success},
|
||||
new object[] {@"//$abc/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//:abc/bb", false, false, false, Result.Success},
|
||||
new object[] {@"\\\asd", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/asd", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\//asd", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//", false, false, false, Result.Success},
|
||||
new object[] {@"///..", false, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d/../../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/bb", false, true, true, Result.Success},
|
||||
new object[] {@"c:/aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../..", false, true, false, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:\c:/aa", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/..", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/../..", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/../../..", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/c:\aa/bb", false, true, true, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb", false, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb", false, true, true, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:/aa/bb", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", false, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/\aa/../b", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/..", false, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/../..", false, true, false, Result.Success},
|
||||
new object[] {@"mount://aa/bb", false, true, false, Result.Success},
|
||||
new object[] {@"mount://aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb", false, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb/..", false, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/..", false, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb", false, false, true, Result.Success},
|
||||
new object[] {@"/aa/bb/..", false, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb/../..", false, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb/../../..", false, false, false, Result.Success},
|
||||
new object[] {@"c:/aa", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:/aa/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/aa/bb/../../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:abcde/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"///aa", false, false, false, Result.Success},
|
||||
new object[] {@"//aa//bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa//bb/..", false, false, false, Result.Success},
|
||||
new object[] {@"//./bb", false, false, false, Result.Success},
|
||||
new object[] {@"//../bb", false, false, false, Result.Success},
|
||||
new object[] {@"//.../bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa$abc/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa$/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa:/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb$b/cc$", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc\/dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/../", false, false, false, Result.Success},
|
||||
new object[] {@"//aa//", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb../..", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb../", false, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb..//..", false, false, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/..", false, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../..", false, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../..", false, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../../..", false, true, false, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:aa\bb/cc/../../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:\//\aa\bb", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"c:\//\aa\bb/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount://////a/bb/c", false, true, false, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/..", false, true, false, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/../..", false, true, false, Result.Success},
|
||||
new object[] {@"//", false, false, false, Result.Success},
|
||||
new object[] {@"///..", false, false, false, Result.Success},
|
||||
new object[] {@"//a", false, false, false, Result.Success},
|
||||
new object[] {@"//a/..", false, false, false, Result.Success},
|
||||
new object[] {@"//a", false, false, false, Result.Success},
|
||||
new object[] {@"//a/..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/", false, false, false, Result.Success},
|
||||
new object[] {@"//a//..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b//..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/../..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c//..", false, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c//../..", false, false, false, Result.Success},
|
||||
new object[] {@"\\", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a//..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b//..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c/", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c//..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/c//../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\/..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\b\c\/../..", false, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//$abc/bb", true, false, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//:abc/bb", true, false, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"\\\asd", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/asd", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\//asd", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//", true, false, false, Result.Success},
|
||||
new object[] {@"///..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b/cc/../d", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/../..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/cc/../d/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:/aa/bb", true, true, true, Result.Success},
|
||||
new object[] {@"c:/aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../..", true, true, false, Result.Success},
|
||||
new object[] {@"c:/aa/bb/../../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:\c:/aa", true, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/..", true, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/../..", true, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:\c:/aa/../../..", true, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/c:\aa/bb", true, true, true, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:\aa/bb/../../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb", true, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:////c:\aa/bb/../../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb", true, true, true, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/bb/../../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/c:/aa/bb", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:c:/aa/bb", true, true, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"mount:/\aa/../b", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/..", true, true, false, Result.Success},
|
||||
new object[] {@"mount:/\aa/../b/../..", true, true, false, Result.Success},
|
||||
new object[] {@"mount://aa/bb", true, true, false, Result.Success},
|
||||
new object[] {@"mount://aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb", true, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb/..", true, true, false, Result.Success},
|
||||
new object[] {@"//aa/bb", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/..", true, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb", true, false, true, Result.Success},
|
||||
new object[] {@"/aa/bb/..", true, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb/../..", true, false, false, Result.Success},
|
||||
new object[] {@"/aa/bb/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:/aa", true, false, true, Result.Success},
|
||||
new object[] {@"c:/aa/..", true, false, false, Result.Success},
|
||||
new object[] {@"c:/aa/../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb", true, false, true, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/..", true, false, false, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:abcde/aa/bb/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:abcde", true, false, true, Result.Success},
|
||||
new object[] {@"c:abcde/..", true, false, false, Result.Success},
|
||||
new object[] {@"c:abcde/", true, false, false, Result.Success},
|
||||
new object[] {@"///aa", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//bb", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//bb/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//./bb", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//../bb", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//.../bb", true, false, false, Result.Success},
|
||||
new object[] {@"//aa$abc/bb", true, false, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa$/bb", true, false, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa:/bb", true, false, false, ResultFs.InvalidCharacter.Value},
|
||||
new object[] {@"//aa/bb$b/cc$", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa/bb/cc$c", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc$c/dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc\/dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc//dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/dd/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb/cc/\dd/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/../", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa//", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//aa/bb..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb../..", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb../", true, false, false, Result.Success},
|
||||
new object[] {@"//aa/bb..//..", true, false, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/..", true, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../..", true, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../..", true, true, false, Result.Success},
|
||||
new object[] {@"/\\aa/bb/cc/../../../..", true, true, false, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc", true, false, true, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/..", true, false, false, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:aa\bb/cc/../../..", true, false, false, Result.Success},
|
||||
new object[] {@"c:\//\aa\bb", true, false, false, Result.Success},
|
||||
new object[] {@"c:\//\aa\bb/..", true, false, false, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c", true, true, false, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/..", true, true, false, Result.Success},
|
||||
new object[] {@"mount://////a/bb/c/../..", true, true, false, Result.Success},
|
||||
new object[] {@"//", true, false, false, Result.Success},
|
||||
new object[] {@"///..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a", true, false, false, Result.Success},
|
||||
new object[] {@"//a/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a", true, false, false, Result.Success},
|
||||
new object[] {@"//a/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a/", true, false, false, Result.Success},
|
||||
new object[] {@"//a//..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"//a/b", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/..", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b//..", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/..", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/../..", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c/", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c//..", true, false, false, Result.Success},
|
||||
new object[] {@"//a/b/c//../..", true, false, false, Result.Success},
|
||||
new object[] {@"\\", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/", true, false, true, Result.Success},
|
||||
new object[] {@"\\a//..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/b", true, false, true, Result.Success},
|
||||
new object[] {@"\\a/b/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b//..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/c", true, false, true, Result.Success},
|
||||
new object[] {@"\\a/b/c/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/c/../..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/c/", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/c//..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a/b/c//../..", true, false, false, Result.Success},
|
||||
new object[] {@"\\", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a/..", true, false, false, ResultFs.InvalidPathFormat.Value},
|
||||
new object[] {@"\\a\", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c/../..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c\", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c\/..", true, false, false, Result.Success},
|
||||
new object[] {@"\\a\b\c\/../..", true, false, false, Result.Success}
|
||||
};
|
||||
|
||||
public static object[][] SubpathTestItems =
|
||||
{
|
||||
new object[] {@"//a/b", @"/a", false},
|
||||
new object[] {@"/a", @"//a/b", false},
|
||||
new object[] {@"//a/b", @"\\a", false},
|
||||
new object[] {@"//a/b", @"//a", true},
|
||||
new object[] {@"/", @"/a", true},
|
||||
new object[] {@"/a", @"/", true},
|
||||
new object[] {@"/", @"/", false},
|
||||
new object[] {@"", @"", false},
|
||||
new object[] {@"/", @"", true},
|
||||
new object[] {@"/", @"mount:/a", false},
|
||||
new object[] {@"mount:/", @"mount:/", false},
|
||||
new object[] {@"mount:/a/b", @"mount:/a/b", false},
|
||||
new object[] {@"mount:/a/b", @"mount:/a/b/c", true},
|
||||
new object[] {@"/a/b", @"/a/b/c", true},
|
||||
new object[] {@"/a/b/c", @"/a/b", true},
|
||||
new object[] {@"/a/b", @"/a/b", false},
|
||||
new object[] {@"/a/b", @"/a/b\c", false}
|
||||
};
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ namespace LibHac.Tests.Fs
|
||||
[Theory, MemberData(nameof(TestData_IsSubPath))]
|
||||
public static void IsSubPath(string path1, string path2, bool expectedResult)
|
||||
{
|
||||
bool result = PathUtility12.IsSubPath(path1.ToU8Span(), path2.ToU8Span());
|
||||
bool result = PathUtility.IsSubPath(path1.ToU8Span(), path2.ToU8Span());
|
||||
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using Xunit;
|
||||
using PathNormalizer = LibHac.FsSrv.Impl.PathNormalizer;
|
||||
|
||||
namespace LibHac.Tests.FsSrv
|
||||
{
|
||||
public class PathNormalizerTests
|
||||
{
|
||||
[Fact]
|
||||
public static void Ctor_EmptyPathWithAcceptEmptyOption_ReturnsEmptyPathWithSuccess()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("".ToU8Span(), PathNormalizer.Option.AcceptEmpty);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.True(normalizer.Path.IsEmpty());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_PreserveTailSeparatorOption_KeepsExistingTailSeparator()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("/a/./b/".ToU8Span(), PathNormalizer.Option.PreserveTrailingSeparator);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.Equal("/a/b/", normalizer.Path.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_PreserveTailSeparatorOption_IgnoresMissingTailSeparator()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("/a/./b".ToU8Span(), PathNormalizer.Option.PreserveTrailingSeparator);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.Equal("/a/b", normalizer.Path.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_PathAlreadyNormalized_ReturnsSameBuffer()
|
||||
{
|
||||
var originalPath = "/a/b".ToU8Span();
|
||||
using var normalizer = new PathNormalizer(originalPath, PathNormalizer.Option.PreserveTrailingSeparator);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
|
||||
// Compares addresses and lengths of the buffers
|
||||
Assert.True(originalPath.Value == normalizer.Path.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_PreserveUncOptionOn_PreservesUncPath()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("//aa/bb/..".ToU8Span(), PathNormalizer.Option.PreserveUnc);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.Equal(@"\\aa/bb", normalizer.Path.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_PreserveUncOptionOff_DoesNotPreserveUncPath()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("//aa/bb/..".ToU8Span(), PathNormalizer.Option.None);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.Equal(@"/aa", normalizer.Path.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_MountNameOptionOn_ParsesMountName()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("mount:/a/./b".ToU8Span(), PathNormalizer.Option.HasMountName);
|
||||
|
||||
Assert.Equal(Result.Success, normalizer.Result);
|
||||
Assert.Equal("mount:/a/b", normalizer.Path.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Normalize_MountNameOptionOff_DoesNotParseMountName()
|
||||
{
|
||||
using var normalizer = new PathNormalizer("mount:/a/./b".ToU8Span(), PathNormalizer.Option.None);
|
||||
|
||||
Assert.Equal(ResultFs.InvalidPathFormat.Value, normalizer.Result);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user