Beispiel #1
0
        // ReSharper disable once UnusedParameter.Local
        private static Result MountBisImpl(FileSystemClient fs, U8Span mountName, BisPartitionId partitionId, U8Span rootPath)
        {
            Result rc = MountHelpers.CheckMountNameAcceptingReservedMountName(mountName);

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

            FsPath sfPath;

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

            IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

            // Nintendo doesn't use the provided rootPath
            sfPath.Str[0] = 0;

            rc = fsProxy.OpenBisFileSystem(out IFileSystem fileSystem, ref sfPath, partitionId);
            if (rc.IsFailure())
            {
                return(rc);
            }

            var nameGenerator = new BisCommonMountNameGenerator(partitionId);

            return(fs.Register(mountName, fileSystem, nameGenerator));
        }
Beispiel #2
0
        // todo: Decide how to handle SetBisRootForHost since it allows mounting any directory on the user's computer
        public static Result SetBisRootForHost(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
        {
            FsPath sfPath;

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

            int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);

            if (pathLen > PathTools.MaxPathLength)
            {
                return(ResultFs.TooLongPath.Log());
            }

            if (pathLen > 0)
            {
                byte endingSeparator = PathTool.IsSeparator(rootPath[pathLen - 1])
                    ? StringTraits.NullTerminator
                    : StringTraits.DirectorySeparator;

                var    sb = new U8StringBuilder(sfPath.Str);
                Result rc = sb.Append(rootPath).Append(endingSeparator).ToSfPath();
                if (rc.IsFailure())
                {
                    return(rc);
                }
            }
            else
            {
                sfPath.Str[0] = StringTraits.NullTerminator;
            }

            IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

            return(fsProxy.SetBisRootForHost(partitionId, ref sfPath));
        }
Beispiel #3
0
            static Result Mount(FileSystemClientImpl fs, U8Span mountName, BisPartitionId partitionId)
            {
                Result rc = fs.CheckMountNameAcceptingReservedMountName(mountName);

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

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

                // Nintendo doesn't use the provided rootPath
                FspPath.CreateEmpty(out FspPath sfPath);

                ReferenceCountedDisposable <IFileSystemSf> fileSystem = null;

                try
                {
                    rc = fsProxy.Target.OpenBisFileSystem(out fileSystem, in sfPath, partitionId);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    var nameGenerator     = new BisCommonMountNameGenerator(partitionId);
                    var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);

                    return(fs.Fs.Register(mountName, fileSystemAdapter, nameGenerator));
                }
                finally
                {
                    fileSystem?.Dispose();
                }
            }
Beispiel #4
0
        public static U8Span GetBisMountName(BisPartitionId partitionId)
        {
            switch (partitionId)
            {
            case BisPartitionId.BootPartition1Root:
            case BisPartitionId.BootPartition2Root:
            case BisPartitionId.UserDataRoot:
            case BisPartitionId.BootConfigAndPackage2Part1:
            case BisPartitionId.BootConfigAndPackage2Part2:
            case BisPartitionId.BootConfigAndPackage2Part3:
            case BisPartitionId.BootConfigAndPackage2Part4:
            case BisPartitionId.BootConfigAndPackage2Part5:
            case BisPartitionId.BootConfigAndPackage2Part6:
            case BisPartitionId.CalibrationBinary:
                throw new HorizonResultException(default, "The partition specified is not mountable.");

            case BisPartitionId.CalibrationFile:
                return(BisCalibrationFilePartitionMountName);

            case BisPartitionId.SafeMode:
                return(BisSafeModePartitionMountName);

            case BisPartitionId.User:
                return(BisUserPartitionMountName);

            case BisPartitionId.System:
                return(BisSystemPartitionMountName);

            default:
                throw new ArgumentOutOfRangeException(nameof(partitionId), partitionId, null);
            }
        }
Beispiel #5
0
        // nn::fs::detail::MountBis
        private static Result MountBis(FileSystemClient fs, U8Span mountName, BisPartitionId partitionId, U8Span rootPath)
        {
            Result rc;

            if (fs.IsEnabledAccessLog(AccessLogTarget.System))
            {
                TimeSpan startTime = fs.Time.GetCurrent();
                rc = MountBisImpl(fs, mountName, partitionId, rootPath);
                TimeSpan endTime = fs.Time.GetCurrent();

                string logMessage = $", name: \"{mountName.ToString()}\", bispartitionid: {partitionId}, path: \"{rootPath.ToString()}\"";

                fs.OutputAccessLog(rc, startTime, endTime, logMessage);
            }
            else
            {
                rc = MountBisImpl(fs, mountName, partitionId, rootPath);
            }

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

            if (fs.IsEnabledAccessLog(AccessLogTarget.System))
            {
                fs.EnableFileSystemAccessorAccessLog(mountName);
            }

            return(Result.Success);
        }
Beispiel #6
0
        private static Result GetAccessibilityForOpenBisPartition(out Accessibility accessibility, ProgramInfo programInfo,
                                                                  BisPartitionId partitionId)
        {
            UnsafeHelpers.SkipParamInit(out accessibility);

            AccessibilityType type = partitionId switch
            {
                BisPartitionId.BootPartition1Root => AccessibilityType.OpenBisPartitionBootPartition1Root,
                BisPartitionId.BootPartition2Root => AccessibilityType.OpenBisPartitionBootPartition2Root,
                BisPartitionId.UserDataRoot => AccessibilityType.OpenBisPartitionUserDataRoot,
                BisPartitionId.BootConfigAndPackage2Part1 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part1,
                BisPartitionId.BootConfigAndPackage2Part2 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part2,
                BisPartitionId.BootConfigAndPackage2Part3 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part3,
                BisPartitionId.BootConfigAndPackage2Part4 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part4,
                BisPartitionId.BootConfigAndPackage2Part5 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part5,
                BisPartitionId.BootConfigAndPackage2Part6 => AccessibilityType.OpenBisPartitionBootConfigAndPackage2Part6,
                BisPartitionId.CalibrationBinary => AccessibilityType.OpenBisPartitionCalibrationBinary,
                BisPartitionId.CalibrationFile => AccessibilityType.OpenBisPartitionCalibrationFile,
                BisPartitionId.SafeMode => AccessibilityType.OpenBisPartitionSafeMode,
                BisPartitionId.User => AccessibilityType.OpenBisPartitionUser,
                BisPartitionId.System => AccessibilityType.OpenBisPartitionSystem,
                BisPartitionId.SystemProperEncryption => AccessibilityType.OpenBisPartitionSystemProperEncryption,
                BisPartitionId.SystemProperPartition => AccessibilityType.OpenBisPartitionSystemProperPartition,
                _ => (AccessibilityType)(-1)
            };

            if (type == (AccessibilityType)(-1))
            {
                return(ResultFs.InvalidArgument.Log());
            }

            accessibility = programInfo.AccessControl.GetAccessibilityFor(type);
            return(Result.Success);
        }
    }
Beispiel #7
0
        private string GetPartitionPath(BisPartitionId id)
        {
            if (Config.TryGetPartitionPath(out string path, id))
            {
                return(path);
            }

            return(GetDefaultPartitionPath(id));
        }
Beispiel #8
0
        // 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();
            }
        }
Beispiel #9
0
        public bool TryGetFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId)
        {
            if (!IsValidPartitionId(partitionId))
            {
                UnsafeHelpers.SkipParamInit(out fileSystem);
                return(false);
            }

            fileSystem = PartitionFileSystems[GetArrayIndex(partitionId)];

            return(fileSystem != null);
        }
Beispiel #10
0
        public bool TryGetFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId)
        {
            if (!IsValidPartitionId(partitionId))
            {
                fileSystem = default;
                return(false);
            }

            fileSystem = PartitionFileSystems[GetArrayIndex(partitionId)];

            return(fileSystem != null);
        }
Beispiel #11
0
        public bool TryGetPartitionPath(out string path, BisPartitionId partitionId)
        {
            if (!IsValidPartitionId(partitionId))
            {
                path = default;
                return(false);
            }

            path = PartitionPaths[GetArrayIndex(partitionId)];

            return(path != null);
        }
Beispiel #12
0
        public bool TryGetPartitionPath(out string path, BisPartitionId partitionId)
        {
            if (!IsValidPartitionId(partitionId))
            {
                UnsafeHelpers.SkipParamInit(out path);
                return(false);
            }

            path = PartitionPaths[GetArrayIndex(partitionId)];

            return(path != null);
        }
Beispiel #13
0
        public Result SetPath(string path, BisPartitionId partitionId)
        {
            if (path == null)
            {
                return(ResultFs.NullptrArgument.Log());
            }
            if (!IsValidPartitionId(partitionId))
            {
                return(ResultFs.InvalidArgument.Log());
            }

            PartitionPaths[GetArrayIndex(partitionId)] = path;

            return(Result.Success);
        }
Beispiel #14
0
        public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId)
        {
            if (fileSystem == null)
            {
                return(ResultFs.NullptrArgument.Log());
            }
            if (!IsValidPartitionId(partitionId))
            {
                return(ResultFs.InvalidArgument.Log());
            }

            PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem;

            return(Result.Success);
        }
Beispiel #15
0
        public Result Create(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId)
        {
            fileSystem = default;

            if (!IsValidPartitionId(partitionId))
            {
                return(ResultFs.InvalidArgument);
            }
            if (rootPath == null)
            {
                return(ResultFs.NullArgument);
            }

            if (Config.TryGetFileSystem(out fileSystem, partitionId))
            {
                return(Result.Success);
            }

            if (Config.RootFileSystem == null)
            {
                return(ResultFs.PreconditionViolation);
            }

            string partitionPath = GetPartitionPath(partitionId);

            Result rc =
                Util.CreateSubFileSystem(out IFileSystem subFileSystem, Config.RootFileSystem, partitionPath, true);

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

            if (rootPath == string.Empty)
            {
                fileSystem = subFileSystem;
                return(Result.Success);
            }

            return(Util.CreateSubFileSystemImpl(out fileSystem, subFileSystem, rootPath));
        }
Beispiel #16
0
        // OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer<bytes<0x301>, 0x19, 0x301>) -> object<nn::fssrv::sf::IFileSystem> Bis
        public ResultCode OpenBisFileSystem(ServiceCtx context)
        {
            BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32();

            Result rc = FileSystemProxyHelper.ReadFsPath(out FsPath path, context);

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

            rc = _baseFileSystemProxy.OpenBisFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, ref path, bisPartitionId);
            if (rc.IsFailure())
            {
                return((ResultCode)rc.Value);
            }

            MakeObject(context, new FileSystemProxy.IFileSystem(fileSystem));

            return(ResultCode.Success);
        }
Beispiel #17
0
        private string GetDefaultPartitionPath(BisPartitionId id)
        {
            Debug.Assert(IsValidPartitionId(id));

            switch (id)
            {
            case BisPartitionId.CalibrationFile:
                return("/bis/cal");

            case BisPartitionId.SafeMode:
                return("/bis/safe");

            case BisPartitionId.User:
                return("/bis/user");

            case BisPartitionId.System:
                return("/bis/system");

            default:
                return(string.Empty);
            }
        }
Beispiel #18
0
 public Result OpenBisStorage(out IStorage storage, BisPartitionId partitionId)
 {
     throw new NotImplementedException();
 }
Beispiel #19
0
        public Result OpenBisFileSystem(out IFileSystem fileSystem, ref FsPath rootPath, BisPartitionId partitionId)
        {
            fileSystem = default;

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

            Result rc = PathTools.Normalize(out U8Span normalizedPath, rootPath);

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

            return(FsProxyCore.OpenBisFileSystem(out fileSystem, normalizedPath.ToString(), partitionId));
        }
Beispiel #20
0
 public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path)
 {
     throw new NotImplementedException();
 }
Beispiel #21
0
        private static Result MountBis(this FileSystemClientImpl fs, U8Span mountName, BisPartitionId partitionId,
                                       U8Span rootPath)
        {
            Result rc;

            if (fs.IsEnabledAccessLog(AccessLogTarget.System))
            {
                Tick start = fs.Hos.Os.GetSystemTick();
                rc = Mount(fs, mountName, partitionId);
                Tick end = fs.Hos.Os.GetSystemTick();

                Span <byte> logBuffer = stackalloc byte[0x300];
                var         idString  = new IdString();
                var         sb        = new U8StringBuilder(logBuffer, true);

                sb.Append(LogName).Append(mountName).Append(LogQuote)
                .Append(LogBisPartitionId).Append(idString.ToString(partitionId))
                .Append(LogPath).Append(rootPath).Append(LogQuote);

                fs.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
            }
            else
            {
                rc = Mount(fs, mountName, partitionId);
            }

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

            if (fs.IsEnabledAccessLog(AccessLogTarget.System))
            {
                fs.EnableFileSystemAccessorAccessLog(mountName);
            }

            return(Result.Success);
Beispiel #22
0
 private bool IsValidPartitionId(BisPartitionId id)
 {
     return(id >= BisPartitionId.CalibrationFile && id <= BisPartitionId.System);
 }
Beispiel #23
0
 public Result CreateFatFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId)
 {
     fileSystem = default;
     return(ResultFs.NotImplemented);
 }
Beispiel #24
0
        private int GetArrayIndex(BisPartitionId id)
        {
            Debug.Assert(IsValidPartitionId(id));

            return(id - BisPartitionId.CalibrationFile);
        }
Beispiel #25
0
 public BisCommonMountNameGenerator(BisPartitionId partitionId)
 {
     PartitionId = partitionId;
 }
Beispiel #26
0
        public static Result OpenBisPartition(this FileSystemClient fs, out IStorage partitionStorage, BisPartitionId partitionId)
        {
            partitionStorage = default;

            IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
            Result           rc      = fsProxy.OpenBisStorage(out IStorage storage, partitionId);

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

            partitionStorage = storage;
            return(Result.Success);
        }
Beispiel #27
0
 public static Result MountBis(this FileSystemClient fs, U8Span mountName, BisPartitionId partitionId)
 {
     return(MountBis(fs, mountName, partitionId, default));
 }
Beispiel #28
0
 public Result SetBisRootForHost(BisPartitionId partitionId, string rootPath)
 {
     return(Config.SetPath(rootPath, partitionId));
 }
Beispiel #29
0
 public Result OpenBisFileSystem(out IFileSystem fileSystem, string rootPath, BisPartitionId partitionId)
 {
     return(FsCreators.BuiltInStorageFileSystemCreator.Create(out fileSystem, rootPath, partitionId));
 }
Beispiel #30
0
 public static Result MountBis(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
 {
     return(MountBis(fs, GetBisMountName(partitionId), partitionId, rootPath));
 }