From 389d3d630eca8b7147c95e08c266f593f49c60bf Mon Sep 17 00:00:00 2001
From: Weiyi Wang <wwylele@gmail.com>
Date: Sat, 29 Sep 2018 12:39:31 -0400
Subject: [PATCH] fs/archive: wrap states into archive manager

---
 src/core/core.cpp                   |  10 +
 src/core/core.h                     |  11 +
 src/core/hle/service/fs/archive.cpp | 112 ++++-----
 src/core/hle/service/fs/archive.h   | 351 +++++++++++++++-------------
 src/core/hle/service/fs/fs_user.cpp |  58 ++---
 src/core/hle/service/fs/fs_user.h   |   6 +-
 src/core/hle/service/service.cpp    |   2 -
 src/core/loader/3dsx.cpp            |   4 +-
 src/core/loader/ncch.cpp            |   3 +-
 9 files changed, 285 insertions(+), 272 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index f16e083a8..99cf495aa 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -19,6 +19,7 @@
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/service/fs/archive.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hw/hw.h"
@@ -191,6 +192,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
 
     service_manager = std::make_shared<Service::SM::ServiceManager>();
     shared_page_handler = std::make_shared<SharedPage::Handler>();
+    archive_manager = std::make_unique<Service::FS::ArchiveManager>();
 
     HW::Init();
     Kernel::Init(system_mode);
@@ -219,6 +221,14 @@ const Service::SM::ServiceManager& System::ServiceManager() const {
     return *service_manager;
 }
 
+Service::FS::ArchiveManager& System::ArchiveManager() {
+    return *archive_manager;
+}
+
+const Service::FS::ArchiveManager& System::ArchiveManager() const {
+    return *archive_manager;
+}
+
 void System::RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd) {
     registered_swkbd = std::move(swkbd);
 }
diff --git a/src/core/core.h b/src/core/core.h
index 517d53e97..cecd29896 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -31,6 +31,9 @@ namespace Service {
 namespace SM {
 class ServiceManager;
 }
+namespace FS {
+class ArchiveManager;
+}
 } // namespace Service
 
 namespace Core {
@@ -158,6 +161,12 @@ public:
      */
     const Service::SM::ServiceManager& ServiceManager() const;
 
+    /// Gets a reference to the archive manager
+    Service::FS::ArchiveManager& ArchiveManager();
+
+    /// Gets a const reference to the archive manager
+    const Service::FS::ArchiveManager& ArchiveManager() const;
+
     PerfStats perf_stats;
     FrameLimiter frame_limiter;
 
@@ -230,6 +239,8 @@ private:
     /// Shared Page
     std::shared_ptr<SharedPage::Handler> shared_page_handler;
 
+    std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
+
     static System s_instance;
 
     ResultStatus status = ResultStatus::Success;
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index e76ec1e13..0f2375124 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -8,9 +8,7 @@
 #include <memory>
 #include <system_error>
 #include <type_traits>
-#include <unordered_map>
 #include <utility>
-#include <boost/container/flat_map.hpp>
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
@@ -32,27 +30,13 @@
 
 namespace Service::FS {
 
-using FileSys::ArchiveBackend;
-using FileSys::ArchiveFactory;
-
-/**
- * Map of registered archives, identified by id code. Once an archive is registered here, it is
- * never removed until UnregisterArchiveTypes is called.
- */
-static boost::container::flat_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map;
-
-/**
- * Map of active archive handles. Values are pointers to the archives in `idcode_map`.
- */
-static std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map;
-static ArchiveHandle next_handle;
-
-static ArchiveBackend* GetArchive(ArchiveHandle handle) {
+ArchiveBackend* ArchiveManager::GetArchive(ArchiveHandle handle) {
     auto itr = handle_map.find(handle);
     return (itr == handle_map.end()) ? nullptr : itr->second.get();
 }
 
-ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) {
+ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code,
+                                                     FileSys::Path& archive_path) {
     LOG_TRACE(Service_FS, "Opening archive with id code 0x{:08X}", static_cast<u32>(id_code));
 
     auto itr = id_code_map.find(id_code);
@@ -70,7 +54,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
     return MakeResult<ArchiveHandle>(next_handle++);
 }
 
-ResultCode CloseArchive(ArchiveHandle handle) {
+ResultCode ArchiveManager::CloseArchive(ArchiveHandle handle) {
     if (handle_map.erase(handle) == 0)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
     else
@@ -79,8 +63,8 @@ ResultCode CloseArchive(ArchiveHandle handle) {
 
 // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
 // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
-ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
-                               ArchiveIdCode id_code) {
+ResultCode ArchiveManager::RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
+                                               ArchiveIdCode id_code) {
     auto result = id_code_map.emplace(id_code, std::move(factory));
 
     bool inserted = result.second;
@@ -92,9 +76,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
     return RESULT_SUCCESS;
 }
 
-ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
-                                                     const FileSys::Path& path,
-                                                     const FileSys::Mode mode) {
+ResultVal<std::shared_ptr<File>> ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle,
+                                                                     const FileSys::Path& path,
+                                                                     const FileSys::Mode mode) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -107,7 +91,8 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl
     return MakeResult<std::shared_ptr<File>>(std::move(file));
 }
 
-ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
+ResultCode ArchiveManager::DeleteFileFromArchive(ArchiveHandle archive_handle,
+                                                 const FileSys::Path& path) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -115,10 +100,10 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
     return archive->DeleteFile(path);
 }
 
-ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
-                                     const FileSys::Path& src_path,
-                                     ArchiveHandle dest_archive_handle,
-                                     const FileSys::Path& dest_path) {
+ResultCode ArchiveManager::RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
+                                                     const FileSys::Path& src_path,
+                                                     ArchiveHandle dest_archive_handle,
+                                                     const FileSys::Path& dest_path) {
     ArchiveBackend* src_archive = GetArchive(src_archive_handle);
     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
     if (src_archive == nullptr || dest_archive == nullptr)
@@ -132,7 +117,8 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
     }
 }
 
-ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
+ResultCode ArchiveManager::DeleteDirectoryFromArchive(ArchiveHandle archive_handle,
+                                                      const FileSys::Path& path) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -140,8 +126,8 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
     return archive->DeleteDirectory(path);
 }
 
-ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle,
-                                                 const FileSys::Path& path) {
+ResultCode ArchiveManager::DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle,
+                                                                 const FileSys::Path& path) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -149,8 +135,8 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle,
     return archive->DeleteDirectoryRecursively(path);
 }
 
-ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
-                               u64 file_size) {
+ResultCode ArchiveManager::CreateFileInArchive(ArchiveHandle archive_handle,
+                                               const FileSys::Path& path, u64 file_size) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -158,7 +144,8 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path
     return archive->CreateFile(path, file_size);
 }
 
-ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
+ResultCode ArchiveManager::CreateDirectoryFromArchive(ArchiveHandle archive_handle,
+                                                      const FileSys::Path& path) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -166,10 +153,10 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
     return archive->CreateDirectory(path);
 }
 
-ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
-                                          const FileSys::Path& src_path,
-                                          ArchiveHandle dest_archive_handle,
-                                          const FileSys::Path& dest_path) {
+ResultCode ArchiveManager::RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
+                                                          const FileSys::Path& src_path,
+                                                          ArchiveHandle dest_archive_handle,
+                                                          const FileSys::Path& dest_path) {
     ArchiveBackend* src_archive = GetArchive(src_archive_handle);
     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
     if (src_archive == nullptr || dest_archive == nullptr)
@@ -183,8 +170,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
     }
 }
 
-ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
-                                                               const FileSys::Path& path) {
+ResultVal<std::shared_ptr<Directory>> ArchiveManager::OpenDirectoryFromArchive(
+    ArchiveHandle archive_handle, const FileSys::Path& path) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
@@ -197,15 +184,16 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc
     return MakeResult<std::shared_ptr<Directory>>(std::move(directory));
 }
 
-ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
+ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handle) {
     ArchiveBackend* archive = GetArchive(archive_handle);
     if (archive == nullptr)
         return FileSys::ERR_INVALID_ARCHIVE_HANDLE;
     return MakeResult<u64>(archive->GetFreeBytes());
 }
 
-ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
-                         const FileSys::Path& path) {
+ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code,
+                                         const FileSys::ArchiveFormatInfo& format_info,
+                                         const FileSys::Path& path) {
     auto archive_itr = id_code_map.find(id_code);
     if (archive_itr == id_code_map.end()) {
         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
@@ -214,8 +202,8 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo
     return archive_itr->second->Format(path, format_info);
 }
 
-ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code,
-                                                           FileSys::Path& archive_path) {
+ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo(
+    ArchiveIdCode id_code, FileSys::Path& archive_path) {
     auto archive = id_code_map.find(id_code);
     if (archive == id_code_map.end()) {
         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
@@ -224,9 +212,9 @@ ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code
     return archive->second->GetFormatInfo(archive_path);
 }
 
-ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
-                             const std::vector<u8>& smdh_icon,
-                             const FileSys::ArchiveFormatInfo& format_info) {
+ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low,
+                                             const std::vector<u8>& smdh_icon,
+                                             const FileSys::ArchiveFormatInfo& format_info) {
     // Construct the binary path to the archive first
     FileSys::Path path =
         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
@@ -248,7 +236,7 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
     return RESULT_SUCCESS;
 }
 
-ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
+ResultCode ArchiveManager::DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
     // Construct the binary path to the archive first
     FileSys::Path path =
         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
@@ -272,7 +260,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
     return RESULT_SUCCESS;
 }
 
-ResultCode DeleteSystemSaveData(u32 high, u32 low) {
+ResultCode ArchiveManager::DeleteSystemSaveData(u32 high, u32 low) {
     // Construct the binary path to the archive first
     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low);
 
@@ -284,7 +272,7 @@ ResultCode DeleteSystemSaveData(u32 high, u32 low) {
     return RESULT_SUCCESS;
 }
 
-ResultCode CreateSystemSaveData(u32 high, u32 low) {
+ResultCode ArchiveManager::CreateSystemSaveData(u32 high, u32 low) {
     // Construct the binary path to the archive first
     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low);
 
@@ -296,7 +284,7 @@ ResultCode CreateSystemSaveData(u32 high, u32 low) {
     return RESULT_SUCCESS;
 }
 
-void RegisterArchiveTypes() {
+void ArchiveManager::RegisterArchiveTypes() {
     // TODO(Subv): Add the other archive types (see here for the known types:
     // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
 
@@ -348,7 +336,7 @@ void RegisterArchiveTypes() {
     RegisterArchiveType(std::move(selfncch_factory), ArchiveIdCode::SelfNCCH);
 }
 
-void RegisterSelfNCCH(Loader::AppLoader& app_loader) {
+void ArchiveManager::RegisterSelfNCCH(Loader::AppLoader& app_loader) {
     auto itr = id_code_map.find(ArchiveIdCode::SelfNCCH);
     if (itr == id_code_map.end()) {
         LOG_ERROR(Service_FS,
@@ -360,20 +348,8 @@ void RegisterSelfNCCH(Loader::AppLoader& app_loader) {
     factory->Register(app_loader);
 }
 
-void UnregisterArchiveTypes() {
-    id_code_map.clear();
-}
-
-/// Initialize archives
-void ArchiveInit() {
-    next_handle = 1;
+ArchiveManager::ArchiveManager() {
     RegisterArchiveTypes();
 }
 
-/// Shutdown archives
-void ArchiveShutdown() {
-    handle_map.clear();
-    UnregisterArchiveTypes();
-}
-
 } // namespace Service::FS
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 4c568097c..ef9b9efc2 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -6,7 +6,9 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
+#include <boost/container/flat_map.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -43,196 +45,209 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
 
 typedef u64 ArchiveHandle;
 
-/**
- * Opens an archive
- * @param id_code IdCode of the archive to open
- * @param archive_path Path to the archive, used with Binary paths
- * @return Handle to the opened archive
- */
-ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path);
+using FileSys::ArchiveBackend;
+using FileSys::ArchiveFactory;
 
-/**
- * Closes an archive
- * @param handle Handle to the archive to close
- */
-ResultCode CloseArchive(ArchiveHandle handle);
+class ArchiveManager {
+public:
+    ArchiveManager();
+    /**
+     * Opens an archive
+     * @param id_code IdCode of the archive to open
+     * @param archive_path Path to the archive, used with Binary paths
+     * @return Handle to the opened archive
+     */
+    ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path);
 
-/**
- * Registers an Archive type, instances of which can later be opened using its IdCode.
- * @param factory File system backend interface to the archive
- * @param id_code Id code used to access this type of archive
- */
-ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
-                               ArchiveIdCode id_code);
+    /**
+     * Closes an archive
+     * @param handle Handle to the archive to close
+     */
+    ResultCode CloseArchive(ArchiveHandle handle);
 
-/**
- * Open a File from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the File inside of the Archive
- * @param mode Mode under which to open the File
- * @return The opened File object
- */
-ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
-                                                     const FileSys::Path& path,
-                                                     const FileSys::Mode mode);
+    /**
+     * Open a File from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the File inside of the Archive
+     * @param mode Mode under which to open the File
+     * @return The opened File object
+     */
+    ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
+                                                         const FileSys::Path& path,
+                                                         const FileSys::Mode mode);
 
-/**
- * Delete a File from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the File inside of the Archive
- * @return Whether deletion succeeded
- */
-ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
+    /**
+     * Delete a File from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the File inside of the Archive
+     * @return Whether deletion succeeded
+     */
+    ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
 
-/**
- * Rename a File between two Archives
- * @param src_archive_handle Handle to the source Archive object
- * @param src_path Path to the File inside of the source Archive
- * @param dest_archive_handle Handle to the destination Archive object
- * @param dest_path Path to the File inside of the destination Archive
- * @return Whether rename succeeded
- */
-ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
-                                     const FileSys::Path& src_path,
-                                     ArchiveHandle dest_archive_handle,
-                                     const FileSys::Path& dest_path);
+    /**
+     * Rename a File between two Archives
+     * @param src_archive_handle Handle to the source Archive object
+     * @param src_path Path to the File inside of the source Archive
+     * @param dest_archive_handle Handle to the destination Archive object
+     * @param dest_path Path to the File inside of the destination Archive
+     * @return Whether rename succeeded
+     */
+    ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
+                                         const FileSys::Path& src_path,
+                                         ArchiveHandle dest_archive_handle,
+                                         const FileSys::Path& dest_path);
 
-/**
- * Delete a Directory from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the Directory inside of the Archive
- * @return Whether deletion succeeded
- */
-ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
+    /**
+     * Delete a Directory from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the Directory inside of the Archive
+     * @return Whether deletion succeeded
+     */
+    ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
 
-/**
- * Delete a Directory and anything under it from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the Directory inside of the Archive
- * @return Whether deletion succeeded
- */
-ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle,
-                                                 const FileSys::Path& path);
+    /**
+     * Delete a Directory and anything under it from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the Directory inside of the Archive
+     * @return Whether deletion succeeded
+     */
+    ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle,
+                                                     const FileSys::Path& path);
 
-/**
- * Create a File in an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the File inside of the Archive
- * @param file_size The size of the new file, filled with zeroes
- * @return File creation result code
- */
-ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
-                               u64 file_size);
+    /**
+     * Create a File in an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the File inside of the Archive
+     * @param file_size The size of the new file, filled with zeroes
+     * @return File creation result code
+     */
+    ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
+                                   u64 file_size);
 
-/**
- * Create a Directory from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the Directory inside of the Archive
- * @return Whether creation of directory succeeded
- */
-ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
+    /**
+     * Create a Directory from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the Directory inside of the Archive
+     * @return Whether creation of directory succeeded
+     */
+    ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
 
-/**
- * Rename a Directory between two Archives
- * @param src_archive_handle Handle to the source Archive object
- * @param src_path Path to the Directory inside of the source Archive
- * @param dest_archive_handle Handle to the destination Archive object
- * @param dest_path Path to the Directory inside of the destination Archive
- * @return Whether rename succeeded
- */
-ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
-                                          const FileSys::Path& src_path,
-                                          ArchiveHandle dest_archive_handle,
-                                          const FileSys::Path& dest_path);
+    /**
+     * Rename a Directory between two Archives
+     * @param src_archive_handle Handle to the source Archive object
+     * @param src_path Path to the Directory inside of the source Archive
+     * @param dest_archive_handle Handle to the destination Archive object
+     * @param dest_path Path to the Directory inside of the destination Archive
+     * @return Whether rename succeeded
+     */
+    ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
+                                              const FileSys::Path& src_path,
+                                              ArchiveHandle dest_archive_handle,
+                                              const FileSys::Path& dest_path);
 
-/**
- * Open a Directory from an Archive
- * @param archive_handle Handle to an open Archive object
- * @param path Path to the Directory inside of the Archive
- * @return The opened Directory object
- */
-ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
-                                                               const FileSys::Path& path);
+    /**
+     * Open a Directory from an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @param path Path to the Directory inside of the Archive
+     * @return The opened Directory object
+     */
+    ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
+                                                                   const FileSys::Path& path);
 
-/**
- * Get the free space in an Archive
- * @param archive_handle Handle to an open Archive object
- * @return The number of free bytes in the archive
- */
-ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
+    /**
+     * Get the free space in an Archive
+     * @param archive_handle Handle to an open Archive object
+     * @return The number of free bytes in the archive
+     */
+    ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
 
-/**
- * Erases the contents of the physical folder that contains the archive
- * identified by the specified id code and path
- * @param id_code The id of the archive to format
- * @param format_info Format information about the new archive
- * @param path The path to the archive, if relevant.
- * @return ResultCode 0 on success or the corresponding code on error
- */
-ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
-                         const FileSys::Path& path = FileSys::Path());
+    /**
+     * Erases the contents of the physical folder that contains the archive
+     * identified by the specified id code and path
+     * @param id_code The id of the archive to format
+     * @param format_info Format information about the new archive
+     * @param path The path to the archive, if relevant.
+     * @return ResultCode 0 on success or the corresponding code on error
+     */
+    ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
+                             const FileSys::Path& path = FileSys::Path());
 
-/**
- * Retrieves the format info about the archive of the specified type and path.
- * The format info is supplied by the client code when creating archives.
- * @param id_code The id of the archive
- * @param archive_path The path of the archive, if relevant
- * @return The format info of the archive, or the corresponding error code if failed.
- */
-ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code,
-                                                           FileSys::Path& archive_path);
+    /**
+     * Retrieves the format info about the archive of the specified type and path.
+     * The format info is supplied by the client code when creating archives.
+     * @param id_code The id of the archive
+     * @param archive_path The path of the archive, if relevant
+     * @return The format info of the archive, or the corresponding error code if failed.
+     */
+    ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code,
+                                                               FileSys::Path& archive_path);
 
-/**
- * Creates a blank SharedExtSaveData archive for the specified extdata ID
- * @param media_type The media type of the archive to create (NAND / SDMC)
- * @param high The high word of the extdata id to create
- * @param low The low word of the extdata id to create
- * @param smdh_icon the SMDH icon for this ExtSaveData
- * @param format_info Format information about the new archive
- * @return ResultCode 0 on success or the corresponding code on error
- */
-ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
-                             const std::vector<u8>& smdh_icon,
-                             const FileSys::ArchiveFormatInfo& format_info);
+    /**
+     * Creates a blank SharedExtSaveData archive for the specified extdata ID
+     * @param media_type The media type of the archive to create (NAND / SDMC)
+     * @param high The high word of the extdata id to create
+     * @param low The low word of the extdata id to create
+     * @param smdh_icon the SMDH icon for this ExtSaveData
+     * @param format_info Format information about the new archive
+     * @return ResultCode 0 on success or the corresponding code on error
+     */
+    ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
+                                 const std::vector<u8>& smdh_icon,
+                                 const FileSys::ArchiveFormatInfo& format_info);
 
-/**
- * Deletes the SharedExtSaveData archive for the specified extdata ID
- * @param media_type The media type of the archive to delete (NAND / SDMC)
- * @param high The high word of the extdata id to delete
- * @param low The low word of the extdata id to delete
- * @return ResultCode 0 on success or the corresponding code on error
- */
-ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low);
+    /**
+     * Deletes the SharedExtSaveData archive for the specified extdata ID
+     * @param media_type The media type of the archive to delete (NAND / SDMC)
+     * @param high The high word of the extdata id to delete
+     * @param low The low word of the extdata id to delete
+     * @return ResultCode 0 on success or the corresponding code on error
+     */
+    ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low);
 
-/**
- * Deletes the SystemSaveData archive folder for the specified save data id
- * @param high The high word of the SystemSaveData archive to delete
- * @param low The low word of the SystemSaveData archive to delete
- * @return ResultCode 0 on success or the corresponding code on error
- */
-ResultCode DeleteSystemSaveData(u32 high, u32 low);
+    /**
+     * Deletes the SystemSaveData archive folder for the specified save data id
+     * @param high The high word of the SystemSaveData archive to delete
+     * @param low The low word of the SystemSaveData archive to delete
+     * @return ResultCode 0 on success or the corresponding code on error
+     */
+    ResultCode DeleteSystemSaveData(u32 high, u32 low);
 
-/**
- * Creates the SystemSaveData archive folder for the specified save data id
- * @param high The high word of the SystemSaveData archive to create
- * @param low The low word of the SystemSaveData archive to create
- * @return ResultCode 0 on success or the corresponding code on error
- */
-ResultCode CreateSystemSaveData(u32 high, u32 low);
+    /**
+     * Creates the SystemSaveData archive folder for the specified save data id
+     * @param high The high word of the SystemSaveData archive to create
+     * @param low The low word of the SystemSaveData archive to create
+     * @return ResultCode 0 on success or the corresponding code on error
+     */
+    ResultCode CreateSystemSaveData(u32 high, u32 low);
 
-/// Initialize archives
-void ArchiveInit();
+    /// Registers a new NCCH file with the SelfNCCH archive factory
+    void RegisterSelfNCCH(Loader::AppLoader& app_loader);
 
-/// Shutdown archives
-void ArchiveShutdown();
+private:
+    /**
+     * Registers an Archive type, instances of which can later be opened using its IdCode.
+     * @param factory File system backend interface to the archive
+     * @param id_code Id code used to access this type of archive
+     */
+    ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
+                                   ArchiveIdCode id_code);
 
-/// Registers a new NCCH file with the SelfNCCH archive factory
-void RegisterSelfNCCH(Loader::AppLoader& app_loader);
+    /// Register all archive types
+    void RegisterArchiveTypes();
 
-/// Register all archive types
-void RegisterArchiveTypes();
+    ArchiveBackend* GetArchive(ArchiveHandle handle);
 
-/// Unregister all archive types
-void UnregisterArchiveTypes();
+    /**
+     * Map of registered archives, identified by id code. Once an archive is registered here, it is
+     * never removed until UnregisterArchiveTypes is called.
+     */
+    boost::container::flat_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map;
+
+    /**
+     * Map of active archive handles to archive objects
+     */
+    std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map;
+    ArchiveHandle next_handle = 1;
+};
 
 } // namespace Service::FS
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index daa7bb237..4386fd608 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -56,7 +56,7 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_FS, "path={}, mode={} attrs={}", file_path.DebugStr(), mode.hex, attributes);
 
     ResultVal<std::shared_ptr<File>> file_res =
-        OpenFileFromArchive(archive_handle, file_path, mode);
+        archives.OpenFileFromArchive(archive_handle, file_path, mode);
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
     rb.Push(file_res.Code());
     if (file_res.Succeeded()) {
@@ -92,7 +92,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
 
-    ResultVal<ArchiveHandle> archive_handle = Service::FS::OpenArchive(archive_id, archive_path);
+    ResultVal<ArchiveHandle> archive_handle = archives.OpenArchive(archive_id, archive_path);
     if (archive_handle.Failed()) {
         LOG_ERROR(Service_FS,
                   "Failed to get a handle for archive archive_id=0x{:08X} archive_path={}",
@@ -101,10 +101,10 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
         rb.PushMoveObjects<Kernel::Object>(nullptr);
         return;
     }
-    SCOPE_EXIT({ Service::FS::CloseArchive(*archive_handle); });
+    SCOPE_EXIT({ archives.CloseArchive(*archive_handle); });
 
     ResultVal<std::shared_ptr<File>> file_res =
-        OpenFileFromArchive(*archive_handle, file_path, mode);
+        archives.OpenFileFromArchive(*archive_handle, file_path, mode);
     rb.Push(file_res.Code());
     if (file_res.Succeeded()) {
         std::shared_ptr<File> file = *file_res;
@@ -131,7 +131,7 @@ void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) {
               file_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(DeleteFileFromArchive(archive_handle, file_path));
+    rb.Push(archives.DeleteFileFromArchive(archive_handle, file_path));
 }
 
 void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) {
@@ -158,8 +158,8 @@ void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) {
               static_cast<u32>(dest_filename_type), dest_filename_size, dest_file_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle,
-                                      dest_file_path));
+    rb.Push(archives.RenameFileBetweenArchives(src_archive_handle, src_file_path,
+                                               dest_archive_handle, dest_file_path));
 }
 
 void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) {
@@ -178,7 +178,7 @@ void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) {
               dir_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(DeleteDirectoryFromArchive(archive_handle, dir_path));
+    rb.Push(archives.DeleteDirectoryFromArchive(archive_handle, dir_path));
 }
 
 void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
@@ -197,7 +197,7 @@ void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
               dir_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(DeleteDirectoryRecursivelyFromArchive(archive_handle, dir_path));
+    rb.Push(archives.DeleteDirectoryRecursivelyFromArchive(archive_handle, dir_path));
 }
 
 void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) {
@@ -218,7 +218,7 @@ void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) {
               static_cast<u32>(filename_type), attributes, file_size, file_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(CreateFileInArchive(archive_handle, file_path, file_size));
+    rb.Push(archives.CreateFileInArchive(archive_handle, file_path, file_size));
 }
 
 void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) {
@@ -236,7 +236,7 @@ void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) {
               dir_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(CreateDirectoryFromArchive(archive_handle, dir_path));
+    rb.Push(archives.CreateDirectoryFromArchive(archive_handle, dir_path));
 }
 
 void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) {
@@ -262,8 +262,8 @@ void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) {
               static_cast<u32>(dest_dirname_type), dest_dirname_size, dest_dir_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle,
-                                           dest_dir_path));
+    rb.Push(archives.RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path,
+                                                    dest_archive_handle, dest_dir_path));
 }
 
 void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) {
@@ -281,7 +281,7 @@ void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
     ResultVal<std::shared_ptr<Directory>> dir_res =
-        OpenDirectoryFromArchive(archive_handle, dir_path);
+        archives.OpenDirectoryFromArchive(archive_handle, dir_path);
     rb.Push(dir_res.Code());
     if (dir_res.Succeeded()) {
         std::shared_ptr<Directory> directory = *dir_res;
@@ -308,7 +308,7 @@ void FS_USER::OpenArchive(Kernel::HLERequestContext& ctx) {
               archive_path.DebugStr());
 
     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
-    ResultVal<ArchiveHandle> handle = Service::FS::OpenArchive(archive_id, archive_path);
+    ResultVal<ArchiveHandle> handle = archives.OpenArchive(archive_id, archive_path);
     rb.Push(handle.Code());
     if (handle.Succeeded()) {
         rb.PushRaw(*handle);
@@ -325,7 +325,7 @@ void FS_USER::CloseArchive(Kernel::HLERequestContext& ctx) {
     auto archive_handle = rp.PopRaw<ArchiveHandle>();
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(Service::FS::CloseArchive(archive_handle));
+    rb.Push(archives.CloseArchive(archive_handle));
 }
 
 void FS_USER::IsSdmcDetected(Kernel::HLERequestContext& ctx) {
@@ -384,7 +384,7 @@ void FS_USER::FormatSaveData(Kernel::HLERequestContext& ctx) {
     format_info.number_files = number_files;
     format_info.total_size = block_size * 512;
 
-    rb.Push(FormatArchive(ArchiveIdCode::SaveData, format_info));
+    rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info));
 }
 
 void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) {
@@ -403,7 +403,7 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) {
     format_info.total_size = block_size * 512;
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(FormatArchive(ArchiveIdCode::SaveData, format_info));
+    rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info));
 
     LOG_TRACE(Service_FS, "called");
 }
@@ -411,7 +411,7 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) {
 void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x812, 2, 0);
     ArchiveHandle archive_handle = rp.PopRaw<ArchiveHandle>();
-    ResultVal<u64> bytes_res = GetFreeBytesInArchive(archive_handle);
+    ResultVal<u64> bytes_res = archives.GetFreeBytesInArchive(archive_handle);
 
     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
     rb.Push(bytes_res.Code());
@@ -445,7 +445,7 @@ void FS_USER::CreateExtSaveData(Kernel::HLERequestContext& ctx) {
     format_info.total_size = 0;
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
-    rb.Push(Service::FS::CreateExtSaveData(media_type, save_high, save_low, icon, format_info));
+    rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info));
     rb.PushMappedBuffer(icon_buffer);
 
     LOG_DEBUG(Service_FS,
@@ -462,7 +462,7 @@ void FS_USER::DeleteExtSaveData(Kernel::HLERequestContext& ctx) {
     u32 unknown = rp.Pop<u32>(); // TODO(Subv): Figure out what this is
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(Service::FS::DeleteExtSaveData(media_type, save_high, save_low));
+    rb.Push(archives.DeleteExtSaveData(media_type, save_high, save_low));
 
     LOG_DEBUG(Service_FS,
               "called, save_low={:08X} save_high={:08X} media_type={:08X} unknown={:08X}", save_low,
@@ -483,7 +483,7 @@ void FS_USER::DeleteSystemSaveData(Kernel::HLERequestContext& ctx) {
     u32 savedata_low = rp.Pop<u32>();
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(Service::FS::DeleteSystemSaveData(savedata_high, savedata_low));
+    rb.Push(archives.DeleteSystemSaveData(savedata_high, savedata_low));
 }
 
 void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) {
@@ -506,7 +506,7 @@ void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) {
         file_buckets, duplicate);
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(Service::FS::CreateSystemSaveData(savedata_high, savedata_low));
+    rb.Push(archives.CreateSystemSaveData(savedata_high, savedata_low));
 }
 
 void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) {
@@ -528,7 +528,7 @@ void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
     // With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND)
-    rb.Push(Service::FS::CreateSystemSaveData(0, savedata_id));
+    rb.Push(archives.CreateSystemSaveData(0, savedata_id));
 }
 
 void FS_USER::InitializeWithSdkVersion(Kernel::HLERequestContext& ctx) {
@@ -595,7 +595,7 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
 
-    auto format_info = GetArchiveFormatInfo(archive_id, archive_path);
+    auto format_info = archives.GetArchiveFormatInfo(archive_id, archive_path);
     rb.Push(format_info.Code());
     if (format_info.Failed()) {
         LOG_ERROR(Service_FS, "Failed to retrieve the format info");
@@ -663,7 +663,7 @@ void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) {
     format_info.total_size = 0;
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
-    rb.Push(Service::FS::CreateExtSaveData(media_type, save_high, save_low, icon, format_info));
+    rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info));
     rb.PushMappedBuffer(icon_buffer);
 
     LOG_DEBUG(Service_FS,
@@ -678,7 +678,7 @@ void FS_USER::ObsoletedDeleteExtSaveData(Kernel::HLERequestContext& ctx) {
     u32 save_low = rp.Pop<u32>();
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-    rb.Push(Service::FS::DeleteExtSaveData(media_type, 0, save_low));
+    rb.Push(archives.DeleteExtSaveData(media_type, 0, save_low));
 
     LOG_DEBUG(Service_FS, "called, save_low={:08X} media_type={:08X}", save_low,
               static_cast<u32>(media_type));
@@ -736,7 +736,7 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) {
     rb.Push<u64>(0);      // the secure value
 }
 
-FS_USER::FS_USER() : ServiceFramework("fs:USER", 30) {
+FS_USER::FS_USER(ArchiveManager& archives) : ServiceFramework("fs:USER", 30), archives(archives) {
     static const FunctionInfo functions[] = {
         {0x000100C6, nullptr, "Dummy1"},
         {0x040100C4, nullptr, "Control"},
@@ -855,6 +855,6 @@ FS_USER::FS_USER() : ServiceFramework("fs:USER", 30) {
 
 void InstallInterfaces(Core::System& system) {
     auto& service_manager = system.ServiceManager();
-    std::make_shared<FS_USER>()->InstallAsService(service_manager);
+    std::make_shared<FS_USER>(system.ArchiveManager())->InstallAsService(service_manager);
 }
 } // namespace Service::FS
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index d8a044dd9..9556c787a 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -13,9 +13,11 @@ class System;
 
 namespace Service::FS {
 
+class ArchiveManager;
+
 class FS_USER final : public ServiceFramework<FS_USER> {
 public:
-    FS_USER();
+    explicit FS_USER(ArchiveManager& archives);
 
 private:
     void Initialize(Kernel::HLERequestContext& ctx);
@@ -519,6 +521,8 @@ private:
     void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx);
 
     u32 priority = -1; ///< For SetPriority and GetPriority service functions
+
+    ArchiveManager& archives;
 };
 
 void InstallInterfaces(Core::System& system);
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 7d6b25d0f..5755d0335 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -236,7 +236,6 @@ static bool AttemptLLE(const ServiceModuleInfo& service_module) {
 
 /// Initialize ServiceManager
 void Init(Core::System& core, std::shared_ptr<SM::ServiceManager>& sm) {
-    FS::ArchiveInit();
     SM::ServiceManager::InstallInterfaces(sm);
 
     for (const auto& service_module : service_module_map) {
@@ -248,7 +247,6 @@ void Init(Core::System& core, std::shared_ptr<SM::ServiceManager>& sm) {
 
 /// Shutdown ServiceManager
 void Shutdown() {
-    FS::ArchiveShutdown();
 
     g_kernel_named_ports.clear();
     LOG_DEBUG(Service, "shutdown OK");
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 5ec3000e8..d791c085c 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -5,7 +5,7 @@
 #include <algorithm>
 #include <vector>
 #include "common/logging/log.h"
-#include "core/file_sys/archive_selfncch.h"
+#include "core/core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/resource_limit.h"
 #include "core/hle/service/fs/archive.h"
@@ -277,7 +277,7 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr<Kernel::Process>& proces
 
     process->Run(48, Kernel::DEFAULT_STACK_SIZE);
 
-    Service::FS::RegisterSelfNCCH(*this);
+    Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this);
 
     is_loaded = true;
     return ResultStatus::Success;
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 12301cb94..c2a0ce0ab 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -14,7 +14,6 @@
 #include "common/string_util.h"
 #include "common/swap.h"
 #include "core/core.h"
-#include "core/file_sys/archive_selfncch.h"
 #include "core/file_sys/ncch_container.h"
 #include "core/file_sys/title_metadata.h"
 #include "core/hle/kernel/process.h"
@@ -185,7 +184,7 @@ ResultStatus AppLoader_NCCH::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     if (ResultStatus::Success != result)
         return result;
 
-    Service::FS::RegisterSelfNCCH(*this);
+    Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this);
 
     ParseRegionLockoutInfo();