aboutsummaryrefslogtreecommitdiff
path: root/src/core/file_sys
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 15:39:20 +0100
committerGitHub <noreply@github.com>2026-11-02 15:39:20 +0100
commitce1b1de6f1beed36958368f89cda466937ff9716 (patch)
treee3f6d670018b57004915e69d1fc741b4efecb325 /src/core/file_sys
parenta407703f6d29a5ab73328b4ededb12cf29b2758d (diff)
parentc0cb3325e22756edb65c87d33ef298349ade0ad3 (diff)
Merge pull request #291 from Djihads80/nx2-experimental
[Update] Bring the mainline release up to speed with the performance updates from nx2-experimental
Diffstat (limited to 'src/core/file_sys')
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp27
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp19
-rw-r--r--src/core/file_sys/vfs/vfs_real.cpp37
-rw-r--r--src/core/file_sys/vfs/vfs_real.h8
4 files changed, 60 insertions, 31 deletions
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 8807bbd0f7..d34e24f177 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -55,15 +55,18 @@ static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size
struct RomFSBuildFileContext;
+// The context's directories and files own the nodes; the links between them don't, or every
+// parent and child would own each other and no build would ever be freed (title 1's loose RomFS:
+// 206k files, ~50 MiB per build).
struct RomFSBuildDirectoryContext {
std::string path;
u32 cur_path_ofs = 0;
u32 path_len = 0;
u32 entry_offset = 0;
- std::shared_ptr<RomFSBuildDirectoryContext> parent;
- std::shared_ptr<RomFSBuildDirectoryContext> child;
- std::shared_ptr<RomFSBuildDirectoryContext> sibling;
- std::shared_ptr<RomFSBuildFileContext> file;
+ RomFSBuildDirectoryContext* parent = nullptr;
+ RomFSBuildDirectoryContext* child = nullptr;
+ RomFSBuildDirectoryContext* sibling = nullptr;
+ RomFSBuildFileContext* file = nullptr;
};
struct RomFSBuildFileContext {
@@ -73,8 +76,8 @@ struct RomFSBuildFileContext {
u32 entry_offset = 0;
u64 offset = 0;
u64 size = 0;
- std::shared_ptr<RomFSBuildDirectoryContext> parent;
- std::shared_ptr<RomFSBuildFileContext> sibling;
+ RomFSBuildDirectoryContext* parent = nullptr;
+ RomFSBuildFileContext* sibling = nullptr;
VirtualFile source;
};
@@ -168,7 +171,7 @@ bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext>
num_dirs++;
dir_table_size +=
sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
- dir_ctx->parent = std::move(parent_dir_ctx);
+ dir_ctx->parent = parent_dir_ctx.get();
directories.emplace_back(std::move(dir_ctx));
return true;
@@ -180,7 +183,7 @@ bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> pare
num_files++;
file_table_size +=
sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
- file_ctx->parent = std::move(parent_dir_ctx);
+ file_ctx->parent = parent_dir_ctx.get();
files.emplace_back(std::move(file_ctx));
return true;
@@ -245,11 +248,11 @@ std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() {
Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
prev_file = cur_file;
}
- // Assign deferred parent/sibling ownership.
+ // Assign deferred parent/sibling links.
for (auto it = files.rbegin(); it != files.rend(); ++it) {
auto& cur_file = *it;
cur_file->sibling = cur_file->parent->file;
- cur_file->parent->file = cur_file;
+ cur_file->parent->file = cur_file.get();
}
// Determine directory offsets.
@@ -260,11 +263,11 @@ std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() {
static_cast<u32>(sizeof(RomFSDirectoryEntry) +
Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
}
- // Assign deferred parent/sibling ownership.
+ // Assign deferred parent/sibling links.
for (auto it = directories.rbegin(); (*it) != root; ++it) {
auto& cur_dir = *it;
cur_dir->sibling = cur_dir->parent->child;
- cur_dir->parent->child = cur_dir;
+ cur_dir->parent->child = cur_dir.get();
}
// Create output map.
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
index 1743d01b12..c3931b6f62 100644
--- a/src/core/file_sys/system_archive/system_archive.cpp
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -4,6 +4,8 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <cstdlib>
+
#include "common/logging.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/mii_model.h"
@@ -12,6 +14,7 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/system_archive/time_zone_binary.h"
+#include "core/file_sys/vfs/vfs_vector.h"
namespace FileSys::SystemArchive {
@@ -76,6 +79,22 @@ constexpr inline SystemArchiveDescriptor GetSystemArchive(u64 title_id) {
VirtualFile SynthesizeSystemArchive(const u64 title_id) {
auto const desc = GetSystemArchive(title_id);
+ if (desc.name == nullptr) {
+ // Not a system archive Eden knows (fmt throws on a null string, ending the process).
+ // Switch 2 system data (ids 04...) is not installed with Switch 1 firmware, and titles
+ // abort when it cannot be mounted (Nintendo Switch Sports Resort, 0400000000000849):
+ // serve an empty archive. EDEN_NX2_EMPTY_SYSTEM_DATA=0 fails the request instead.
+ static const bool empty_nx2 = [] {
+ const char* setting = std::getenv("EDEN_NX2_EMPTY_SYSTEM_DATA");
+ return setting == nullptr || setting[0] != '0';
+ }();
+ if (empty_nx2 && (title_id >> 56) == 0x04) {
+ LOG_WARNING(Service_FS, "Empty archive for Switch 2 system data {:#016x}", title_id);
+ return CreateRomFS(std::make_shared<VectorVfsDirectory>());
+ }
+ LOG_WARNING(Service_FS, "No system archive {:#016x} to synthesize", title_id);
+ return nullptr;
+ }
LOG_INFO(Service_FS, "Synthesizing system archive '{}' ({:#016x}).", desc.name, title_id);
if (desc.supplier != nullptr) {
if (auto const dir = desc.supplier(); dir != nullptr) {
diff --git a/src/core/file_sys/vfs/vfs_real.cpp b/src/core/file_sys/vfs/vfs_real.cpp
index 5b5b54017c..7cc5315a70 100644
--- a/src/core/file_sys/vfs/vfs_real.cpp
+++ b/src/core/file_sys/vfs/vfs_real.cpp
@@ -114,7 +114,6 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
}
VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
- std::optional<std::string> parent_path,
OpenMode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
std::scoped_lock lk{list_lock};
@@ -132,14 +131,14 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
auto reference = std::make_unique<FileReference>();
this->InsertReferenceIntoListLocked(*reference);
- auto file = std::make_shared<RealVfsFile>(*this, std::move(reference), path, perms, size, std::move(parent_path));
+ auto file = std::make_shared<RealVfsFile>(*this, std::move(reference), path, perms, size);
cache[path] = file;
return file;
}
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) {
- return OpenFileFromEntry(path_, {}, {}, perms);
+ return OpenFileFromEntry(path_, {}, perms);
}
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) {
@@ -257,7 +256,8 @@ std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::stri
return lk;
}
-void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
+void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference,
+ const std::string& path) {
if (in_dtor)
return;
@@ -266,6 +266,11 @@ void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference
// Remove from list.
this->RemoveReferenceFromListLocked(*reference);
+ // Forget the path, unless it was opened again since this file's last reference went away.
+ if (const auto it = cache.find(path); it != cache.end() && it->second.expired()) {
+ cache.erase(it);
+ }
+
// Close the file.
if (reference->file) {
reference->file.reset();
@@ -309,14 +314,11 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference)
}
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
- const std::string& path_, OpenMode perms_, std::optional<u64> size_,
- std::optional<std::string> parent_path_)
- : base(base_), reference(std::move(reference_)), path(path_),
- parent_path(parent_path_ ? std::move(*parent_path_) : FS::GetParentPath(path_)),
- path_components(FS::SplitPathComponentsCopy(path_)), size(size_), perms(perms_) {}
+ const std::string& path_, OpenMode perms_, std::optional<u64> size_)
+ : base(base_), reference(std::move(reference_)), path(path_), size(size_), perms(perms_) {}
RealVfsFile::~RealVfsFile() {
- base.DropReference(std::move(reference));
+ base.DropReference(std::move(reference), path);
}
std::string RealVfsFile::GetName() const {
@@ -325,7 +327,14 @@ std::string RealVfsFile::GetName() const {
return FS::Android::GetFilename(path);
}
#endif
- return path_components.empty() ? "" : std::string(path_components.back());
+ // The last path component.
+ const auto end = path.find_last_not_of("\\/");
+ if (end == std::string::npos) {
+ return "";
+ }
+ const auto separator = path.find_last_of("\\/", end);
+ const auto begin = separator == std::string::npos ? 0 : separator + 1;
+ return path.substr(begin, end + 1 - begin);
}
std::size_t RealVfsFile::GetSize() const {
@@ -343,7 +352,7 @@ bool RealVfsFile::Resize(std::size_t new_size) {
}
VirtualDir RealVfsFile::GetContainingDirectory() const {
- return base.OpenDirectory(parent_path, perms);
+ return base.OpenDirectory(FS::GetParentPath(path), perms);
}
bool RealVfsFile::IsWritable() const {
@@ -372,7 +381,7 @@ std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t o
}
bool RealVfsFile::Rename(std::string_view name) {
- return base.MoveFile(path, parent_path + '/' + std::string(name)) != nullptr;
+ return base.MoveFile(path, FS::GetParentPath(path) + '/' + std::string(name)) != nullptr;
}
// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if
@@ -390,7 +399,7 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
&out](const std::filesystem::directory_entry& entry) {
const auto full_path_string = FS::PathToUTF8String(entry.path());
- out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), path, perms));
+ out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms));
return true;
};
diff --git a/src/core/file_sys/vfs/vfs_real.h b/src/core/file_sys/vfs/vfs_real.h
index a97f7d32ea..2df125b7eb 100644
--- a/src/core/file_sys/vfs/vfs_real.h
+++ b/src/core/file_sys/vfs/vfs_real.h
@@ -62,12 +62,11 @@ private:
friend class RealVfsFile;
std::unique_lock<std::mutex> RefreshReference(const std::string& path, OpenMode perms,
FileReference& reference);
- void DropReference(std::unique_ptr<FileReference>&& reference);
+ void DropReference(std::unique_ptr<FileReference>&& reference, const std::string& path);
private:
friend class RealVfsDirectory;
VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
- std::optional<std::string> parent_path,
OpenMode perms = OpenMode::Read);
private:
@@ -84,7 +83,7 @@ class RealVfsFile : public VfsFile {
public:
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
const std::string& path, OpenMode perms = OpenMode::Read,
- std::optional<u64> size = {}, std::optional<std::string> parent_path = {});
+ std::optional<u64> size = {});
~RealVfsFile() override;
std::string GetName() const override;
@@ -101,9 +100,8 @@ private:
RealVfsFilesystem& base;
std::unique_ptr<FileReference> reference;
+ // Only the path: a loose RomFS keeps one of these per file (title 1: 206k).
std::string path;
- std::string parent_path;
- std::vector<std::string> path_components;
std::optional<u64> size;
OpenMode perms;
};