summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/am/am.cpp1
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp209
-rw-r--r--src/core/hle/service/filesystem/filesystem.h110
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp177
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
5 files changed, 383 insertions, 116 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 0f0ab1e6a..97ef07bf9 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -5,7 +5,6 @@
#include <cinttypes>
#include <stack>
#include "core/core.h"
-#include "core/file_sys/filesystem.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 902256757..ec528ef40 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -2,17 +2,204 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <boost/container/flat_map.hpp>
+#pragma optimize("", off)
+
+#include "common/assert.h"
#include "common/file_util.h"
+#include "core/core.h"
#include "core/file_sys/errors.h"
-#include "core/file_sys/filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.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 {
+// Size of emulated sd card free space, reported in bytes.
+// Just using 32GB because thats reasonable
+// TODO(DarkLordZach): Eventually make this configurable in settings.
+constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
+
+static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
+ const std::string& dir_name) {
+ if (dir_name == "." || dir_name == "" || dir_name == "/" || dir_name == "\\")
+ return base;
+
+ return base->GetDirectoryRelative(dir_name);
+}
+
+VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
+ : backing(backing_) {}
+
+std::string VfsDirectoryServiceWrapper::GetName() const {
+ return backing->GetName();
+}
+
+ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ auto file = dir->CreateFile(FileUtil::GetFilename(path));
+ if (file == nullptr) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ if (!file->Resize(size)) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ if (path == "/" || path == "\\") {
+ // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
+ return RESULT_SUCCESS;
+ }
+ if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr)
+ return FileSys::ERROR_PATH_NOT_FOUND;
+ if (!backing->DeleteFile(FileUtil::GetFilename(path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty())
+ dir = backing;
+ auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path));
+ if (new_dir == nullptr) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path,
+ const std::string& dest_path) const {
+ auto src = backing->GetFileRelative(src_path);
+ if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
+ // Use more-optimized vfs implementation rename.
+ if (src == nullptr)
+ return FileSys::ERROR_PATH_NOT_FOUND;
+ if (!src->Rename(FileUtil::GetFilename(dest_path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+ }
+
+ // Move by hand -- TODO(DarkLordZach): Optimize
+ auto c_res = CreateFile(dest_path, src->GetSize());
+ if (c_res != RESULT_SUCCESS)
+ return c_res;
+
+ auto dest = backing->GetFileRelative(dest_path);
+ ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
+
+ ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
+ "Could not write all of the bytes but everything else has succeded.");
+
+ if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path,
+ const std::string& dest_path) const {
+ auto src = GetDirectoryRelativeWrapped(backing, src_path);
+ if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
+ // Use more-optimized vfs implementation rename.
+ if (src == nullptr)
+ return FileSys::ERROR_PATH_NOT_FOUND;
+ if (!src->Rename(FileUtil::GetFilename(dest_path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return RESULT_SUCCESS;
+ }
+
+ // TODO(DarkLordZach): Implement renaming across the tree (move).
+ ASSERT_MSG(false,
+ "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs "
+ "don't match -- UNIMPLEMENTED",
+ src_path, dest_path);
+
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+}
+
+ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path,
+ FileSys::Mode mode) const {
+ auto npath = path;
+ while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\'))
+ npath = npath.substr(1);
+ auto file = backing->GetFileRelative(npath);
+ if (file == nullptr)
+ return FileSys::ERROR_PATH_NOT_FOUND;
+
+ if (mode == FileSys::Mode::Append) {
+ return MakeResult<FileSys::VirtualFile>(
+ std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()));
+ }
+
+ return MakeResult<FileSys::VirtualFile>(file);
+}
+
+ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) {
+ auto dir = GetDirectoryRelativeWrapped(backing, path);
+ if (dir == nullptr) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+ return MakeResult(dir);
+}
+
+u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
+ if (backing->IsWritable())
+ return EMULATED_SD_REPORTED_SIZE;
+
+ return 0;
+}
+
+ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
+ const std::string& path) const {
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
+ if (dir == nullptr)
+ return FileSys::ERROR_PATH_NOT_FOUND;
+ auto filename = FileUtil::GetFilename(path);
+ if (dir->GetFile(filename) != nullptr)
+ return MakeResult(FileSys::EntryType::File);
+ if (dir->GetSubdirectory(filename) != nullptr)
+ return MakeResult(FileSys::EntryType::Directory);
+ return FileSys::ERROR_PATH_NOT_FOUND;
+}
+
/**
* Map of registered file systems, identified by type. Once an file system is registered here, it
* is never removed until UnregisterFileSystems is called.
@@ -42,7 +229,7 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
return RESULT_SUCCESS;
}
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) {
+ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
if (romfs_factory == nullptr) {
@@ -53,19 +240,19 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) {
return romfs_factory->Open(title_id);
}
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
- FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct) {
+ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
+ FileSys::SaveDataDescriptor save_struct) {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
- static_cast<u8>(space), SaveStructDebugInfo(save_struct));
+ static_cast<u8>(space), save_struct.DebugInfo());
if (save_data_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound);
+ return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
}
return save_data_factory->Open(space, save_struct);
}
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC() {
+ResultVal<FileSys::VirtualDir> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
@@ -80,8 +267,10 @@ void RegisterFileSystems() {
save_data_factory = nullptr;
sdmc_factory = nullptr;
- std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
- std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
+ auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
+ FileUtil::GetUserPath(D_NAND_IDX), FileSys::Mode::Write);
+ auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
+ FileUtil::GetUserPath(D_SDMC_IDX), FileSys::Mode::Write);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 45272d326..d4483daa5 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -6,15 +6,13 @@
#include <memory>
#include "common/common_types.h"
+#include "core/file_sys/directory.h"
+#include "core/file_sys/mode.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/hle/result.h"
-namespace FileSys {
-class FileSystemBackend;
-} // namespace FileSys
-
namespace Service {
namespace SM {
@@ -29,11 +27,10 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
// TODO(DarkLordZach): BIS Filesystem
// ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
-
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id);
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
- FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct);
-ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC();
+ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id);
+ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
+ FileSys::SaveDataDescriptor save_struct);
+ResultVal<FileSys::VirtualDir> OpenSDMC();
// TODO(DarkLordZach): BIS Filesystem
// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
@@ -41,5 +38,100 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC();
/// Registers all Filesystem services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
+// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
+// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
+// avoids repetitive code.
+class VfsDirectoryServiceWrapper {
+public:
+ explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing);
+
+ /**
+ * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
+ */
+ std::string GetName() const;
+
+ /**
+ * Create a file specified by its path
+ * @param path Path relative to the Archive
+ * @param size The size of the new file, filled with zeroes
+ * @return Result of the operation
+ */
+ ResultCode CreateFile(const std::string& path, u64 size) const;
+
+ /**
+ * Delete a file specified by its path
+ * @param path Path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode DeleteFile(const std::string& path) const;
+
+ /**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode CreateDirectory(const std::string& path) const;
+
+ /**
+ * Delete a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode DeleteDirectory(const std::string& path) const;
+
+ /**
+ * Delete a directory specified by its path and anything under it
+ * @param path Path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode DeleteDirectoryRecursively(const std::string& path) const;
+
+ /**
+ * Rename a File specified by its path
+ * @param src_path Source path relative to the archive
+ * @param dest_path Destination path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const;
+
+ /**
+ * Rename a Directory specified by its path
+ * @param src_path Source path relative to the archive
+ * @param dest_path Destination path relative to the archive
+ * @return Result of the operation
+ */
+ ResultCode RenameDirectory(const std::string& src_path, const std::string& dest_path) const;
+
+ /**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or error code
+ */
+ ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const;
+
+ /**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or error code
+ */
+ ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
+
+ /**
+ * Get the free space
+ * @return The number of free bytes in the archive
+ */
+ u64 GetFreeSpaceSize() const;
+
+ /**
+ * Get the type of the specified path
+ * @return The type of the specified path or error code
+ */
+ ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
+
+private:
+ FileSys::VirtualDir backing;
+};
+
} // namespace FileSystem
} // namespace Service
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 22d3e645d..1b003bd84 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -8,11 +8,7 @@
#include "core/core.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/errors.h"
-#include "core/file_sys/filesystem.h"
-#include "core/file_sys/storage.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
@@ -25,13 +21,13 @@ enum class StorageId : u8 {
GameCard = 2,
NandSystem = 3,
NandUser = 4,
- SdCard = 5
+ SdCard = 5,
};
class IStorage final : public ServiceFramework<IStorage> {
public:
- IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
- : ServiceFramework("IStorage"), backend(std::move(backend)) {
+ IStorage(FileSys::VirtualFile backend_)
+ : ServiceFramework("IStorage"), backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
{3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"},
@@ -40,7 +36,7 @@ public:
}
private:
- std::unique_ptr<FileSys::StorageBackend> backend;
+ FileSys::VirtualFile backend;
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -62,14 +58,7 @@ private:
}
// Read the data from the Storage backend
- std::vector<u8> output(length);
- ResultVal<size_t> res = backend->Read(offset, length, output.data());
- if (res.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(res.Code());
- return;
- }
-
+ std::vector<u8> output = backend->ReadBytes(length, offset);
// Write the data to memory
ctx.WriteBuffer(output);
@@ -80,8 +69,8 @@ private:
class IFile final : public ServiceFramework<IFile> {
public:
- explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend)
- : ServiceFramework("IFile"), backend(std::move(backend)) {
+ explicit IFile(FileSys::VirtualFile backend_)
+ : ServiceFramework("IFile"), backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
{2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
@@ -91,7 +80,7 @@ public:
}
private:
- std::unique_ptr<FileSys::StorageBackend> backend;
+ FileSys::VirtualFile backend;
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -114,20 +103,14 @@ private:
}
// Read the data from the Storage backend
- std::vector<u8> output(length);
- ResultVal<size_t> res = backend->Read(offset, length, output.data());
- if (res.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(res.Code());
- return;
- }
+ std::vector<u8> output = backend->ReadBytes(length, offset);
// Write the data to memory
ctx.WriteBuffer(output);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(*res));
+ rb.Push(static_cast<u64>(output.size()));
}
void Write(Kernel::HLERequestContext& ctx) {
@@ -150,14 +133,21 @@ private:
return;
}
- // Write the data to the Storage backend
std::vector<u8> data = ctx.ReadBuffer();
- ResultVal<size_t> res = backend->Write(offset, length, true, data.data());
- if (res.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(res.Code());
- return;
- }
+ std::vector<u8> actual_data(length);
+
+ ASSERT_MSG(
+ data.size() <= length,
+ "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
+ length, data.size());
+
+ std::copy(data.begin(), data.end(), actual_data.begin());
+ // Write the data to the Storage backend
+ auto written = backend->WriteBytes(data, offset);
+
+ ASSERT_MSG(written == length,
+ "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
+ written);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -165,7 +155,8 @@ private:
void Flush(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- backend->Flush();
+
+ // Exists for SDK compatibiltity -- No need to flush file.
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -174,7 +165,7 @@ private:
void SetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
- backend->SetSize(size);
+ backend->Resize(size);
LOG_DEBUG(Service_FS, "called, size={}", size);
IPC::ResponseBuilder rb{ctx, 2};
@@ -191,19 +182,39 @@ private:
}
};
+template <typename T>
+static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
+ FileSys::EntryType type) {
+ for (const auto& new_entry : new_data) {
+ FileSys::Entry entry;
+ entry.filename[0] = '\0';
+ std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1);
+ entry.type = type;
+ entry.file_size = new_entry->GetSize();
+ entries.emplace_back(std::move(entry));
+ }
+}
+
class IDirectory final : public ServiceFramework<IDirectory> {
public:
- explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend)
- : ServiceFramework("IDirectory"), backend(std::move(backend)) {
+ explicit IDirectory(FileSys::VirtualDir backend_)
+ : ServiceFramework("IDirectory"), backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IDirectory::Read, "Read"},
{1, &IDirectory::GetEntryCount, "GetEntryCount"},
};
RegisterHandlers(functions);
+
+ // TODO(DarkLordZach): Verify that this is the correct behavior.
+ // Build entry index now to save time later.
+ BuildEntryIndex(entries, backend->GetFiles(), FileSys::File);
+ BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory);
}
private:
- std::unique_ptr<FileSys::DirectoryBackend> backend;
+ FileSys::VirtualDir backend;
+ std::vector<FileSys::Entry> entries;
+ u64 next_entry_index = 0;
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -214,26 +225,31 @@ 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);
+
+ 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);
@@ -243,7 +259,7 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
- explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend)
+ explicit IFileSystem(FileSys::VirtualDir backend)
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
@@ -278,7 +294,7 @@ public:
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend->CreateFile(name, size));
+ rb.Push(backend.CreateFile(name, size));
}
void DeleteFile(Kernel::HLERequestContext& ctx) {
@@ -290,7 +306,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) {
@@ -302,7 +318,7 @@ public:
LOG_DEBUG(Service_FS, "called directory {}", name);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend->CreateDirectory(name));
+ rb.Push(backend.CreateDirectory(name));
}
void RenameFile(Kernel::HLERequestContext& ctx) {
@@ -320,7 +336,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) {
@@ -333,14 +349,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);
@@ -358,14 +374,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);
@@ -380,7 +396,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());
@@ -400,7 +416,7 @@ public:
}
private:
- std::unique_ptr<FileSys::FileSystemBackend> backend;
+ VfsDirectoryServiceWrapper backend;
};
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
@@ -536,17 +552,19 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
- auto filesystem = OpenSaveData(space_id, save_struct);
+ auto dir = OpenSaveData(space_id, save_struct);
- if (filesystem.Failed()) {
+ if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound));
+ rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
return;
}
+ IFileSystem filesystem(std::move(dir.Unwrap()));
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem.Unwrap()));
+ rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
}
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
@@ -569,18 +587,11 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
return;
}
- auto storage = romfs.Unwrap()->OpenFile({}, {});
-
- if (storage.Failed()) {
- LOG_CRITICAL(Service_FS, "no storage interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(storage.Code());
- return;
- }
+ IStorage storage(std::move(romfs.Unwrap()));
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) {
@@ -591,33 +602,9 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}",
static_cast<u8>(storage_id), title_id);
- if (title_id != Core::System::GetInstance().CurrentProcess()->program_id) {
- LOG_CRITICAL(
- Service_FS,
- "Attempting to access RomFS of another title id (current={:016X}, requested={:016X}).",
- Core::System::GetInstance().CurrentProcess()->program_id, title_id);
- }
- auto romfs = OpenRomFS(title_id);
- if (romfs.Failed()) {
- LOG_CRITICAL(Service_FS, "no file system interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::RomFSNotFound));
- return;
- }
-
- auto storage = romfs.Unwrap()->OpenFile({}, {});
-
- if (storage.Failed()) {
- LOG_CRITICAL(Service_FS, "no storage interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(storage.Code());
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4653eee4e..07f99c93d 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -27,7 +27,7 @@ private:
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenRomStorage(Kernel::HLERequestContext& ctx);
- std::unique_ptr<FileSys::FileSystemBackend> romfs;
+ FileSys::VirtualFile romfs;
};
} // namespace Service::FileSystem