Exemplo n.º 1
0
        private Result GetNcaSectionIndex(out int index, FileSystemProxyType fspType)
        {
            switch (fspType)
            {
            case FileSystemProxyType.Code:
            case FileSystemProxyType.Control:
            case FileSystemProxyType.Manual:
            case FileSystemProxyType.Meta:
            case FileSystemProxyType.Data:
                index = 0;
                return(Result.Success);

            case FileSystemProxyType.Rom:
            case FileSystemProxyType.RegisteredUpdate:
                index = 1;
                return(Result.Success);

            case FileSystemProxyType.Logo:
                index = 2;
                return(Result.Success);

            default:
                index = default;
                return(ResultFs.InvalidArgument.Log());
            }
        }
Exemplo n.º 2
0
        private Result OpenSubDirectoryForFsType(out IFileSystem fileSystem, IFileSystem baseFileSystem,
                                                 FileSystemProxyType fsType)
        {
            fileSystem = default;
            ReadOnlySpan <byte> dirName;

            // Get the name of the subdirectory for the filesystem type
            switch (fsType)
            {
            case FileSystemProxyType.Package:
                fileSystem = baseFileSystem;
                return(Result.Success);

            case FileSystemProxyType.Code:
                dirName = new[] { (byte)'/', (byte)'c', (byte)'o', (byte)'d', (byte)'e', (byte)'/' };
                break;

            case FileSystemProxyType.Rom:
            case FileSystemProxyType.Control:
            case FileSystemProxyType.Manual:
            case FileSystemProxyType.Meta:
            // Nintendo doesn't include the Data case in the switch. Maybe an oversight?
            case FileSystemProxyType.Data:
            case FileSystemProxyType.RegisteredUpdate:
                dirName = new[] { (byte)'/', (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)'/' };
                break;

            case FileSystemProxyType.Logo:
                dirName = new[] { (byte)'/', (byte)'l', (byte)'o', (byte)'g', (byte)'o', (byte)'/' };
                break;

            default:
                return(ResultFs.InvalidArgument.Log());
            }

            // Open the subdirectory filesystem
            Result rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFs, baseFileSystem,
                                                                        new U8Span(dirName));

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

            if (fsType == FileSystemProxyType.Code)
            {
                rc = FsCreators.StorageOnNcaCreator.VerifyAcidSignature(subDirFs, null);
                if (rc.IsFailure())
                {
                    return(rc);
                }
            }

            fileSystem = subDirFs;
            return(Result.Success);
        }
Exemplo n.º 3
0
        public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, TitleId titleId, ContentType type)
        {
            Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName);

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

            FileSystemProxyType fspType = ConvertToFileSystemProxyType(type);

            return(MountContentImpl(fs, mountName, path, titleId, fspType));
        }
Exemplo n.º 4
0
        private Result TryOpenContentDirectory(U8Span path, out IFileSystem contentFileSystem,
                                               IFileSystem baseFileSystem, FileSystemProxyType fsType, bool preserveUnc)
        {
            contentFileSystem = default;

            FsPath fullPath;

            unsafe { _ = &fullPath; } // workaround for CS0165

            Result rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFs,
                                                                        baseFileSystem, path, preserveUnc);

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

            return(OpenSubDirectoryForFsType(out contentFileSystem, subDirFs, fsType));
        }
Exemplo n.º 5
0
        private static Result MountContentImpl(FileSystemClient fs, U8Span mountName, U8Span path, ulong id,
                                               ContentType contentType)
        {
            Result rc = fs.Impl.CheckMountNameAcceptingReservedMountName(mountName);

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

            FileSystemProxyType fsType = ConvertToFileSystemProxyType(contentType);

            if (path.IsNull())
            {
                return(ResultFs.NullptrArgument.Log());
            }

            rc = FspPath.FromSpan(out FspPath fsPath, path);
            if (rc.IsFailure())
            {
                return(rc);
            }

            using ReferenceCountedDisposable <IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();

            ReferenceCountedDisposable <IFileSystemSf> fileSystem = null;

            try
            {
                rc = fsProxy.Target.OpenFileSystemWithId(out fileSystem, in fsPath, id, fsType);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
                return(fs.Register(mountName, fileSystemAdapter));
            }
            finally
            {
                fileSystem?.Dispose();
            }
        }
Exemplo n.º 6
0
        public static Result MountContent(this FileSystemClient fs, U8Span mountName, TitleId programId, ContentType type)
        {
            Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName);

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

            FileSystemProxyType fspType = ConvertToFileSystemProxyType(type);

            IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

            rc = fsProxy.OpenFileSystemWithPatch(out IFileSystem fileSystem, programId, fspType);
            if (rc.IsFailure())
            {
                return(rc);
            }

            return(fs.Register(mountName, fileSystem));
        }
Exemplo n.º 7
0
        private Result OpenNcaStorage(out IStorage ncaStorage, Nca nca, out NcaFormatType fsType,
                                      FileSystemProxyType fsProxyType, bool isGameCard, bool canMountSystemDataPrivate)
        {
            ncaStorage = default;
            fsType     = default;

            NcaContentType contentType = nca.Header.ContentType;

            switch (fsProxyType)
            {
            case FileSystemProxyType.Code:
            case FileSystemProxyType.Rom:
            case FileSystemProxyType.Logo:
            case FileSystemProxyType.RegisteredUpdate:
                if (contentType != NcaContentType.Program)
                {
                    return(ResultFs.PreconditionViolation.Log());
                }

                break;

            case FileSystemProxyType.Control:
                if (contentType != NcaContentType.Control)
                {
                    return(ResultFs.PreconditionViolation.Log());
                }

                break;

            case FileSystemProxyType.Manual:
                if (contentType != NcaContentType.Manual)
                {
                    return(ResultFs.PreconditionViolation.Log());
                }

                break;

            case FileSystemProxyType.Meta:
                if (contentType != NcaContentType.Meta)
                {
                    return(ResultFs.PreconditionViolation.Log());
                }

                break;

            case FileSystemProxyType.Data:
                if (contentType != NcaContentType.Data && contentType != NcaContentType.PublicData)
                {
                    return(ResultFs.PreconditionViolation.Log());
                }

                if (contentType == NcaContentType.Data && !canMountSystemDataPrivate)
                {
                    return(ResultFs.PermissionDenied.Log());
                }

                break;

            default:
                return(ResultFs.InvalidArgument.Log());
            }

            if (nca.Header.DistributionType == DistributionType.GameCard && !isGameCard)
            {
                return(ResultFs.PermissionDenied.Log());
            }

            Result rc = SetNcaExternalKey(nca);

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

            rc = GetNcaSectionIndex(out int sectionIndex, fsProxyType);
            if (rc.IsFailure())
            {
                return(rc);
            }

            rc = FsCreators.StorageOnNcaCreator.Create(out ncaStorage, out NcaFsHeader fsHeader, nca,
                                                       sectionIndex, fsProxyType == FileSystemProxyType.Code);
            if (rc.IsFailure())
            {
                return(rc);
            }

            fsType = fsHeader.FormatType;
            return(Result.Success);
        }
Exemplo n.º 8
0
        public Result OpenFileSystem(out IFileSystem fileSystem, U8Span path, FileSystemProxyType type,
                                     bool canMountSystemDataPrivate, ulong programId)
        {
            fileSystem = default;

            // Get a reference to the path that will be advanced as each part of the path is parsed
            U8Span currentPath = path.Slice(0, StringUtils.GetLength(path));

            // Open the root filesystem based on the path's mount name
            Result rc = OpenFileSystemFromMountName(ref currentPath, out IFileSystem baseFileSystem, out bool shouldContinue,
                                                    out MountNameInfo mountNameInfo);

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

            // Don't continue if the rest of the path is empty
            if (!shouldContinue)
            {
                return(ResultFs.InvalidArgument.Log());
            }

            if (type == FileSystemProxyType.Logo && mountNameInfo.IsGameCard)
            {
                rc = OpenGameCardFileSystem(out fileSystem, new GameCardHandle(mountNameInfo.GcHandle),
                                            GameCardPartition.Logo);

                if (rc.IsSuccess())
                {
                    return(Result.Success);
                }

                if (!ResultFs.PartitionNotFound.Includes(rc))
                {
                    return(rc);
                }
            }

            rc = IsContentPathDir(ref currentPath, out bool isDirectory);
            if (rc.IsFailure())
            {
                return(rc);
            }

            if (isDirectory)
            {
                if (!mountNameInfo.IsHostFs)
                {
                    return(ResultFs.PermissionDenied.Log());
                }

                if (type == FileSystemProxyType.Manual)
                {
                    rc = TryOpenCaseSensitiveContentDirectory(out IFileSystem manualFileSystem, baseFileSystem, currentPath);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    fileSystem = new ReadOnlyFileSystem(manualFileSystem);
                    return(Result.Success);
                }

                return(TryOpenContentDirectory(currentPath, out fileSystem, baseFileSystem, type, true));
            }

            rc = TryOpenNsp(ref currentPath, out IFileSystem nspFileSystem, baseFileSystem);

            if (rc.IsSuccess())
            {
                // Must be the end of the path to open Application Package FS type
                if (currentPath.Length == 0 || currentPath[0] == 0)
                {
                    if (type == FileSystemProxyType.Package)
                    {
                        fileSystem = nspFileSystem;
                        return(Result.Success);
                    }

                    return(ResultFs.InvalidArgument.Log());
                }

                baseFileSystem = nspFileSystem;
            }

            if (!mountNameInfo.CanMountNca)
            {
                return(ResultFs.InvalidNcaMountPoint.Log());
            }

            ulong openProgramId = mountNameInfo.IsHostFs ? ulong.MaxValue : programId;

            rc = TryOpenNca(ref currentPath, out Nca nca, baseFileSystem, openProgramId);
            if (rc.IsFailure())
            {
                return(rc);
            }

            rc = OpenNcaStorage(out IStorage ncaSectionStorage, nca, out NcaFormatType fsType, type,
                                mountNameInfo.IsGameCard, canMountSystemDataPrivate);
            if (rc.IsFailure())
            {
                return(rc);
            }

            switch (fsType)
            {
            case NcaFormatType.Romfs:
                return(FsCreators.RomFileSystemCreator.Create(out fileSystem, ncaSectionStorage));

            case NcaFormatType.Pfs0:
                return(FsCreators.PartitionFileSystemCreator.Create(out fileSystem, ncaSectionStorage));

            default:
                return(ResultFs.InvalidNcaFsType.Log());
            }
        }
Exemplo n.º 9
0
 public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemProxyType type)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 10
0
        public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, TitleId titleId, FileSystemProxyType type)
        {
            fileSystem = default;

            // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter

            bool canMountSystemDataPrivate = false;

            var normalizer = new PathNormalizer(path, GetPathNormalizerOptions(path));

            if (normalizer.Result.IsFailure())
            {
                return(normalizer.Result);
            }

            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            return(FsProxyCore.OpenFileSystem(out fileSystem, normalizer.Path, type, canMountSystemDataPrivate, titleId));
        }
Exemplo n.º 11
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();
            }
        }
Exemplo n.º 12
0
        private static Result MountContentImpl(FileSystemClient fs, U8Span mountName, U8Span path, TitleId titleId, FileSystemProxyType type)
        {
            FsPath.FromSpan(out FsPath fsPath, path);

            IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

            Result rc = fsProxy.OpenFileSystemWithId(out IFileSystem fileSystem, ref fsPath, titleId, type);

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

            return(fs.Register(mountName, fileSystem));
        }