Example #1
0
        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      = PathUtility.GetWindowsPathSkipLength(path2);
            int remainingLength = PathTools.MaxPathLength - skipLength;

            Result rc = PathUtility.VerifyPath(path2.Slice(skipLength), remainingLength, remainingLength);

            if (rc.IsFailure())
            {
                return(rc);
            }

            var normalizer = new PathNormalizer(path, PathNormalizer.Option.PreserveUnc);

            return(normalizer.Result);
        }
Example #2
0
        public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable <IFileSystemSf> fileSystem,
                                              ProgramId programId, FileSystemProxyType fsType)
        {
            UnsafeHelpers.SkipParamInit(out fileSystem);

            const StorageType storageFlag = StorageType.All;

            using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);

            // Get the program info for the caller and verify permissions
            Result rc = GetProgramInfo(out ProgramInfo callerProgramInfo);

            if (rc.IsFailure())
            {
                return(rc);
            }

            if (fsType != FileSystemProxyType.Manual)
            {
                if (fsType == FileSystemProxyType.Logo || fsType == FileSystemProxyType.Control)
                {
                    return(ResultFs.NotImplemented.Log());
                }
                else
                {
                    return(ResultFs.InvalidArgument.Log());
                }
            }

            Accessibility accessibility =
                callerProgramInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountContentManual);

            if (!accessibility.CanRead)
            {
                return(ResultFs.PermissionDenied.Log());
            }

            // Get the program info for the owner of the file system being opened
            rc = GetProgramInfoByProgramId(out ProgramInfo ownerProgramInfo, programId.Value);
            if (rc.IsFailure())
            {
                return(rc);
            }

            // Try to find the path to the original version of the file system
            Result originalResult = ServiceImpl.ResolveApplicationHtmlDocumentPath(out Path originalPath,
                                                                                   new Ncm.ApplicationId(programId.Value), ownerProgramInfo.StorageId);

            // The file system might have a patch version with no original version, so continue if not found
            if (originalResult.IsFailure() && !ResultLr.HtmlDocumentNotFound.Includes(originalResult))
            {
                return(originalResult);
            }

            // Use a separate bool because ref structs can't be used as type parameters
            bool           originalPathNormalizerHasValue = false;
            PathNormalizer originalPathNormalizer         = default;

            // Normalize the original version path if found
            if (originalResult.IsSuccess())
            {
                originalPathNormalizer = new PathNormalizer(originalPath, GetPathNormalizerOptions(originalPath));
                if (originalPathNormalizer.Result.IsFailure())
                {
                    return(originalPathNormalizer.Result);
                }

                originalPathNormalizerHasValue = true;
            }

            // Try to find the path to the patch file system
            Result patchResult = ServiceImpl.ResolveRegisteredHtmlDocumentPath(out Path patchPath, programId.Value);

            ReferenceCountedDisposable <IFileSystem> tempFileSystem = null;
            ReferenceCountedDisposable <IRomFileSystemAccessFailureManager> accessFailureManager = null;

            try
            {
                if (ResultLr.HtmlDocumentNotFound.Includes(patchResult))
                {
                    // There must either be an original version or patch version of the file system being opened
                    if (originalResult.IsFailure())
                    {
                        return(originalResult);
                    }

                    Assert.True(originalPathNormalizerHasValue);

                    // There is an original version and no patch version. Open the original directly
                    rc = ServiceImpl.OpenFileSystem(out tempFileSystem, originalPathNormalizer.Path, fsType, programId.Value);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }
                }
                else
                {
                    // Get the normalized path to the original file system
                    U8Span normalizedOriginalPath;
                    if (originalPathNormalizerHasValue)
                    {
                        normalizedOriginalPath = originalPathNormalizer.Path;
                    }
                    else
                    {
                        normalizedOriginalPath = U8Span.Empty;
                    }

                    // Normalize the path to the patch file system
                    var patchPathNormalizer = new PathNormalizer(patchPath, GetPathNormalizerOptions(patchPath));
                    if (patchPathNormalizer.Result.IsFailure())
                    {
                        return(patchPathNormalizer.Result);
                    }

                    if (patchResult.IsFailure())
                    {
                        return(patchResult);
                    }

                    U8Span normalizedPatchPath = patchPathNormalizer.Path;

                    // Open the file system using both the original and patch versions
                    rc = ServiceImpl.OpenFileSystemWithPatch(out tempFileSystem, normalizedOriginalPath,
                                                             normalizedPatchPath, fsType, programId.Value);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }
                }

                // Add all the file system wrappers
                tempFileSystem = StorageLayoutTypeSetFileSystem.CreateShared(ref tempFileSystem, storageFlag);
                tempFileSystem = AsynchronousAccessFileSystem.CreateShared(ref tempFileSystem);

                accessFailureManager = SelfReference.AddReference <IRomFileSystemAccessFailureManager>();
                tempFileSystem       = DeepRetryFileSystem.CreateShared(ref tempFileSystem, ref accessFailureManager);

                fileSystem = FileSystemInterfaceAdapter.CreateShared(ref tempFileSystem);
                return(Result.Success);
            }
            finally
            {
                tempFileSystem?.Dispose();
                accessFailureManager?.Dispose();
            }
        }