simplify stdio/native file paths by sharing the same code.

This commit is contained in:
ITotalJustice
2025-05-23 12:44:56 +01:00
parent 93c38da742
commit 6475f4316a
12 changed files with 59 additions and 118 deletions

View File

@@ -91,7 +91,6 @@ add_executable(sphaira
source/yati/container/nsp.cpp source/yati/container/nsp.cpp
source/yati/container/xci.cpp source/yati/container/xci.cpp
source/yati/source/file.cpp source/yati/source/file.cpp
source/yati/source/stdio.cpp
source/yati/source/usb.cpp source/yati/source/usb.cpp
source/yati/source/stream.cpp source/yati/source/stream.cpp
source/yati/source/stream_file.cpp source/yati/source/stream_file.cpp

View File

@@ -3,17 +3,20 @@
#include "base.hpp" #include "base.hpp"
#include "fs.hpp" #include "fs.hpp"
#include <switch.h> #include <switch.h>
#include <memory>
namespace sphaira::yati::source { namespace sphaira::yati::source {
struct File final : Base { struct File final : Base {
File(FsFileSystem* fs, const fs::FsPath& path); File(FsFileSystem* fs, const fs::FsPath& path);
File(const fs::FsPath& path);
~File(); ~File();
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override; Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override;
private: private:
FsFile m_file{}; std::unique_ptr<fs::Fs> m_fs{};
fs::File m_file{};
}; };
} // namespace sphaira::yati::source } // namespace sphaira::yati::source

View File

@@ -1,20 +0,0 @@
#pragma once
#include "base.hpp"
#include "fs.hpp"
#include <cstdio>
#include <switch.h>
namespace sphaira::yati::source {
struct Stdio final : Base {
Stdio(const fs::FsPath& path);
~Stdio();
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override;
private:
std::FILE* m_file{};
};
} // namespace sphaira::yati::source

View File

@@ -5,17 +5,20 @@
#include "stream.hpp" #include "stream.hpp"
#include "fs.hpp" #include "fs.hpp"
#include <switch.h> #include <switch.h>
#include <memory>
namespace sphaira::yati::source { namespace sphaira::yati::source {
struct StreamFile final : Stream { struct StreamFile final : Stream {
StreamFile(FsFileSystem* fs, const fs::FsPath& path); StreamFile(FsFileSystem* fs, const fs::FsPath& path);
StreamFile(const fs::FsPath& path);
~StreamFile(); ~StreamFile();
Result ReadChunk(void* buf, s64 size, u64* bytes_read) override; Result ReadChunk(void* buf, s64 size, u64* bytes_read) override;
private: private:
FsFile m_file{}; std::unique_ptr<fs::Fs> m_fs{};
fs::File m_file{};
s64 m_offset{}; s64 m_offset{};
}; };

View File

@@ -130,7 +130,7 @@ struct ConfigOverride {
}; };
Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath& path, const ConfigOverride& override = {}); Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath& path, const ConfigOverride& override = {});
Result InstallFromStdioFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override = {}); Result InstallFromFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override = {});
Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const fs::FsPath& path, const ConfigOverride& override = {}); Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const fs::FsPath& path, const ConfigOverride& override = {});
Result InstallFromContainer(ui::ProgressBox* pbox, std::shared_ptr<container::Base> container, const ConfigOverride& override = {}); Result InstallFromContainer(ui::ProgressBox* pbox, std::shared_ptr<container::Base> container, const ConfigOverride& override = {});
Result InstallFromCollections(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const container::Collections& collections, const ConfigOverride& override = {}); Result InstallFromCollections(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const container::Collections& collections, const ConfigOverride& override = {});

View File

@@ -102,89 +102,54 @@ private:
s64 m_pull_offset{}; s64 m_pull_offset{};
}; };
Result DumpToFile(ui::ProgressBox* pbox, BaseSource* source, std::span<const fs::FsPath> paths) { Result DumpToFile(ui::ProgressBox* pbox, fs::Fs* fs, const fs::FsPath& root, BaseSource* source, std::span<const fs::FsPath> paths) {
static constexpr fs::FsPath DUMP_PATH{"/dumps/NSP"}; const auto DUMP_PATH = fs::AppendPath(root, "/dumps/NSP");
constexpr s64 BIG_FILE_SIZE = 1024ULL*1024ULL*1024ULL*4ULL; constexpr s64 BIG_FILE_SIZE = 1024ULL*1024ULL*1024ULL*4ULL;
fs::FsNativeSd fs{};
R_TRY(fs.GetFsOpenResult());
for (auto path : paths) { for (auto path : paths) {
const auto file_size = source->GetSize(path); const auto file_size = source->GetSize(path);
pbox->SetTitle(source->GetName(path)); pbox->SetTitle(source->GetName(path));
pbox->NewTransfer(path); pbox->NewTransfer(path);
const auto temp_path = fs::AppendPath(DUMP_PATH, path + ".temp"); const auto temp_path = fs::AppendPath(DUMP_PATH, path + ".temp");
fs.CreateDirectoryRecursivelyWithPath(temp_path); fs->CreateDirectoryRecursivelyWithPath(temp_path);
fs.DeleteFile(temp_path); fs->DeleteFile(temp_path);
const auto flags = file_size >= BIG_FILE_SIZE ? FsCreateOption_BigFile : 0; const auto flags = file_size >= BIG_FILE_SIZE ? FsCreateOption_BigFile : 0;
R_TRY(fs.CreateFile(temp_path, file_size, flags)); R_TRY(fs->CreateFile(temp_path, file_size, flags));
ON_SCOPE_EXIT(fs.DeleteFile(temp_path)); ON_SCOPE_EXIT(fs->DeleteFile(temp_path));
{ {
FsFile file; fs::File file;
R_TRY(fs.OpenFile(temp_path, FsOpenMode_Write, &file)); R_TRY(fs->OpenFile(temp_path, FsOpenMode_Write, &file));
ON_SCOPE_EXIT(fsFileClose(&file)); ON_SCOPE_EXIT(fs->FileClose(&file));
R_TRY(thread::Transfer(pbox, file_size, R_TRY(thread::Transfer(pbox, file_size,
[&](void* data, s64 off, s64 size, u64* bytes_read) -> Result { [&](void* data, s64 off, s64 size, u64* bytes_read) -> Result {
return source->Read(path, data, off, size, bytes_read); return source->Read(path, data, off, size, bytes_read);
}, },
[&](const void* data, s64 off, s64 size) -> Result { [&](const void* data, s64 off, s64 size) -> Result {
return fsFileWrite(&file, off, data, size, FsWriteOption_None); return fs->FileWrite(&file, off, data, size, FsWriteOption_None);
} }
)); ));
} }
path = fs::AppendPath(DUMP_PATH, path); path = fs::AppendPath(DUMP_PATH, path);
fs.DeleteFile(path); fs->DeleteFile(path);
R_TRY(fs.RenameFile(temp_path, path)); R_TRY(fs->RenameFile(temp_path, path));
} }
R_SUCCEED(); R_SUCCEED();
} }
Result DumpToFileNative(ui::ProgressBox* pbox, BaseSource* source, std::span<const fs::FsPath> paths) {
fs::FsNative fs{};
return DumpToFile(pbox, &fs, "/", source, paths);
}
Result DumpToStdio(ui::ProgressBox* pbox, const location::StdioEntry& loc, BaseSource* source, std::span<const fs::FsPath> paths) { Result DumpToStdio(ui::ProgressBox* pbox, const location::StdioEntry& loc, BaseSource* source, std::span<const fs::FsPath> paths) {
const fs::FsPath DUMP_PATH = loc.mount + "/dumps/NSP";
fs::FsStdio fs{}; fs::FsStdio fs{};
return DumpToFile(pbox, &fs, loc.mount, source, paths);
for (auto path : paths) {
const auto file_size = source->GetSize(path);
pbox->SetTitle(source->GetName(path));
pbox->NewTransfer(path);
const auto temp_path = fs::AppendPath(DUMP_PATH, path + ".temp");
fs.CreateDirectoryRecursivelyWithPath(temp_path);
fs.DeleteFile(temp_path);
R_TRY(fs.CreateFile(temp_path, file_size));
ON_SCOPE_EXIT(fs.DeleteFile(temp_path));
{
auto file = std::fopen(temp_path, "wb");
R_UNLESS(file, 0x1);
ON_SCOPE_EXIT(std::fclose(file));
R_TRY(thread::Transfer(pbox, file_size,
[&](void* data, s64 off, s64 size, u64* bytes_read) -> Result {
return source->Read(path, data, off, size, bytes_read);
},
[&](const void* data, s64 off, s64 size) -> Result {
const auto written = std::fwrite(data, 1, size, file);
R_UNLESS(written >= 1, 0x1);
R_SUCCEED();
}
));
}
path = fs::AppendPath(DUMP_PATH, path);
fs.DeleteFile(path);
R_TRY(fs.RenameFile(temp_path, path));
}
R_SUCCEED();
} }
Result DumpToUsbS2SStream(ui::ProgressBox* pbox, UsbTest* usb, std::span<const fs::FsPath> paths) { Result DumpToUsbS2SStream(ui::ProgressBox* pbox, UsbTest* usb, std::span<const fs::FsPath> paths) {
@@ -389,7 +354,7 @@ void Dump(std::shared_ptr<BaseSource> source, const std::vector<fs::FsPath>& pat
} else if (dump_entry.type == DumpLocationType_Stdio) { } else if (dump_entry.type == DumpLocationType_Stdio) {
R_TRY(DumpToStdio(pbox, stdio_locations[dump_entry.index], source.get(), paths)); R_TRY(DumpToStdio(pbox, stdio_locations[dump_entry.index], source.get(), paths));
} else if (dump_entry.type == DumpLocationType_SdCard) { } else if (dump_entry.type == DumpLocationType_SdCard) {
R_TRY(DumpToFile(pbox, source.get(), paths)); R_TRY(DumpToFileNative(pbox, source.get(), paths));
} else if (dump_entry.type == DumpLocationType_UsbS2S) { } else if (dump_entry.type == DumpLocationType_UsbS2S) {
R_TRY(DumpToUsbS2S(pbox, source.get(), paths)); R_TRY(DumpToUsbS2S(pbox, source.get(), paths));
} else if (dump_entry.type == DumpLocationType_DevNull) { } else if (dump_entry.type == DumpLocationType_DevNull) {

View File

@@ -465,9 +465,9 @@ Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f) {
// todo: // todo:
R_THROW(0x1); R_THROW(0x1);
} else if (mode & FsOpenMode_Read) { } else if (mode & FsOpenMode_Read) {
f->m_stdio = fopen(path, "rb"); f->m_stdio = std::fopen(path, "rb");
} else if (mode & FsOpenMode_Write) { } else if (mode & FsOpenMode_Write) {
f->m_stdio = fopen(path, "wb"); f->m_stdio = std::fopen(path, "wb");
} }
R_UNLESS(f->m_stdio, 0x1); R_UNLESS(f->m_stdio, 0x1);

View File

@@ -931,7 +931,7 @@ void Menu::InstallFiles() {
if (m_fs->IsNative()) { if (m_fs->IsNative()) {
R_TRY(yati::InstallFromFile(pbox, &GetNative()->m_fs, GetNewPath(e))); R_TRY(yati::InstallFromFile(pbox, &GetNative()->m_fs, GetNewPath(e)));
} else { } else {
R_TRY(yati::InstallFromStdioFile(pbox, GetNewPath(e))); R_TRY(yati::InstallFromFile(pbox, GetNewPath(e)));
} }
App::Notify("Installed " + e.GetName()); App::Notify("Installed " + e.GetName());
} }

View File

@@ -3,18 +3,28 @@
namespace sphaira::yati::source { namespace sphaira::yati::source {
File::File(FsFileSystem* fs, const fs::FsPath& path) { File::File(FsFileSystem* fs, const fs::FsPath& path) {
m_open_result = fsFsOpenFile(fs, path, FsOpenMode_Read, std::addressof(m_file)); if (fs) {
m_fs = std::make_unique<fs::FsNative>(fs, false);
} else {
m_fs = std::make_unique<fs::FsStdio>();
}
m_open_result = m_fs->OpenFile(path, FsOpenMode_Read, std::addressof(m_file));
}
File::File(const fs::FsPath& path) : File{nullptr, path} {
} }
File::~File() { File::~File() {
if (R_SUCCEEDED(GetOpenResult())) { if (R_SUCCEEDED(GetOpenResult())) {
fsFileClose(std::addressof(m_file)); m_fs->FileClose(std::addressof(m_file));
} }
} }
Result File::Read(void* buf, s64 off, s64 size, u64* bytes_read) { Result File::Read(void* buf, s64 off, s64 size, u64* bytes_read) {
R_TRY(GetOpenResult()); R_TRY(GetOpenResult());
return fsFileRead(std::addressof(m_file), off, buf, size, 0, bytes_read); return m_fs->FileRead(std::addressof(m_file), off, buf, size, 0, bytes_read);
} }
} // namespace sphaira::yati::source } // namespace sphaira::yati::source

View File

@@ -1,28 +0,0 @@
#include "yati/source/stdio.hpp"
namespace sphaira::yati::source {
Stdio::Stdio(const fs::FsPath& path) {
m_file = std::fopen(path, "rb");
if (!m_file) {
m_open_result = fsdevGetLastResult();
}
}
Stdio::~Stdio() {
if (R_SUCCEEDED(GetOpenResult())) {
std::fclose(m_file);
}
}
Result Stdio::Read(void* buf, s64 off, s64 size, u64* bytes_read) {
R_TRY(GetOpenResult());
std::fseek(m_file, off, SEEK_SET);
R_TRY(fsdevGetLastResult());
*bytes_read = std::fread(buf, 1, size, m_file);
return fsdevGetLastResult();
}
} // namespace sphaira::yati::source

View File

@@ -4,18 +4,28 @@
namespace sphaira::yati::source { namespace sphaira::yati::source {
StreamFile::StreamFile(FsFileSystem* fs, const fs::FsPath& path) { StreamFile::StreamFile(FsFileSystem* fs, const fs::FsPath& path) {
m_open_result = fsFsOpenFile(fs, path, FsOpenMode_Read, std::addressof(m_file)); if (fs) {
m_fs = std::make_unique<fs::FsNative>(fs, false);
} else {
m_fs = std::make_unique<fs::FsStdio>();
}
m_open_result = m_fs->OpenFile(path, FsOpenMode_Read, std::addressof(m_file));
}
StreamFile::StreamFile(const fs::FsPath& path) : StreamFile{nullptr, path} {
} }
StreamFile::~StreamFile() { StreamFile::~StreamFile() {
if (R_SUCCEEDED(GetOpenResult())) { if (R_SUCCEEDED(GetOpenResult())) {
fsFileClose(std::addressof(m_file)); m_fs->FileClose(std::addressof(m_file));
} }
} }
Result StreamFile::ReadChunk(void* buf, s64 size, u64* bytes_read) { Result StreamFile::ReadChunk(void* buf, s64 size, u64* bytes_read) {
R_TRY(GetOpenResult()); R_TRY(GetOpenResult());
const auto rc = fsFileRead(std::addressof(m_file), m_offset, buf, size, 0, bytes_read); const auto rc = m_fs->FileRead(std::addressof(m_file), m_offset, buf, size, 0, bytes_read);
m_offset += *bytes_read; m_offset += *bytes_read;
return rc; return rc;
} }

View File

@@ -1,7 +1,6 @@
#include "yati/yati.hpp" #include "yati/yati.hpp"
#include "yati/source/file.hpp" #include "yati/source/file.hpp"
#include "yati/source/stream_file.hpp" #include "yati/source/stream_file.hpp"
#include "yati/source/stdio.hpp"
#include "yati/container/nsp.hpp" #include "yati/container/nsp.hpp"
#include "yati/container/xci.hpp" #include "yati/container/xci.hpp"
@@ -1393,8 +1392,8 @@ Result InstallFromFile(ui::ProgressBox* pbox, FsFileSystem* fs, const fs::FsPath
// return InstallFromSource(pbox, std::make_shared<source::StreamFile>(fs, path), path, override); // return InstallFromSource(pbox, std::make_shared<source::StreamFile>(fs, path), path, override);
} }
Result InstallFromStdioFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override) { Result InstallFromFile(ui::ProgressBox* pbox, const fs::FsPath& path, const ConfigOverride& override) {
return InstallFromSource(pbox, std::make_shared<source::Stdio>(path), path, override); return InstallFromFile(pbox, nullptr, path, override);
} }
Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const fs::FsPath& path, const ConfigOverride& override) { Result InstallFromSource(ui::ProgressBox* pbox, std::shared_ptr<source::Base> source, const fs::FsPath& path, const ConfigOverride& override) {