devoptab: use fixed size array of entries rather than vector as vector can change/break pointers when it reallocs. fs: disable loading assoc when mounting custom fs.
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
|
||||
namespace sphaira::devoptab::common {
|
||||
|
||||
// max entries per devoptab, should be enough.
|
||||
enum { MAX_ENTRIES = 4 };
|
||||
|
||||
// buffers data in 512k chunks to maximise throughput.
|
||||
// not suitable if random access >= 512k is common.
|
||||
// if that is needed, see the LRU cache varient used for fatfs.
|
||||
|
||||
@@ -2363,7 +2363,8 @@ void MountFsHelper(const std::shared_ptr<fs::Fs>& fs, const fs::FsPath& name) {
|
||||
.flags = filebrowser::FsEntryFlag_ReadOnly,
|
||||
};
|
||||
|
||||
App::Push<filebrowser::Menu>(fs, fs_entry, fs->Root());
|
||||
const auto options = FsOption_All &~ FsOption_LoadAssoc;
|
||||
App::Push<filebrowser::Menu>(fs, fs_entry, fs->Root(), options);
|
||||
}
|
||||
|
||||
} // namespace sphaira::ui::menu::filebrowser
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
#include "yati/source/file.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
@@ -164,8 +165,6 @@ int devoptab_dirclose(struct _reent *r, DIR_ITER *dirState) {
|
||||
int devoptab_lstat(struct _reent *r, const char *_path, struct stat *st) {
|
||||
auto device = (Device*)r->deviceData;
|
||||
|
||||
log_write("[\t\tDEV] lstat\n");
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (!common::fix_path(_path, path)) {
|
||||
return set_errno(r, ENOENT);
|
||||
@@ -210,17 +209,20 @@ constexpr devoptab_t DEVOPTAB = {
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
Device device;
|
||||
devoptab_t devoptab;
|
||||
fs::FsPath path;
|
||||
fs::FsPath mount;
|
||||
char name[32];
|
||||
s32 ref_count;
|
||||
Device device{};
|
||||
devoptab_t devoptab{};
|
||||
fs::FsPath path{};
|
||||
fs::FsPath mount{};
|
||||
char name[32]{};
|
||||
s32 ref_count{};
|
||||
|
||||
~Entry() {
|
||||
RemoveDevice(mount);
|
||||
}
|
||||
};
|
||||
|
||||
Mutex g_mutex;
|
||||
std::vector<Entry> g_entries;
|
||||
u32 g_mount_idx;
|
||||
std::array<std::unique_ptr<Entry>, common::MAX_ENTRIES> g_entries;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -229,13 +231,20 @@ Result MountNsp(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
|
||||
// check if we already have the save mounted.
|
||||
for (auto& e : g_entries) {
|
||||
if (e.path == path) {
|
||||
e.ref_count++;
|
||||
out_path = e.mount;
|
||||
if (e && e->path == path) {
|
||||
e->ref_count++;
|
||||
out_path = e->mount;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, find next free entry.
|
||||
auto itr = std::ranges::find_if(g_entries, [](auto& e){
|
||||
return !e;
|
||||
});
|
||||
R_UNLESS(itr != g_entries.end(), 0x1);
|
||||
|
||||
const auto index = std::distance(g_entries.begin(), itr);
|
||||
auto source = std::make_unique<yati::source::File>(fs, path);
|
||||
|
||||
s64 size;
|
||||
@@ -246,22 +255,22 @@ Result MountNsp(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
yati::container::Collections collections;
|
||||
R_TRY(nsp.GetCollections(collections));
|
||||
|
||||
auto& entry = g_entries.emplace_back();
|
||||
entry.path = path;
|
||||
entry.devoptab = DEVOPTAB;
|
||||
entry.devoptab.name = entry.name;
|
||||
entry.devoptab.deviceData = &entry.device;
|
||||
entry.device.source = std::move(buffered);
|
||||
entry.device.collections = collections;
|
||||
std::snprintf(entry.name, sizeof(entry.name), "nsp_%u", g_mount_idx);
|
||||
std::snprintf(entry.mount, sizeof(entry.mount), "nsp_%u:/", g_mount_idx);
|
||||
auto entry = std::make_unique<Entry>();
|
||||
entry->path = path;
|
||||
entry->devoptab = DEVOPTAB;
|
||||
entry->devoptab.name = entry->name;
|
||||
entry->devoptab.deviceData = &entry->device;
|
||||
entry->device.source = std::move(buffered);
|
||||
entry->device.collections = collections;
|
||||
std::snprintf(entry->name, sizeof(entry->name), "nsp_%zu", index);
|
||||
std::snprintf(entry->mount, sizeof(entry->mount), "nsp_%zu:/", index);
|
||||
|
||||
R_UNLESS(AddDevice(&entry.devoptab) >= 0, 0x1);
|
||||
log_write("[NSP] DEVICE SUCCESS %s %s\n", path.s, entry.name);
|
||||
R_UNLESS(AddDevice(&entry->devoptab) >= 0, 0x1);
|
||||
log_write("[NSP] DEVICE SUCCESS %s %s\n", path.s, entry->name);
|
||||
|
||||
out_path = entry.mount;
|
||||
entry.ref_count++;
|
||||
g_mount_idx++;
|
||||
out_path = entry->mount;
|
||||
entry->ref_count++;
|
||||
*itr = std::move(entry);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -270,20 +279,19 @@ void UmountNsp(const fs::FsPath& mount) {
|
||||
SCOPED_MUTEX(&g_mutex);
|
||||
|
||||
auto itr = std::ranges::find_if(g_entries, [&mount](auto& e){
|
||||
return mount == e.mount;
|
||||
return e && e->mount == mount;
|
||||
});
|
||||
|
||||
if (itr == g_entries.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (itr->ref_count) {
|
||||
itr->ref_count--;
|
||||
if ((*itr)->ref_count) {
|
||||
(*itr)->ref_count--;
|
||||
}
|
||||
|
||||
if (!itr->ref_count) {
|
||||
RemoveDevice(mount);
|
||||
g_entries.erase(itr);
|
||||
if (!(*itr)->ref_count) {
|
||||
itr->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "yati/nx/nxdumptool/core/save.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
@@ -243,19 +244,21 @@ constexpr devoptab_t DEVOPTAB = {
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
u64 id;
|
||||
Device device;
|
||||
devoptab_t devoptab;
|
||||
char name[32];
|
||||
s32 ref_count;
|
||||
Device device{};
|
||||
devoptab_t devoptab{};
|
||||
u64 id{};
|
||||
fs::FsPath mount{};
|
||||
char name[32]{};
|
||||
s32 ref_count{};
|
||||
|
||||
~Entry() {
|
||||
RemoveDevice(mount);
|
||||
save_close_savefile(&device.ctx);
|
||||
}
|
||||
};
|
||||
|
||||
Mutex g_mutex;
|
||||
std::vector<Entry> g_entries;
|
||||
|
||||
void MakeMountPath(u64 id, fs::FsPath& out_path) {
|
||||
std::snprintf(out_path, sizeof(out_path), "%016lx:/", id);
|
||||
}
|
||||
std::array<std::unique_ptr<Entry>, common::MAX_ENTRIES> g_entries;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -264,13 +267,19 @@ Result MountFromSavePath(u64 id, fs::FsPath& out_path) {
|
||||
|
||||
// check if we already have the save mounted.
|
||||
for (auto& e : g_entries) {
|
||||
if (e.id == id) {
|
||||
e.ref_count++;
|
||||
MakeMountPath(id, out_path);
|
||||
if (e && e->id == id) {
|
||||
e->ref_count++;
|
||||
out_path = e->mount;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, find next free entry.
|
||||
auto itr = std::ranges::find_if(g_entries, [](auto& e){
|
||||
return !e;
|
||||
});
|
||||
R_UNLESS(itr != g_entries.end(), 0x1);
|
||||
|
||||
char path[256];
|
||||
std::snprintf(path, sizeof(path), "SYSTEM:/save/%016lx", id);
|
||||
|
||||
@@ -281,21 +290,23 @@ Result MountFromSavePath(u64 id, fs::FsPath& out_path) {
|
||||
|
||||
log_write("[SAVE] OPEN SUCCESS %s\n", path);
|
||||
|
||||
auto& entry = g_entries.emplace_back();
|
||||
entry.id = id;
|
||||
entry.device.ctx = ctx;
|
||||
entry.device.file_table = &ctx->save_filesystem_core.file_table;
|
||||
entry.devoptab = DEVOPTAB;
|
||||
entry.devoptab.name = entry.name;
|
||||
entry.devoptab.deviceData = &entry.device;
|
||||
std::snprintf(entry.name, sizeof(entry.name), "%016lx", id);
|
||||
auto entry = std::make_unique<Entry>();
|
||||
entry->id = id;
|
||||
entry->device.ctx = ctx;
|
||||
entry->device.file_table = &ctx->save_filesystem_core.file_table;
|
||||
entry->devoptab = DEVOPTAB;
|
||||
entry->devoptab.name = entry->name;
|
||||
entry->devoptab.deviceData = &entry->device;
|
||||
std::snprintf(entry->name, sizeof(entry->name), "%016lx", id);
|
||||
std::snprintf(entry->mount, sizeof(entry->mount), "%016lx:/", id);
|
||||
|
||||
R_UNLESS(AddDevice(&entry.devoptab) >= 0, 0x1);
|
||||
log_write("[SAVE] DEVICE SUCCESS %s %s\n", path, entry.name);
|
||||
R_UNLESS(AddDevice(&entry->devoptab) >= 0, 0x1);
|
||||
log_write("[SAVE] DEVICE SUCCESS %s %s\n", path, entry->name);
|
||||
|
||||
MakeMountPath(id, out_path);
|
||||
out_path = entry->mount;
|
||||
entry->ref_count++;
|
||||
*itr = std::move(entry);
|
||||
|
||||
entry.ref_count++;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
@@ -303,29 +314,19 @@ void UnmountSave(u64 id) {
|
||||
SCOPED_MUTEX(&g_mutex);
|
||||
|
||||
auto itr = std::ranges::find_if(g_entries, [id](auto& e){
|
||||
return id == e.id;
|
||||
return e && e->id == id;
|
||||
});
|
||||
|
||||
if (itr == g_entries.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (itr->ref_count) {
|
||||
itr->ref_count--;
|
||||
if ((*itr)->ref_count) {
|
||||
(*itr)->ref_count--;
|
||||
}
|
||||
|
||||
if (!itr->ref_count) {
|
||||
fs::FsPath path;
|
||||
MakeMountPath(id, path);
|
||||
|
||||
// todo: verify this actually works.
|
||||
RemoveDevice(path);
|
||||
|
||||
if (itr->device.ctx) {
|
||||
save_close_savefile(&itr->device.ctx);
|
||||
}
|
||||
|
||||
g_entries.erase(itr);
|
||||
if (!(*itr)->ref_count) {
|
||||
itr->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "yati/source/file.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
@@ -230,17 +231,20 @@ constexpr devoptab_t DEVOPTAB = {
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
Device device;
|
||||
devoptab_t devoptab;
|
||||
fs::FsPath path;
|
||||
fs::FsPath mount;
|
||||
char name[32];
|
||||
s32 ref_count;
|
||||
Device device{};
|
||||
devoptab_t devoptab{};
|
||||
fs::FsPath path{};
|
||||
fs::FsPath mount{};
|
||||
char name[32]{};
|
||||
s32 ref_count{};
|
||||
|
||||
~Entry() {
|
||||
RemoveDevice(mount);
|
||||
}
|
||||
};
|
||||
|
||||
Mutex g_mutex;
|
||||
std::vector<Entry> g_entries;
|
||||
u32 g_mount_idx;
|
||||
std::array<std::unique_ptr<Entry>, common::MAX_ENTRIES> g_entries;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -249,13 +253,20 @@ Result MountXci(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
|
||||
// check if we already have the save mounted.
|
||||
for (auto& e : g_entries) {
|
||||
if (e.path == path) {
|
||||
e.ref_count++;
|
||||
out_path = e.mount;
|
||||
if (e && e->path == path) {
|
||||
e->ref_count++;
|
||||
out_path = e->mount;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, find next free entry.
|
||||
auto itr = std::ranges::find_if(g_entries, [](auto& e){
|
||||
return !e;
|
||||
});
|
||||
R_UNLESS(itr != g_entries.end(), 0x1);
|
||||
|
||||
const auto index = std::distance(g_entries.begin(), itr);
|
||||
auto source = std::make_unique<yati::source::File>(fs, path);
|
||||
|
||||
s64 size;
|
||||
@@ -266,22 +277,22 @@ Result MountXci(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
yati::container::Xci::Partitions partitions;
|
||||
R_TRY(xci.GetPartitions(partitions));
|
||||
|
||||
auto& entry = g_entries.emplace_back();
|
||||
entry.path = path;
|
||||
entry.devoptab = DEVOPTAB;
|
||||
entry.devoptab.name = entry.name;
|
||||
entry.devoptab.deviceData = &entry.device;
|
||||
entry.device.source = std::move(buffered);
|
||||
entry.device.partitions = partitions;
|
||||
std::snprintf(entry.name, sizeof(entry.name), "xci_%u", g_mount_idx);
|
||||
std::snprintf(entry.mount, sizeof(entry.mount), "xci_%u:/", g_mount_idx);
|
||||
auto entry = std::make_unique<Entry>();
|
||||
entry->path = path;
|
||||
entry->devoptab = DEVOPTAB;
|
||||
entry->devoptab.name = entry->name;
|
||||
entry->devoptab.deviceData = &entry->device;
|
||||
entry->device.source = std::move(buffered);
|
||||
entry->device.partitions = partitions;
|
||||
std::snprintf(entry->name, sizeof(entry->name), "xci_%zu", index);
|
||||
std::snprintf(entry->mount, sizeof(entry->mount), "xci_%zu:/", index);
|
||||
|
||||
R_UNLESS(AddDevice(&entry.devoptab) >= 0, 0x1);
|
||||
log_write("[XCI] DEVICE SUCCESS %s %s\n", path.s, entry.name);
|
||||
R_UNLESS(AddDevice(&entry->devoptab) >= 0, 0x1);
|
||||
log_write("[XCI] DEVICE SUCCESS %s %s\n", path.s, entry->name);
|
||||
|
||||
out_path = entry.mount;
|
||||
entry.ref_count++;
|
||||
g_mount_idx++;
|
||||
out_path = entry->mount;
|
||||
entry->ref_count++;
|
||||
*itr = std::move(entry);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -290,20 +301,19 @@ void UmountXci(const fs::FsPath& mount) {
|
||||
SCOPED_MUTEX(&g_mutex);
|
||||
|
||||
auto itr = std::ranges::find_if(g_entries, [&mount](auto& e){
|
||||
return mount == e.mount;
|
||||
return e && e->mount == mount;
|
||||
});
|
||||
|
||||
if (itr == g_entries.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (itr->ref_count) {
|
||||
itr->ref_count--;
|
||||
if ((*itr)->ref_count) {
|
||||
(*itr)->ref_count--;
|
||||
}
|
||||
|
||||
if (!itr->ref_count) {
|
||||
RemoveDevice(mount);
|
||||
g_entries.erase(itr);
|
||||
if (!(*itr)->ref_count) {
|
||||
itr->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
#include "yati/source/file.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <sys/iosupport.h>
|
||||
#include <zlib.h>
|
||||
@@ -600,17 +601,20 @@ Result ParseZip(common::BufferedData* source, s64 size, FileTableEntries& out) {
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
Device device;
|
||||
devoptab_t devoptab;
|
||||
fs::FsPath path;
|
||||
fs::FsPath mount;
|
||||
char name[32];
|
||||
s32 ref_count;
|
||||
Device device{};
|
||||
devoptab_t devoptab{};
|
||||
fs::FsPath path{};
|
||||
fs::FsPath mount{};
|
||||
char name[32]{};
|
||||
s32 ref_count{};
|
||||
|
||||
~Entry() {
|
||||
RemoveDevice(mount);
|
||||
}
|
||||
};
|
||||
|
||||
Mutex g_mutex;
|
||||
std::vector<Entry> g_entries;
|
||||
u32 g_mount_idx;
|
||||
std::array<std::unique_ptr<Entry>, common::MAX_ENTRIES> g_entries;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -619,13 +623,20 @@ Result MountZip(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
|
||||
// check if we already have the save mounted.
|
||||
for (auto& e : g_entries) {
|
||||
if (e.path == path) {
|
||||
e.ref_count++;
|
||||
out_path = e.mount;
|
||||
if (e && e->path == path) {
|
||||
e->ref_count++;
|
||||
out_path = e->mount;
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, find next free entry.
|
||||
auto itr = std::ranges::find_if(g_entries, [](auto& e){
|
||||
return !e;
|
||||
});
|
||||
R_UNLESS(itr != g_entries.end(), 0x1);
|
||||
|
||||
const auto index = std::distance(g_entries.begin(), itr);
|
||||
auto source = std::make_unique<yati::source::File>(fs, path);
|
||||
|
||||
s64 size;
|
||||
@@ -640,22 +651,22 @@ Result MountZip(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path) {
|
||||
DirectoryEntry root;
|
||||
Parse(table_entries, root);
|
||||
|
||||
auto& entry = g_entries.emplace_back();
|
||||
entry.path = path;
|
||||
entry.devoptab = DEVOPTAB;
|
||||
entry.devoptab.name = entry.name;
|
||||
entry.devoptab.deviceData = &entry.device;
|
||||
entry.device.source = std::move(buffered);
|
||||
entry.device.root = root;
|
||||
std::snprintf(entry.name, sizeof(entry.name), "zip_%u", g_mount_idx);
|
||||
std::snprintf(entry.mount, sizeof(entry.mount), "zip_%u:/", g_mount_idx);
|
||||
auto entry = std::make_unique<Entry>();
|
||||
entry->path = path;
|
||||
entry->devoptab = DEVOPTAB;
|
||||
entry->devoptab.name = entry->name;
|
||||
entry->devoptab.deviceData = &entry->device;
|
||||
entry->device.source = std::move(buffered);
|
||||
entry->device.root = root;
|
||||
std::snprintf(entry->name, sizeof(entry->name), "zip_%zu", index);
|
||||
std::snprintf(entry->mount, sizeof(entry->mount), "zip_%zu:/", index);
|
||||
|
||||
R_UNLESS(AddDevice(&entry.devoptab) >= 0, 0x1);
|
||||
log_write("[ZIP] DEVICE SUCCESS %s %s\n", path.s, entry.name);
|
||||
R_UNLESS(AddDevice(&entry->devoptab) >= 0, 0x1);
|
||||
log_write("[ZIP] DEVICE SUCCESS %s %s\n", path.s, entry->name);
|
||||
|
||||
out_path = entry.mount;
|
||||
entry.ref_count++;
|
||||
g_mount_idx++;
|
||||
out_path = entry->mount;
|
||||
entry->ref_count++;
|
||||
*itr = std::move(entry);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -664,20 +675,19 @@ void UmountZip(const fs::FsPath& mount) {
|
||||
SCOPED_MUTEX(&g_mutex);
|
||||
|
||||
auto itr = std::ranges::find_if(g_entries, [&mount](auto& e){
|
||||
return mount == e.mount;
|
||||
return e && e->mount == mount;
|
||||
});
|
||||
|
||||
if (itr == g_entries.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (itr->ref_count) {
|
||||
itr->ref_count--;
|
||||
if ((*itr)->ref_count) {
|
||||
(*itr)->ref_count--;
|
||||
}
|
||||
|
||||
if (!itr->ref_count) {
|
||||
RemoveDevice(mount);
|
||||
g_entries.erase(itr);
|
||||
if (!(*itr)->ref_count) {
|
||||
itr->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user