public Result OpenHostFileSystem(out ReferenceCountedDisposable <IFileSystem> fileSystem, U8Span path, bool openCaseSensitive) { UnsafeHelpers.SkipParamInit(out fileSystem); Result rc; if (!path.IsEmpty()) { rc = Util.VerifyHostPath(path); if (rc.IsFailure()) { return(rc); } } // Todo: Return shared fs from Create rc = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, openCaseSensitive); if (rc.IsFailure()) { return(rc); } ReferenceCountedDisposable <IFileSystem> sharedHostFs = null; ReferenceCountedDisposable <IFileSystem> subDirFs = null; try { sharedHostFs = new ReferenceCountedDisposable <IFileSystem>(hostFs); if (path.IsEmpty()) { ReadOnlySpan <byte> rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; rc = sharedHostFs.Target.GetEntryType(out _, new U8Span(rootHostPath)); // Nintendo ignores all results other than this one if (ResultFs.TargetNotFound.Includes(rc)) { return(rc); } Shared.Move(out fileSystem, ref sharedHostFs); return(Result.Success); } rc = FsCreators.SubDirectoryFileSystemCreator.Create(out subDirFs, ref sharedHostFs, path, preserveUnc: true); if (rc.IsFailure()) { return(rc); } fileSystem = subDirFs; return(Result.Success); } finally { sharedHostFs?.Dispose(); subDirFs?.Dispose(); } }
public static bool IsValidMountName(this FileSystemClientImpl fs, U8Span name) { if (name.IsEmpty()) { return(false); } // Check for a single-letter mount name if ((name.Length <= 1 || name[1] == 0) && ('a' <= name[0] && name[0] <= 'z' || 'A' <= name[0] && name[0] <= 'Z')) { return(false); } // Check for mount or directory separators int length = 0; for (int i = 0; i < name.Length && name[i] != 0; i++) { if (PathTool.IsDriveSeparator(name[i]) || PathTool.IsSeparator(name[i])) { return(false); } if (++length > PathTools.MountNameLengthMax) { return(false); } } // Todo: VerifyUtf8String return(true); }
public static Result VerifyHostPath(U8Span path) { if (path.IsEmpty()) { return(Result.Success); } if (path[0] != StringTraits.DirectorySeparator) { return(ResultFs.InvalidPathFormat.Log()); } U8Span path2 = path.Slice(1); if (path2.IsEmpty()) { return(Result.Success); } int skipLength = WindowsPath.GetWindowsPathSkipLength(path2); int remainingLength = PathTools.MaxPathLength - skipLength; Result rc = PathUtility.VerifyPath(null, path2.Slice(skipLength), remainingLength, remainingLength); if (rc.IsFailure()) { return(rc); } using var normalizer = new PathNormalizer(path, PathNormalizer.Option.PreserveUnc); return(normalizer.Result); }
public FileSystemAccessor(FileSystemClient fsClient, U8Span name, IMultiCommitTarget multiCommitTarget, IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator, ISaveDataAttributeGetter saveAttributeGetter) { FsClient = fsClient; _fileSystem = fileSystem; _openFiles = new LinkedList <FileAccessor>(); _openDirectories = new LinkedList <DirectoryAccessor>(); _openListLock.Initialize(); _mountNameGenerator = mountNameGenerator; _saveDataAttributeGetter = saveAttributeGetter; _multiCommitTarget = multiCommitTarget; if (name.IsEmpty()) { Abort.DoAbort(ResultFs.InvalidMountName.Log()); } if (StringUtils.GetLength(name, PathTool.MountNameLengthMax + 1) > PathTool.MountNameLengthMax) { Abort.DoAbort(ResultFs.InvalidMountName.Log()); } StringUtils.Copy(_mountName.Name.Slice(0, PathTool.MountNameLengthMax), name); _mountName.Name[PathTool.MountNameLengthMax] = 0; }
public Result OpenHostFileSystem(out IFileSystem fileSystem, U8Span path, bool openCaseSensitive) { fileSystem = default; Result rc; if (!path.IsEmpty()) { rc = Util.VerifyHostPath(path); if (rc.IsFailure()) { return(rc); } } rc = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, openCaseSensitive); if (rc.IsFailure()) { return(rc); } if (path.IsEmpty()) { ReadOnlySpan <byte> rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; rc = hostFs.GetEntryType(out _, new U8Span(rootHostPath)); // Nintendo ignores all results other than this one if (ResultFs.TargetNotFound.Includes(rc)) { return(rc); } fileSystem = hostFs; return(Result.Success); } rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFs, hostFs, path, preserveUnc: true); if (rc.IsFailure()) { return(rc); } fileSystem = subDirFs; return(Result.Success); }
// Todo: Make case sensitive public Result Create(out ReferenceCountedDisposable <IFileSystem> fileSystem, U8Span rootPath, BisPartitionId partitionId, bool caseSensitive) { UnsafeHelpers.SkipParamInit(out fileSystem); if (!IsValidPartitionId(partitionId)) { return(ResultFs.InvalidArgument.Log()); } if (rootPath.IsNull()) { return(ResultFs.NullptrArgument.Log()); } if (Config.TryGetFileSystem(out IFileSystem fs, partitionId)) { fileSystem = new ReferenceCountedDisposable <IFileSystem>(fs); return(Result.Success); } if (Config.RootFileSystem == null) { return(ResultFs.PreconditionViolation.Log()); } var partitionPath = GetPartitionPath(partitionId).ToU8String(); ReferenceCountedDisposable <IFileSystem> partitionFileSystem = null; ReferenceCountedDisposable <IFileSystem> sharedRootFs = null; try { sharedRootFs = new ReferenceCountedDisposable <IFileSystem>(Config.RootFileSystem); Result rc = Utility.WrapSubDirectory(out partitionFileSystem, ref sharedRootFs, partitionPath, true); if (rc.IsFailure()) { return(rc); } if (rootPath.IsEmpty()) { Shared.Move(out fileSystem, ref partitionFileSystem); return(Result.Success); } return(Utility.CreateSubDirectoryFileSystem(out fileSystem, ref partitionFileSystem, rootPath)); } finally { partitionFileSystem?.Dispose(); sharedRootFs?.Dispose(); } }
public PathNormalizer(U8Span path, Option option) { if (option.HasFlag(Option.AcceptEmpty) && path.IsEmpty()) { _path = path; Result = Result.Success; } else { bool preserveUnc = option.HasFlag(Option.PreserveUnc); bool preserveTailSeparator = option.HasFlag(Option.PreserveTailSeparator); bool hasMountName = option.HasFlag(Option.HasMountName); Result = Normalize(out _path, path, preserveUnc, preserveTailSeparator, hasMountName); } }