private void LocationServiceStorageLocationChanging(object sender, PersistentStorageLocationChangingEventArgs e)
        {
            ReferenceCountedDisposable <IPersistentStorage> storage = null;

            lock (_lock)
            {
                if (e.SolutionId != _currentPersistentStorageSolutionId)
                {
                    return;
                }

                // We will transfer ownership in a thread-safe way out so we can dispose outside the lock
                storage = _currentPersistentStorage;
                _currentPersistentStorage           = null;
                _currentPersistentStorageSolutionId = null;
            }

            if (storage != null)
            {
                if (e.MustUseNewStorageLocationImmediately)
                {
                    // Dispose storage outside of the lock. Note this only removes our reference count; clients who are still
                    // using this will still be holding a reference count.
                    storage.Dispose();
                }
                else
                {
                    // make it to shutdown asynchronously
                    Task.Run(() => storage.Dispose());
                }
            }
        }
예제 #2
0
        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();
            }
        }
예제 #3
0
 protected override void Dispose(bool isDisposing)
 {
     if (isDisposing)
     {
         _baseOperator?.Dispose();
     }
 }
예제 #4
0
            static Result Mount(FileSystemClient fs, U8Span mountName, GameCardHandle handle,
                                GameCardPartition partitionId)
            {
                Result rc = fs.Impl.CheckMountNameAcceptingReservedMountName(mountName);

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

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

                ReferenceCountedDisposable <IFileSystemSf> fileSystem = null;

                try
                {
                    rc = fsProxy.Target.OpenGameCardFileSystem(out fileSystem, handle, partitionId);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    var fileSystemAdapter  = new FileSystemServiceObjectAdapter(fileSystem);
                    var mountNameGenerator = new GameCardCommonMountNameGenerator(handle, partitionId);
                    return(fs.Register(mountName, fileSystemAdapter, mountNameGenerator));
                }
                finally
                {
                    fileSystem?.Dispose();
                }
            }
예제 #5
0
        public static Result GetAndClearPatrolReadAllocateBufferCount(this StorageService service,
                                                                      out long successCount, out long failureCount)
        {
            UnsafeHelpers.SkipParamInit(out successCount, out failureCount);

            ReferenceCountedDisposable <IStorageDeviceOperator> mmcOperator = null;

            try
            {
                Result rc = service.GetMmcManagerOperator(out mmcOperator);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                int       operationId        = MakeOperationId(MmcManagerOperationIdValue.GetAndClearPatrolReadAllocateBufferCount);
                OutBuffer successCountBuffer = OutBuffer.FromStruct(ref successCount);
                OutBuffer failureCountBuffer = OutBuffer.FromStruct(ref failureCount);

                return(mmcOperator.Target.OperateOut2(out _, successCountBuffer, out _, failureCountBuffer,
                                                      operationId));
            }
            finally
            {
                mmcOperator?.Dispose();
            }
        }
예제 #6
0
 protected override void Dispose(bool isDisposing)
 {
     if (isDisposing)
     {
         _baseDirectory?.Dispose();
     }
 }
예제 #7
0
        public static Result MountCustomStorage(this FileSystemClient fs, U8Span mountName, CustomStorageId storageId)
        {
            Result rc = fs.Impl.CheckMountName(mountName);

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

            ReferenceCountedDisposable <IFileSystemSf> fileSystem = null;

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

                rc = fsProxy.Target.OpenCustomStorageFileSystem(out fileSystem, storageId);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
                return(fs.Register(mountName, fileSystemAdapter));
            }
            finally
            {
                fileSystem?.Dispose();
            }
        }
예제 #8
0
 protected override void Dispose(bool isDisposing)
 {
     if (isDisposing)
     {
         _baseStorage?.Dispose();
     }
 }
        protected override void Dispose(bool disposing)
        {
            if (_baseFileSystem is null)
            {
                return;
            }

            if (disposing)
            {
                if (typeof(T) == typeof(SaveDataFileSystem))
                {
                    _cacheManager.Register(
                        (ReferenceCountedDisposable <SaveDataFileSystem>)(object) _baseFileSystem);
                }
                else if (typeof(T) == typeof(ApplicationTemporaryFileSystem))
                {
                    _cacheManager.Register(
                        (ReferenceCountedDisposable <ApplicationTemporaryFileSystem>)(object) _baseFileSystem);
                }
                else if (typeof(T) == typeof(DirectorySaveDataFileSystem))
                {
                    _cacheManager.Register(
                        (ReferenceCountedDisposable <DirectorySaveDataFileSystem>)(object) _baseFileSystem);
                }

                _baseFileSystem.Dispose();
                _baseFileSystem = null;
            }

            base.Dispose(disposing);
        }
예제 #10
0
 protected override void Dispose(bool isDisposing)
 {
     if (isDisposing)
     {
         _baseCommitManager?.Dispose();
     }
 }
예제 #11
0
        /// <summary>
        /// Commits all added file systems.
        /// </summary>
        /// <returns>The <see cref="Result"/> of the operation.</returns>
        public Result Commit()
        {
            lock (Locker)
            {
                Result rc = EnsureSaveDataForContext();
                if (rc.IsFailure())
                {
                    return(rc);
                }

                ReferenceCountedDisposable <IFileSystem> contextFs = null;
                try
                {
                    rc = MultiCommitInterface.Target.OpenMultiCommitContext(out contextFs);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    return(Commit(contextFs.Target));
                }
                finally
                {
                    contextFs?.Dispose();
                }
            }
        }
예제 #12
0
 protected override void Dispose(bool isDisposing)
 {
     if (isDisposing)
     {
         _baseReader?.Dispose();
     }
 }
예제 #13
0
        public void TestWeakReferenceLifetime()
        {
            var target = new DisposableObject();

            var reference     = new ReferenceCountedDisposable <DisposableObject>(target);
            var weakReference = new ReferenceCountedDisposable <DisposableObject> .WeakReference(reference);

            var reference2 = reference.TryAddReference();

            Assert.NotNull(reference2);

            reference.Dispose();

            // TryAddReference fails after dispose for a counted reference
            Assert.Null(reference.TryAddReference());
            Assert.NotNull(reference2.Target);
            Assert.False(target.IsDisposed);

            // However, a WeakReference created from the disposed reference can still add a reference
            var reference3 = weakReference.TryAddReference();

            Assert.NotNull(reference3);

            reference2.Dispose();
            Assert.False(target.IsDisposed);

            reference3.Dispose();
            Assert.True(target.IsDisposed);
        }
        public Result OpenBaseFileSystem(out ReferenceCountedDisposable <IFileSystemSf> fileSystem,
                                         BaseFileSystemId fileSystemId)
        {
            UnsafeHelpers.SkipParamInit(out fileSystem);

            Result rc = CheckCapabilityById(fileSystemId, _processId);

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

            ReferenceCountedDisposable <IFileSystem> fs = null;

            try
            {
                // Open the file system
                rc = _serviceImpl.OpenBaseFileSystem(out fs, fileSystemId);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                // Create an SF adapter for the file system
                fileSystem = FileSystemInterfaceAdapter.CreateShared(ref fs);

                return(Result.Success);
            }
            finally
            {
                fs?.Dispose();
            }
        }
예제 #15
0
        public static Result GetGameCardHandle(this FileSystemClient fs, out GameCardHandle handle)
        {
            UnsafeHelpers.SkipParamInit(out handle);

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

            ReferenceCountedDisposable <IDeviceOperator> deviceOperator = null;

            try
            {
                Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
                fs.Impl.AbortIfNeeded(rc);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rc = deviceOperator.Target.GetGameCardHandle(out handle);
                fs.Impl.AbortIfNeeded(rc);
                return(rc);
            }
            finally
            {
                deviceOperator?.Dispose();
            }
        }
예제 #16
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();
                }
            }
예제 #17
0
        public static Result GetAndClearMmcErrorInfo(this StorageService service, out StorageErrorInfo errorInfo,
                                                     out long logSize, Span <byte> logBuffer)
        {
            UnsafeHelpers.SkipParamInit(out errorInfo, out logSize);

            ReferenceCountedDisposable <IStorageDeviceOperator> mmcOperator = null;

            try
            {
                Result rc = service.GetMmcManagerOperator(out mmcOperator);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                int       operationId        = MakeOperationId(MmcManagerOperationIdValue.GetAndClearErrorInfo);
                var       logOutBuffer       = new OutBuffer(logBuffer);
                OutBuffer errorInfoOutBuffer = OutBuffer.FromStruct(ref errorInfo);

                return(mmcOperator.Target.OperateOut2(out _, errorInfoOutBuffer, out logSize, logOutBuffer,
                                                      operationId));
            }
            finally
            {
                mmcOperator?.Dispose();
            }
        }
예제 #18
0
        protected override void DisposeImpl()
        {
            // dispose service and snapshot channels
            _serviceEndPoint.UnexpectedExceptionThrown -= UnexpectedExceptionThrown;
            _serviceEndPoint.Dispose();
            _remoteDataRpc.Dispose();

            base.DisposeImpl();
        }
예제 #19
0
        public static Result OpenMmcStorage(this StorageService service,
                                            out ReferenceCountedDisposable <IStorage> storage, MmcPartition partition)
        {
            UnsafeHelpers.SkipParamInit(out storage);

            ReferenceCountedDisposable <IStorageDeviceManager> deviceManager = null;

            try
            {
                Result rc = service.GetMmcManager(out deviceManager);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                rc = GetAttribute(out ulong attribute, partition);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                ReferenceCountedDisposable <IStorageSf> mmcStorage  = null;
                ReferenceCountedDisposable <IStorage>   tempStorage = null;
                try
                {
                    rc = deviceManager.Target.OpenStorage(out mmcStorage, attribute);
                    if (rc.IsFailure())
                    {
                        return(rc);
                    }

                    tempStorage = StorageServiceObjectAdapter.CreateShared(ref mmcStorage);

                    if (IsSpeedEmulationNeeded(partition))
                    {
                        tempStorage = SpeedEmulationStorage.CreateShared(ref tempStorage);
                        if (tempStorage is null)
                        {
                            return(ResultFs.AllocationMemoryFailedCreateShared.Log());
                        }
                    }

                    storage = Shared.Move(ref tempStorage);
                    return(Result.Success);
                }
                finally
                {
                    mmcStorage?.Dispose();
                    tempStorage?.Dispose();
                }
            }
            finally
            {
                deviceManager?.Dispose();
            }
        }
예제 #20
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _entryCountSemaphore?.Dispose();
                _mountCountSemaphore?.Dispose();
            }

            base.Dispose(disposing);
        }
예제 #21
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                BaseFileSystem?.Dispose();
                BaseFileSystem = null;
            }

            base.Dispose(disposing);
        }
예제 #22
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _baseStorage?.Target.UnsetOpenType(_type);
                _baseStorage?.Dispose();
            }

            base.Dispose(disposing);
        }
예제 #23
0
        public void Dispose()
        {
            if (_pinnedObject != null)
            {
                _semaphore.Dispose();
                _pinnedObject.Dispose();

                _pinnedObject = null;
            }
        }
예제 #24
0
        public void TestTryAddReferenceFailsAfterDispose()
        {
            var target = new DisposableObject();

            var reference = new ReferenceCountedDisposable <DisposableObject>(target);

            reference.Dispose();

            Assert.Null(reference.TryAddReference());
        }
예제 #25
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();
            }
        }
예제 #26
0
 protected override void OnStopped()
 {
     // we are asked to stop. unsubscribe and dispose to disconnect.
     // there are 2 ways to get disconnected. one is Roslyn decided to disconnect with RemoteHost (ex, cancellation or recycle OOP) and
     // the other is external thing disconnecting remote host from us (ex, user killing OOP process).
     // the Disconnected event we subscribe is to detect #2 case. and this method is for #1 case. so when we are willingly disconnecting
     // we don't need the event, otherwise, Disconnected event will be called twice.
     _rpc.Disconnected -= OnRpcDisconnected;
     _rpc.Dispose();
     _remotableDataRpc.Dispose();
 }
예제 #27
0
                protected override void Dispose(bool disposing)
                {
                    base.Dispose(disposing);

                    if (disposing)
                    {
                        _accessor.Dispose();
                    }

                    _start = null;
                }
예제 #28
0
        /// <summary>
        /// Recovers an interrupted multi-commit. The commit will either be completed or rolled back depending on
        /// where in the commit process it was interrupted. Does nothing if there is no commit to recover.
        /// </summary>
        /// <param name="multiCommitInterface">The core interface used for multi-commits.</param>
        /// <param name="saveService">The save data service.</param>
        /// <returns>The <see cref="Result"/> of the operation.<br/>
        /// <see cref="Result.Success"/>: The recovery was successful or there was no multi-commit to recover.</returns>
        public static Result Recover(ISaveDataMultiCommitCoreInterface multiCommitInterface,
                                     SaveDataFileSystemServiceImpl saveService)
        {
            lock (Locker)
            {
                bool needsRecover = true;
                ReferenceCountedDisposable <IFileSystem> fileSystem = null;

                try
                {
                    // Check if a multi-commit was interrupted by checking if there's a commit context file.
                    Result rc = multiCommitInterface.OpenMultiCommitContext(out fileSystem);

                    if (rc.IsFailure())
                    {
                        if (!ResultFs.PathNotFound.Includes(rc) && !ResultFs.TargetNotFound.Includes(rc))
                        {
                            return(rc);
                        }

                        // Unable to open the multi-commit context file system, so there's nothing to recover
                        needsRecover = false;
                    }

                    if (needsRecover)
                    {
                        rc = fileSystem.Target.OpenFile(out IFile file, CommitContextFileName, OpenMode.Read);
                        file?.Dispose();

                        if (rc.IsFailure())
                        {
                            // Unable to open the context file. No multi-commit to recover.
                            if (ResultFs.PathNotFound.Includes(rc))
                            {
                                needsRecover = false;
                            }
                        }
                    }

                    if (!needsRecover)
                    {
                        return(Result.Success);
                    }

                    // There was a context file. Recover the unfinished commit.
                    return(Recover(multiCommitInterface, fileSystem.Target, saveService));
                }
                finally
                {
                    fileSystem?.Dispose();
                }
            }
        }
예제 #29
0
            static Result Mount(FileSystemClient fs, U8Span mountName, ContentStorageId storageId)
            {
                // It can take some time for the system partition to be ready (if it's on the SD card).
                // Thus, we will retry up to 10 times, waiting one second each time.
                const int maxRetries    = 10;
                const int retryInterval = 1000;

                Result rc = fs.Impl.CheckMountNameAcceptingReservedMountName(mountName);

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

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

                ReferenceCountedDisposable <IFileSystemSf> fileSystem = null;

                try
                {
                    for (int i = 0; i < maxRetries; i++)
                    {
                        rc = fsProxy.Target.OpenContentStorageFileSystem(out fileSystem, storageId);

                        if (rc.IsSuccess())
                        {
                            break;
                        }

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

                        if (i == maxRetries - 1)
                        {
                            return(rc);
                        }

                        fs.Hos.Os.SleepThread(TimeSpan.FromMilliSeconds(retryInterval));
                    }

                    var fileSystemAdapter  = new FileSystemServiceObjectAdapter(fileSystem);
                    var mountNameGenerator = new ContentStorageCommonMountNameGenerator(storageId);
                    return(fs.Register(mountName, fileSystemAdapter, mountNameGenerator));
                }
                finally
                {
                    fileSystem?.Dispose();
                }
            }
예제 #30
0
        public Result OpenBisStorage(out ReferenceCountedDisposable <IStorageSf> storage, BisPartitionId id)
        {
            UnsafeHelpers.SkipParamInit(out storage);

            var storageFlag = StorageType.Bis;

            using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);

            Result rc = GetProgramInfo(out ProgramInfo programInfo);

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

            rc = GetAccessibilityForOpenBisPartition(out Accessibility accessibility, programInfo, id);
            if (rc.IsFailure())
            {
                return(rc);
            }

            bool canAccess = accessibility.CanRead && accessibility.CanWrite;

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

            ReferenceCountedDisposable <IStorage> tempStorage = null;

            try
            {
                rc = _serviceImpl.OpenBisStorage(out tempStorage, id);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                tempStorage = StorageLayoutTypeSetStorage.CreateShared(ref tempStorage, storageFlag);

                // Todo: Async storage

                storage = StorageInterfaceAdapter.CreateShared(ref tempStorage);
                return(Result.Success);
            }
            finally
            {
                tempStorage?.Dispose();
            }
        }