Fixes and testing
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory_setup.h"
|
||||
#include "core/settings.h"
|
||||
#include "file_sys/vfs_real.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -84,7 +85,7 @@ System::ResultStatus System::SingleStep() {
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
|
||||
app_loader = Loader::GetLoader(filepath);
|
||||
app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath));
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
|
||||
@@ -44,7 +44,7 @@ static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
|
||||
|
||||
static bool IsDirectoryExeFS(std::shared_ptr<FileSys::VfsDirectory> pfs) {
|
||||
// According to switchbrew, an exefs must only contain these two files:
|
||||
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.ndpm") != nullptr;
|
||||
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
|
||||
}
|
||||
|
||||
static bool IsValidNCA(const NCAHeader& header) {
|
||||
|
||||
@@ -21,7 +21,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
|
||||
// For cartridges, HFSs can get very large, so we need to calculate the size up to
|
||||
// the actual content itself instead of just blindly reading in the entire file.
|
||||
Header pfs_header;
|
||||
if (!file->ReadObject(&pfs_header)) {
|
||||
if (sizeof(Header) != file->ReadObject(&pfs_header)) {
|
||||
status = Loader::ResultStatus::Error;
|
||||
return;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&pfs_header, &file_data, sizeof(Header));
|
||||
memcpy(&pfs_header, file_data.data(), sizeof(Header));
|
||||
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
|
||||
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
|
||||
status = Loader::ResultStatus::ErrorInvalidFormat;
|
||||
|
||||
@@ -54,7 +54,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(const filesystem::path& p
|
||||
|
||||
auto parent = path.parent_path().string();
|
||||
parent.replace(path.root_path().string().begin(), path.root_path().string().end(), "");
|
||||
const auto index = parent.find_first_of('\\');
|
||||
const auto index = parent.find_first_of('/');
|
||||
const auto first_dir = parent.substr(0, index), rest = parent.substr(index + 1);
|
||||
const auto sub = GetSubdirectory(first_dir);
|
||||
if (sub == nullptr)
|
||||
@@ -69,11 +69,23 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(const filesystem::path& p
|
||||
return GetParentDirectory()->GetFileAbsolute(path);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(const filesystem::path& path) const {
|
||||
return "";
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(
|
||||
const filesystem::path& path) const {
|
||||
if (path.parent_path() == path.root_path())
|
||||
return GetSubdirectory(path.filename().string());
|
||||
|
||||
auto parent = path.parent_path().string();
|
||||
parent.replace(path.root_path().string().begin(), path.root_path().string().end(), "");
|
||||
const auto index = parent.find_first_of('/');
|
||||
const auto first_dir = parent.substr(0, index), rest = parent.substr(index + 1);
|
||||
const auto sub = GetSubdirectory(first_dir);
|
||||
if (sub == nullptr)
|
||||
return nullptr;
|
||||
return sub->GetDirectoryRelative(path.root_path().string() + rest);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(const filesystem::path& path) const {
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(
|
||||
const filesystem::path& path) const {
|
||||
if (IsRoot())
|
||||
return GetDirectoryRelative(path);
|
||||
|
||||
@@ -113,6 +125,23 @@ size_t VfsDirectory::GetSize() const {
|
||||
return file_total + subdir_total;
|
||||
}
|
||||
|
||||
bool VfsDirectory::DeleteSubdirectoryRecursive(const std::string& name) {
|
||||
auto dir = GetSubdirectory(name);
|
||||
if (dir == nullptr)
|
||||
return false;
|
||||
|
||||
bool success = true;
|
||||
for (const auto& file : dir->GetFiles())
|
||||
if (!DeleteFile(file->GetName()))
|
||||
success = false;
|
||||
|
||||
for (const auto& sdir : dir->GetSubdirectories())
|
||||
if (!dir->DeleteSubdirectoryRecursive(sdir->GetName()))
|
||||
success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VfsDirectory::Copy(const std::string& src, const std::string& dest) {
|
||||
const auto f1 = CreateFile(src);
|
||||
auto f2 = CreateFile(dest);
|
||||
|
||||
@@ -119,6 +119,7 @@ struct VfsDirectory : NonCopyable {
|
||||
virtual std::shared_ptr<VfsFile> CreateFile(const std::string& name) = 0;
|
||||
|
||||
virtual bool DeleteSubdirectory(const std::string& name) = 0;
|
||||
virtual bool DeleteSubdirectoryRecursive(const std::string& name);
|
||||
virtual bool DeleteFile(const std::string& name) = 0;
|
||||
|
||||
virtual bool Rename(const std::string& name) = 0;
|
||||
|
||||
@@ -7,17 +7,21 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
static const char* PermissionsToCharArray(filesystem::perms perms) {
|
||||
static std::string PermissionsToCharArray(filesystem::perms perms) {
|
||||
std::string out;
|
||||
if ((perms & filesystem::perms::owner_read) != filesystem::perms::none)
|
||||
out += "r";
|
||||
if ((perms & filesystem::perms::owner_write) != filesystem::perms::none)
|
||||
out += "w";
|
||||
return out.c_str();
|
||||
out += "+";
|
||||
if (out == "+")
|
||||
out = "w";
|
||||
return out + "b";
|
||||
}
|
||||
|
||||
RealVfsFile::RealVfsFile(const filesystem::path& path_, filesystem::perms perms_)
|
||||
: backing(path_.string(), PermissionsToCharArray(perms_)), path(path_), perms(perms_) {}
|
||||
: backing(path_.string(), PermissionsToCharArray(perms_).c_str()), path(path_), perms(perms_) {
|
||||
path.make_preferred();
|
||||
}
|
||||
|
||||
std::string RealVfsFile::GetName() const {
|
||||
return path.filename().string();
|
||||
@@ -58,12 +62,13 @@ size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
|
||||
bool RealVfsFile::Rename(const std::string& name) {
|
||||
const auto out = FileUtil::Rename(GetName(), name);
|
||||
path = path.parent_path() / name;
|
||||
backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms));
|
||||
backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms).c_str());
|
||||
return out;
|
||||
}
|
||||
|
||||
RealVfsDirectory::RealVfsDirectory(const filesystem::path& path_, filesystem::perms perms_)
|
||||
: path(path_), perms(perms_) {
|
||||
path.make_preferred();
|
||||
for (const auto& entry : filesystem::directory_iterator(path)) {
|
||||
if (filesystem::is_directory(entry.path()))
|
||||
subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(entry.path(), perms));
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace FileSys {
|
||||
|
||||
struct RealVfsFile : public VfsFile {
|
||||
RealVfsFile(const filesystem::path& name, filesystem::perms perms);
|
||||
RealVfsFile(const filesystem::path& name,
|
||||
filesystem::perms perms = filesystem::perms::owner_read);
|
||||
|
||||
std::string GetName() const override;
|
||||
size_t GetSize() const override;
|
||||
|
||||
@@ -621,7 +621,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
FileSys::Path unused;
|
||||
auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused);
|
||||
auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData);
|
||||
if (savedata.Failed()) {
|
||||
// Create the save data and return an error indicating that the operation was performed.
|
||||
FileSystem::FormatFileSystem(FileSystem::Type::SaveData);
|
||||
|
||||
@@ -7,116 +7,132 @@
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/filesystem.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(v_dir backing_) : backing(backing_) { }
|
||||
VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(v_dir backing_) : backing(backing_) {}
|
||||
|
||||
std::string VfsDirectoryServiceWrapper::GetName() const {
|
||||
return backing->GetName();
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const {
|
||||
filesystem::path s_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(s_path.parent_path());
|
||||
auto file = dir->CreateFile(path.filename().string());
|
||||
if (file == nullptr) return ResultCode(-1);
|
||||
if (!file->Resize(size)) return ResultCode(-1);
|
||||
auto file = dir->CreateFile(s_path.filename().string());
|
||||
if (file == nullptr)
|
||||
return ResultCode(-1);
|
||||
if (!file->Resize(size))
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const {
|
||||
filesystem::path s_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(s_path.parent_path());
|
||||
if (!backing->DeleteFile(s_path.filename().string())) return ResultCode(-1);
|
||||
if (!backing->DeleteFile(s_path.filename().string()))
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const {
|
||||
filesystem::path s_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(s_path.parent_path());
|
||||
auto new_dir = dir->CreateSubdirectory(path.filename().name);
|
||||
if (new_dir == nullptr) return ResultCode(-1);
|
||||
auto new_dir = dir->CreateSubdirectory(s_path.filename().string());
|
||||
if (new_dir == nullptr)
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const {
|
||||
filesystem::path s_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(s_path.parent_path());
|
||||
if (!dir->DeleteSubdirectory(path.filename().string())) return ResultCode(-1);
|
||||
if (!dir->DeleteSubdirectory(s_path.filename().string()))
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const {
|
||||
filesystem::path s_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(s_path.parent_path());
|
||||
if (!dir->DeleteSubdirectoryRecursive(path.filename().string())) return ResultCode(-1);
|
||||
if (!dir->DeleteSubdirectoryRecursive(s_path.filename().string()))
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, const std::string& dest_path) const {
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path,
|
||||
const std::string& dest_path) const {
|
||||
filesystem::path s_path(src_path);
|
||||
auto file = backing->GetFileRelative(s_path);
|
||||
file->GetContainingDirectory()->DeleteFile(file->GetName());
|
||||
auto res_code = CreateFile(dest_path, file->GetSize());
|
||||
if (res_code != RESULT_SUCCESS) return res_code;
|
||||
if (res_code != RESULT_SUCCESS)
|
||||
return res_code;
|
||||
auto file2 = backing->GetFileRelative(filesystem::path(dest_path));
|
||||
if (file2->WriteBytes(file->ReadAllBytes() != file->GetSize()) return ResultCode(-1);
|
||||
if (file2->WriteBytes(file->ReadAllBytes()) != file->GetSize())
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultCode
|
||||
VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, const std::string& dest_path) const {
|
||||
ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path,
|
||||
const std::string& dest_path) const {
|
||||
filesystem::path s_path(src_path);
|
||||
auto file = backing->GetFileRelative(s_path);
|
||||
file->GetContainingDirectory()->DeleteFile(file->GetName());
|
||||
auto res_code = CreateFile(dest_path, file->GetSize());
|
||||
if (res_code != RESULT_SUCCESS) return res_code;
|
||||
if (res_code != RESULT_SUCCESS)
|
||||
return res_code;
|
||||
auto file2 = backing->GetFileRelative(filesystem::path(dest_path));
|
||||
if (file2->WriteBytes(file->ReadAllBytes() != file->GetSize())) return ResultCode(-1);
|
||||
if (file2->WriteBytes(file->ReadAllBytes()) != file->GetSize())
|
||||
return ResultCode(-1);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultVal<v_file> VfsDirectoryServiceWrapper::OpenFile(const std::string& path, FileSys::Mode mode) const {
|
||||
ResultVal<v_file> VfsDirectoryServiceWrapper::OpenFile(const std::string& path,
|
||||
FileSys::Mode mode) const {
|
||||
auto file = backing->GetFileRelative(filesystem::path(path));
|
||||
if (file == nullptr) return ResultVal<v_file>(-1);
|
||||
if (mode == FileSys::Mode::Append) return MakeResult(std::make_shared<OffsetVfsFile>(file, 0, file->GetSize()));
|
||||
else if (mode == FileSys::Mode::Write && file->IsWritable()) return file;
|
||||
else if (mode == FileSys::Mode::Read && file->IsReadable()) return file;
|
||||
return ResultVal<v_file>(-1);
|
||||
if (file == nullptr)
|
||||
return ResultCode(-1);
|
||||
if (mode == FileSys::Mode::Append)
|
||||
return MakeResult<v_file>(
|
||||
std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()));
|
||||
else if (mode == FileSys::Mode::Write && file->IsWritable())
|
||||
return MakeResult<v_file>(file);
|
||||
else if (mode == FileSys::Mode::Read && file->IsReadable())
|
||||
return MakeResult<v_file>(file);
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultVal<v_dir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) const {
|
||||
auto dir = backing->GetDirectoryRelative(filesystem::path(path));
|
||||
if (dir == nullptr) return ResultVal<v_dir>(-1);
|
||||
return MakeResult(RESULT_SUCCESS, dir);
|
||||
if (dir == nullptr)
|
||||
return ResultCode(-1);
|
||||
return MakeResult(dir);
|
||||
}
|
||||
|
||||
u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
|
||||
// TODO(DarkLordZach): Infinite? Actual? Is this actually used productively or...?
|
||||
if (backing->IsWritable())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Verify path usage.
|
||||
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(const std::string& path) const {
|
||||
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
const std::string& path) const {
|
||||
filesystem::path r_path(path);
|
||||
auto dir = backing->GetDirectoryRelative(r_path.parent_path());
|
||||
if (dir == nullptr) return ResultVal<FileSys::EntryType>(-1);
|
||||
if (dir->GetFile(r_path.filename().string()) != nullptr) return MakeResult(FileSys::EntryType::File);
|
||||
if (dir->GetSubdirectory(r_path.filename().string()) != nullptr) return MakeResult(FileSys::EntryType::Directory);
|
||||
return ResultVal<FileSys::EntryType>(-1);
|
||||
if (dir == nullptr)
|
||||
return ResultCode(-1);
|
||||
if (dir->GetFile(r_path.filename().string()) != nullptr)
|
||||
return MakeResult(FileSys::EntryType::File);
|
||||
if (dir->GetSubdirectory(r_path.filename().string()) != nullptr)
|
||||
return MakeResult(FileSys::EntryType::Directory);
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,7 +177,8 @@ ResultVal<v_dir> OpenFileSystem(Type type) {
|
||||
}
|
||||
|
||||
ResultVal<v_file> OpenRomFS() {
|
||||
if (filesystem_romfs == nullptr) return ResultVal<v_file>(-1);
|
||||
if (filesystem_romfs == nullptr)
|
||||
return ResultCode(-1);
|
||||
return MakeResult(filesystem_romfs);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/filesystem.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
@@ -121,10 +122,6 @@ public:
|
||||
ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
|
||||
};
|
||||
|
||||
class VfsFileServiceWrapper {
|
||||
v_file backing;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a FileSystem, instances of which can later be opened using its IdCode.
|
||||
* @param factory FileSystem backend interface to use
|
||||
|
||||
@@ -137,8 +137,10 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data = ctx.ReadBuffer();
|
||||
data.resize(length);
|
||||
// Write the data to the Storage backend
|
||||
auto res = MakeResult<size_t>(backend->WriteBytes(ctx.ReadBuffer(), length, offset));
|
||||
auto res = MakeResult<size_t>(backend->WriteBytes(data, offset));
|
||||
if (res.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
@@ -180,17 +182,37 @@ private:
|
||||
|
||||
class IDirectory final : public ServiceFramework<IDirectory> {
|
||||
public:
|
||||
explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend)
|
||||
: ServiceFramework("IDirectory"), backend(std::move(backend)) {
|
||||
explicit IDirectory(v_dir backend_) : ServiceFramework("IDirectory"), backend(backend_) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IDirectory::Read, "Read"},
|
||||
{1, &IDirectory::GetEntryCount, "GetEntryCount"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
// Build entry index now to save time later.
|
||||
for (const auto& file : backend->GetFiles()) {
|
||||
FileSys::Entry entry;
|
||||
entry.filename[0] = '\0';
|
||||
strncat(entry.filename, file->GetName().c_str(), FileSys::FILENAME_LENGTH - 1);
|
||||
entry.type = FileSys::File;
|
||||
entry.file_size = file->GetSize();
|
||||
entries.emplace_back(entry);
|
||||
}
|
||||
|
||||
for (const auto& dir : backend->GetSubdirectories()) {
|
||||
FileSys::Entry entry;
|
||||
entry.filename[0] = '\0';
|
||||
strncat(entry.filename, dir->GetName().c_str(), FileSys::FILENAME_LENGTH - 1);
|
||||
entry.type = FileSys::Directory;
|
||||
entry.file_size = dir->GetSize();
|
||||
entries.emplace_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::DirectoryBackend> backend;
|
||||
v_dir backend;
|
||||
std::vector<FileSys::Entry> entries;
|
||||
u64 next_entry_index = 0;
|
||||
|
||||
void Read(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
@@ -201,26 +223,29 @@ private:
|
||||
// Calculate how many entries we can fit in the output buffer
|
||||
u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
|
||||
|
||||
// Cap at total number of entries.
|
||||
u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
|
||||
|
||||
// Read the data from the Directory backend
|
||||
std::vector<FileSys::Entry> entries(count_entries);
|
||||
u64 read_entries = backend->Read(count_entries, entries.data());
|
||||
std::vector<FileSys::Entry> entry_data(entries.begin() + next_entry_index,
|
||||
entries.begin() + next_entry_index + actual_entries);
|
||||
|
||||
// Convert the data into a byte array
|
||||
std::vector<u8> output(entries.size() * sizeof(FileSys::Entry));
|
||||
std::memcpy(output.data(), entries.data(), output.size());
|
||||
std::vector<u8> output(entry_data.size() * sizeof(FileSys::Entry));
|
||||
std::memcpy(output.data(), entry_data.data(), output.size());
|
||||
|
||||
// Write the data to memory
|
||||
ctx.WriteBuffer(output);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(read_entries);
|
||||
rb.Push(actual_entries);
|
||||
}
|
||||
|
||||
void GetEntryCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
u64 count = backend->GetEntryCount();
|
||||
u64 count = entries.size() - next_entry_index;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -265,12 +290,7 @@ public:
|
||||
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
auto b1 = backend->CreateFile(name);
|
||||
if (b1 == nullptr) {
|
||||
}
|
||||
auto b2 = b1->Res
|
||||
|
||||
rb.Push(? RESULT_SUCCESS : ResultCode(-1));
|
||||
rb.Push(backend.CreateFile(name, size));
|
||||
}
|
||||
|
||||
void DeleteFile(Kernel::HLERequestContext& ctx) {
|
||||
@@ -282,7 +302,7 @@ public:
|
||||
LOG_DEBUG(Service_FS, "called file {}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend->DeleteFile(name));
|
||||
rb.Push(backend.DeleteFile(name));
|
||||
}
|
||||
|
||||
void CreateDirectory(Kernel::HLERequestContext& ctx) {
|
||||
@@ -294,8 +314,7 @@ public:
|
||||
LOG_DEBUG(Service_FS, "called directory {}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
auto dir = backend->CreateSubdirectory(name);
|
||||
rb.Push(dir == nullptr ? -1 : 0);
|
||||
rb.Push(backend.CreateDirectory(name));
|
||||
}
|
||||
|
||||
void RenameFile(Kernel::HLERequestContext& ctx) {
|
||||
@@ -313,7 +332,7 @@ public:
|
||||
LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend->RenameFile(src_name, dst_name));
|
||||
rb.Push(backend.RenameFile(src_name, dst_name));
|
||||
}
|
||||
|
||||
void OpenFile(Kernel::HLERequestContext& ctx) {
|
||||
@@ -326,14 +345,14 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode));
|
||||
|
||||
auto result = backend->OpenFile(name, mode);
|
||||
auto result = backend.OpenFile(name, mode);
|
||||
if (result.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
return;
|
||||
}
|
||||
|
||||
auto file = std::move(result.Unwrap());
|
||||
IFile file(result.Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -351,14 +370,14 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags);
|
||||
|
||||
auto result = backend->OpenDirectory(name);
|
||||
auto result = backend.OpenDirectory(name);
|
||||
if (result.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
return;
|
||||
}
|
||||
|
||||
auto directory = std::move(result.Unwrap());
|
||||
IDirectory directory(result.Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -373,7 +392,7 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {}", name);
|
||||
|
||||
auto result = backend->GetEntryType(name);
|
||||
auto result = backend.GetEntryType(name);
|
||||
if (result.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
@@ -393,7 +412,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
v_dir backend;
|
||||
VfsDirectoryServiceWrapper backend;
|
||||
};
|
||||
|
||||
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
@@ -510,7 +529,7 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
auto filesystem = OpenFileSystem(Type::SDMC).Unwrap();
|
||||
IFileSystem filesystem(OpenFileSystem(Type::SDMC).Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -533,8 +552,7 @@ void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
FileSys::Path unused;
|
||||
auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap();
|
||||
IFileSystem filesystem(OpenFileSystem(Type::SaveData).Unwrap());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -561,9 +579,11 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
IStorage storage(romfs);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
|
||||
rb.PushIpcInterface<IStorage>(std::move(storage));
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -102,27 +102,19 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
|
||||
metadata.GetMainThreadStackSize());
|
||||
|
||||
// Find the RomFS by searching for a ".romfs" file in this directory
|
||||
const auto romfs_iter =
|
||||
std::find_if(dir->GetFiles().begin(), dir->GetFiles().end(), [](const v_file& file) {
|
||||
return file->GetName().find(".romfs") != std::string::npos;
|
||||
});
|
||||
const auto& files = dir->GetFiles();
|
||||
const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const v_file& file) {
|
||||
return file->GetName().find(".romfs") != std::string::npos;
|
||||
});
|
||||
|
||||
// TODO(DarkLordZach): Identify RomFS if its a subdirectory.
|
||||
romfs = (romfs_iter == dir->GetFiles().end()) ? nullptr : *romfs_iter;
|
||||
const auto romfs = (romfs_iter == files.end()) ? nullptr : *romfs_iter;
|
||||
|
||||
if (romfs != nullptr)
|
||||
Service::FileSystem::RegisterRomFS(romfs);
|
||||
|
||||
is_loaded = true;
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(v_file& file) {
|
||||
if (romfs == nullptr) {
|
||||
LOG_DEBUG(Loader, "No RomFS available");
|
||||
return ResultStatus::ErrorNotUsed;
|
||||
}
|
||||
|
||||
file = romfs;
|
||||
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -35,10 +35,7 @@ public:
|
||||
|
||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||
|
||||
ResultStatus ReadRomFS(v_file& file) override;
|
||||
|
||||
private:
|
||||
v_file romfs;
|
||||
FileSys::ProgramMetadata metadata;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/loader/deconstructed_rom_directory.h"
|
||||
#include "core/loader/elf.h"
|
||||
@@ -41,25 +42,19 @@ FileType IdentifyFile(v_file file) {
|
||||
}
|
||||
|
||||
FileType IdentifyFile(const std::string& file_name) {
|
||||
FileUtil::IOFile file(file_name, "rb");
|
||||
if (!file.IsOpen()) {
|
||||
LOG_ERROR(Loader, "Failed to load file {}", file_name);
|
||||
return FileType::Unknown;
|
||||
}
|
||||
|
||||
return IdentifyFile(file, file_name);
|
||||
return IdentifyFile(v_file(std::make_shared<FileSys::RealVfsFile>(file_name)));
|
||||
}
|
||||
|
||||
FileType GuessFromExtension(const std::string& extension_) {
|
||||
std::string extension = Common::ToLower(extension_);
|
||||
|
||||
if (extension == ".elf")
|
||||
if (extension == "elf")
|
||||
return FileType::ELF;
|
||||
else if (extension == ".nro")
|
||||
else if (extension == "nro")
|
||||
return FileType::NRO;
|
||||
else if (extension == ".nso")
|
||||
else if (extension == "nso")
|
||||
return FileType::NSO;
|
||||
else if (extension == ".nca")
|
||||
else if (extension == "nca")
|
||||
return FileType::NCA;
|
||||
|
||||
return FileType::Unknown;
|
||||
|
||||
@@ -37,10 +37,9 @@ enum class FileType {
|
||||
/**
|
||||
* Identifies the type of a bootable file based on the magic value in its header.
|
||||
* @param file open file
|
||||
* @param filepath Path of the file that we are opening.
|
||||
* @return FileType of file
|
||||
*/
|
||||
FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath);
|
||||
FileType IdentifyFile(v_file file);
|
||||
|
||||
/**
|
||||
* Identifies the type of a bootable file based on the magic value in its header.
|
||||
@@ -197,6 +196,6 @@ extern const std::initializer_list<Kernel::AddressMapping> default_address_mappi
|
||||
* @param filename String filename of bootable file
|
||||
* @return best loader for this file
|
||||
*/
|
||||
std::unique_ptr<AppLoader> GetLoader(const std::string& filename);
|
||||
std::unique_ptr<AppLoader> GetLoader(v_file file);
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -66,6 +66,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
|
||||
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
|
||||
const VAddr load_addr = next_load_addr;
|
||||
|
||||
next_load_addr = AppLoader_NSO::LoadModule(exefs->GetFile(module), load_addr);
|
||||
if (next_load_addr) {
|
||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
|
||||
@@ -83,18 +84,10 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
||||
metadata.GetMainThreadStackSize());
|
||||
|
||||
is_loaded = true;
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NCA::ReadRomFS(v_file& file) {
|
||||
const auto romfs = nca->GetRomFS();
|
||||
|
||||
if (romfs == nullptr) {
|
||||
NGLOG_DEBUG(Loader, "No RomFS available");
|
||||
return ResultStatus::ErrorNotUsed;
|
||||
}
|
||||
|
||||
file = romfs;
|
||||
if (romfs != nullptr)
|
||||
Service::FileSystem::RegisterRomFS(romfs);
|
||||
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ public:
|
||||
|
||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||
|
||||
ResultStatus ReadRomFS(v_file& file) override;
|
||||
|
||||
~AppLoader_NCA();
|
||||
|
||||
private:
|
||||
|
||||
@@ -96,6 +96,9 @@ static constexpr u32 PageAlignSize(u32 size) {
|
||||
}
|
||||
|
||||
VAddr AppLoader_NSO::LoadModule(v_file file, VAddr load_base) {
|
||||
if (file == nullptr)
|
||||
return {};
|
||||
|
||||
if (file->GetSize() < sizeof(NsoHeader))
|
||||
return {};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/common_paths.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "game_list.h"
|
||||
#include "game_list_p.h"
|
||||
@@ -404,7 +405,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||
bool is_dir = FileUtil::IsDirectory(physical_name);
|
||||
if (!is_dir &&
|
||||
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
|
||||
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name);
|
||||
std::unique_ptr<Loader::AppLoader> loader =
|
||||
Loader::GetLoader(std::make_unique<FileSys::RealVfsFile>(physical_name));
|
||||
if (!loader)
|
||||
return true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user