mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-04 23:35:12 +01:00
Split VFS implementations from API
This allows better validation and simplified default argument handling. Could also be useful in the future when we switch to proper VFS error reporting.
This commit is contained in:
parent
48acb6d369
commit
5f942e2dff
@ -10,6 +10,17 @@ namespace skyline::vfs {
|
||||
* @brief The Backing class provides abstract access to a storage device, all access can be done without using a specific backing
|
||||
*/
|
||||
class Backing {
|
||||
protected:
|
||||
virtual size_t ReadImpl(span <u8> output, size_t offset) = 0;
|
||||
|
||||
virtual size_t WriteImpl(span <u8> input, size_t offset) {
|
||||
throw exception("This backing does not support being written to");
|
||||
}
|
||||
|
||||
virtual void ResizeImpl(size_t pSize) {
|
||||
throw exception("This backing does not support being resized");
|
||||
}
|
||||
|
||||
public:
|
||||
union Mode {
|
||||
struct {
|
||||
@ -42,7 +53,15 @@ namespace skyline::vfs {
|
||||
* @param offset The offset to start reading from
|
||||
* @return The amount of bytes read
|
||||
*/
|
||||
virtual size_t Read(span <u8> output, size_t offset = 0) = 0;
|
||||
size_t Read(span <u8> output, size_t offset = 0) {
|
||||
if (!mode.read)
|
||||
throw exception("Attempting to read a backing that is not readable");
|
||||
|
||||
if ((static_cast<ssize_t>(size) - offset) < output.size())
|
||||
throw exception("Trying to read past the end of a backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", output.size(), size, offset);
|
||||
|
||||
return ReadImpl(output, offset);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implicit casting for reading into spans of different types
|
||||
@ -70,8 +89,18 @@ namespace skyline::vfs {
|
||||
* @param offset The offset where the input buffer should be written
|
||||
* @return The amount of bytes written
|
||||
*/
|
||||
virtual size_t Write(span <u8> input, size_t offset = 0) {
|
||||
throw exception("This backing does not support being written to");
|
||||
size_t Write(span <u8> input, size_t offset = 0) {
|
||||
if (!mode.write)
|
||||
throw exception("Attempting to write to a backing that is not writable");
|
||||
|
||||
if (input.size() > (static_cast<ssize_t>(size) - offset)) {
|
||||
if (mode.append)
|
||||
Resize(offset + input.size());
|
||||
else
|
||||
throw exception("Trying to write past the end of a non-appendable backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", input.size(), size, offset);
|
||||
}
|
||||
|
||||
return WriteImpl(input, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,17 +110,17 @@ namespace skyline::vfs {
|
||||
*/
|
||||
template<typename T>
|
||||
void WriteObject(const T &object, size_t offset = 0) {
|
||||
size_t size;
|
||||
if ((size = Write(span(reinterpret_cast<u8 *>(&object), sizeof(T)), offset)) != sizeof(T))
|
||||
throw exception("Object wasn't written fully into output backing: {}/{}", size, sizeof(T));
|
||||
size_t lSize;
|
||||
if ((lSize = Write(span(reinterpret_cast<u8 *>(&object), sizeof(T)), offset)) != sizeof(T))
|
||||
throw exception("Object wasn't written fully into output backing: {}/{}", lSize, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes a backing to the given size
|
||||
* @param size The new size for the backing
|
||||
* @param pSize The new size for the backing
|
||||
*/
|
||||
virtual void Resize(size_t size) {
|
||||
throw exception("This backing does not support being resized");
|
||||
void Resize(size_t pSize) {
|
||||
ResizeImpl(pSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,10 @@
|
||||
namespace skyline::vfs {
|
||||
constexpr size_t SectorSize{0x10};
|
||||
|
||||
CtrEncryptedBacking::CtrEncryptedBacking(crypto::KeyStore::Key128 ctr, crypto::KeyStore::Key128 key, std::shared_ptr<Backing> backing, size_t baseOffset) : Backing({true, false, false}), ctr(ctr), cipher(key, MBEDTLS_CIPHER_AES_128_CTR), backing(std::move(backing)), baseOffset(baseOffset) {}
|
||||
CtrEncryptedBacking::CtrEncryptedBacking(crypto::KeyStore::Key128 ctr, crypto::KeyStore::Key128 key, std::shared_ptr<Backing> backing, size_t baseOffset) : Backing({true, false, false}), ctr(ctr), cipher(key, MBEDTLS_CIPHER_AES_128_CTR), backing(std::move(backing)), baseOffset(baseOffset) {
|
||||
if (mode.write || mode.append)
|
||||
throw exception("Cannot open a CtrEncryptedBacking as writable");
|
||||
}
|
||||
|
||||
void CtrEncryptedBacking::UpdateCtr(u64 offset) {
|
||||
offset >>= 4;
|
||||
@ -15,7 +18,7 @@ namespace skyline::vfs {
|
||||
cipher.SetIV(ctr);
|
||||
}
|
||||
|
||||
size_t CtrEncryptedBacking::Read(span<u8> output, size_t offset) {
|
||||
size_t CtrEncryptedBacking::ReadImpl(span<u8> output, size_t offset) {
|
||||
size_t size{output.size()};
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
@ -24,9 +24,10 @@ namespace skyline::vfs {
|
||||
*/
|
||||
void UpdateCtr(u64 offset);
|
||||
|
||||
protected:
|
||||
size_t ReadImpl(span<u8> output, size_t offset) override;
|
||||
|
||||
public:
|
||||
CtrEncryptedBacking(crypto::KeyStore::Key128 ctr, crypto::KeyStore::Key128 key, std::shared_ptr<Backing> backing, size_t baseOffset);
|
||||
|
||||
size_t Read(span<u8> output, size_t offset = 0) override;
|
||||
};
|
||||
}
|
||||
|
@ -11,6 +11,23 @@ namespace skyline::vfs {
|
||||
* @brief The FileSystem class represents an abstract filesystem with child files and folders
|
||||
*/
|
||||
class FileSystem {
|
||||
protected:
|
||||
virtual bool CreateFileImpl(const std::string &path, size_t size) {
|
||||
throw exception("This filesystem does not support creating files");
|
||||
};
|
||||
|
||||
virtual bool CreateDirectoryImpl(const std::string &path, bool parents) {
|
||||
throw exception("This filesystem does not support creating directories");
|
||||
};
|
||||
|
||||
virtual std::shared_ptr<Backing> OpenFileImpl(const std::string &path, Backing::Mode mode) = 0;
|
||||
|
||||
virtual std::optional<Directory::EntryType> GetEntryTypeImpl(const std::string &path) = 0;
|
||||
|
||||
virtual std::shared_ptr<Directory> OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) {
|
||||
throw exception("This filesystem does not support opening directories");
|
||||
};
|
||||
|
||||
public:
|
||||
FileSystem() = default;
|
||||
|
||||
@ -27,8 +44,8 @@ namespace skyline::vfs {
|
||||
* @param size The size of the file to create
|
||||
* @return Whether creating the file succeeded
|
||||
*/
|
||||
virtual bool CreateFile(const std::string &path, size_t size) {
|
||||
throw exception("This filesystem does not support creating files");
|
||||
bool CreateFile(const std::string &path, size_t size) {
|
||||
return CreateFileImpl(path, size);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -37,8 +54,8 @@ namespace skyline::vfs {
|
||||
* @param parents Whether all parent directories in the given path should be created
|
||||
* @return Whether creating the directory succeeded
|
||||
*/
|
||||
virtual bool CreateDirectory(const std::string &path, bool parents) {
|
||||
throw exception("This filesystem does not support creating directories");
|
||||
bool CreateDirectory(const std::string &path, bool parents) {
|
||||
return CreateDirectoryImpl(path, parents);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -47,14 +64,21 @@ namespace skyline::vfs {
|
||||
* @param mode The mode to open the file with
|
||||
* @return A shared pointer to a Backing object of the file
|
||||
*/
|
||||
virtual std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false}) = 0;
|
||||
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false}) {
|
||||
if (!mode.write && !mode.read)
|
||||
throw exception("Cannot open a file with a mode that is neither readable nor writable");
|
||||
|
||||
return OpenFileImpl(path, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the type of the entry given by path
|
||||
* @param path The path to the entry
|
||||
* @return The type of the entry, if present
|
||||
*/
|
||||
virtual std::optional<Directory::EntryType> GetEntryType(const std::string &path) = 0;
|
||||
std::optional<Directory::EntryType> GetEntryType(const std::string &path) {
|
||||
return GetEntryTypeImpl(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a given file exists in a filesystem
|
||||
@ -82,8 +106,11 @@ namespace skyline::vfs {
|
||||
* @param listMode The list mode for the directory
|
||||
* @return A shared pointer to a Directory object of the directory
|
||||
*/
|
||||
virtual std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode) {
|
||||
throw exception("This filesystem does not support opening directories");
|
||||
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode = {true, true}) {
|
||||
if (!listMode.raw)
|
||||
throw exception("Cannot open a directory with an empty listMode");
|
||||
|
||||
return OpenDirectoryImpl(path, listMode);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -20,10 +20,7 @@ namespace skyline::vfs {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
size_t OsBacking::Read(span<u8> output, size_t offset) {
|
||||
if (!mode.read)
|
||||
throw exception("Attempting to read a backing that is not readable");
|
||||
|
||||
size_t OsBacking::ReadImpl(span<u8> output, size_t offset) {
|
||||
auto ret{pread64(fd, output.data(), output.size(), offset)};
|
||||
if (ret < 0)
|
||||
throw exception("Failed to read from fd: {}", strerror(errno));
|
||||
@ -31,10 +28,7 @@ namespace skyline::vfs {
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
size_t OsBacking::Write(span<u8> input, size_t offset) {
|
||||
if (!mode.write)
|
||||
throw exception("Attempting to write to a backing that is not writable");
|
||||
|
||||
size_t OsBacking::WriteImpl(span<u8> input, size_t offset) {
|
||||
auto ret{pwrite64(fd, input.data(), input.size(), offset)};
|
||||
if (ret < 0)
|
||||
throw exception("Failed to write to fd: {}", strerror(errno));
|
||||
@ -42,7 +36,7 @@ namespace skyline::vfs {
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
void OsBacking::Resize(size_t pSize) {
|
||||
void OsBacking::ResizeImpl(size_t pSize) {
|
||||
int ret{ftruncate(fd, pSize)};
|
||||
if (ret < 0)
|
||||
throw exception("Failed to resize file: {}", strerror(errno));
|
||||
|
@ -14,6 +14,13 @@ namespace skyline::vfs {
|
||||
int fd; //!< An FD to the backing
|
||||
bool closable; //!< Whether the FD can be closed when the backing is destroyed
|
||||
|
||||
protected:
|
||||
size_t ReadImpl(span<u8> output, size_t offset) override;
|
||||
|
||||
size_t WriteImpl(span<u8> input, size_t offset) override;
|
||||
|
||||
void ResizeImpl(size_t size) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param fd The file descriptor of the backing
|
||||
@ -21,11 +28,5 @@ namespace skyline::vfs {
|
||||
OsBacking(int fd, bool closable = false, Mode = {true, false, false});
|
||||
|
||||
~OsBacking();
|
||||
|
||||
size_t Read(span<u8> output, size_t offset = 0);
|
||||
|
||||
size_t Write(span<u8> input, size_t offset = 0);
|
||||
|
||||
void Resize(size_t size);
|
||||
};
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace skyline::vfs {
|
||||
throw exception("Error creating the OS filesystem backing directory");
|
||||
}
|
||||
|
||||
bool OsFileSystem::CreateFile(const std::string &path, size_t size) {
|
||||
bool OsFileSystem::CreateFileImpl(const std::string &path, size_t size) {
|
||||
auto fullPath{basePath + path};
|
||||
|
||||
// Create a directory that will hold the file
|
||||
@ -38,7 +38,7 @@ namespace skyline::vfs {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OsFileSystem::CreateDirectory(const std::string &path, bool parents) {
|
||||
bool OsFileSystem::CreateDirectoryImpl(const std::string &path, bool parents) {
|
||||
if (!parents) {
|
||||
int ret{mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)};
|
||||
return ret == 0 || errno == EEXIST;
|
||||
@ -58,10 +58,7 @@ namespace skyline::vfs {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<Backing> OsFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
|
||||
if (!(mode.read || mode.write))
|
||||
throw exception("Cannot open a file that is neither readable or writable");
|
||||
|
||||
std::shared_ptr<Backing> OsFileSystem::OpenFileImpl(const std::string &path, Backing::Mode mode) {
|
||||
int fd{open((basePath + path).c_str(), (mode.read && mode.write) ? O_RDWR : (mode.write ? O_WRONLY : O_RDONLY))};
|
||||
if (fd < 0)
|
||||
throw exception("Failed to open file at '{}': {}", path, strerror(errno));
|
||||
@ -69,7 +66,7 @@ namespace skyline::vfs {
|
||||
return std::make_shared<OsBacking>(fd, true, mode);
|
||||
}
|
||||
|
||||
std::optional<Directory::EntryType> OsFileSystem::GetEntryType(const std::string &path) {
|
||||
std::optional<Directory::EntryType> OsFileSystem::GetEntryTypeImpl(const std::string &path) {
|
||||
auto fullPath{basePath + path};
|
||||
|
||||
auto directory{opendir(fullPath.c_str())};
|
||||
@ -84,7 +81,7 @@ namespace skyline::vfs {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<Directory> OsFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
|
||||
std::shared_ptr<Directory> OsFileSystem::OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) {
|
||||
return std::make_shared<OsFileSystemDirectory>(basePath + path, listMode);
|
||||
}
|
||||
|
||||
|
@ -13,18 +13,19 @@ namespace skyline::vfs {
|
||||
private:
|
||||
std::string basePath; //!< The base path for filesystem operations
|
||||
|
||||
protected:
|
||||
bool CreateFileImpl(const std::string &path, size_t size) override;
|
||||
|
||||
bool CreateDirectoryImpl(const std::string &path, bool parents) override;
|
||||
|
||||
std::shared_ptr<Backing> OpenFileImpl(const std::string &path, Backing::Mode mode) override;
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryTypeImpl(const std::string &path) override;
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) override;
|
||||
|
||||
public:
|
||||
OsFileSystem(const std::string &basePath);
|
||||
|
||||
bool CreateFile(const std::string &path, size_t size);
|
||||
|
||||
bool CreateDirectory(const std::string &path, bool parents);
|
||||
|
||||
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,7 +31,7 @@ namespace skyline::vfs {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Backing> PartitionFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
|
||||
std::shared_ptr<Backing> PartitionFileSystem::OpenFileImpl(const std::string &path, Backing::Mode mode) {
|
||||
try {
|
||||
auto &entry{fileMap.at(path)};
|
||||
return std::make_shared<RegionBacking>(backing, fileDataOffset + entry.offset, entry.size, mode);
|
||||
@ -40,16 +40,16 @@ namespace skyline::vfs {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Directory::EntryType> PartitionFileSystem::GetEntryType(const std::string &path) {
|
||||
std::optional<Directory::EntryType> PartitionFileSystem::GetEntryTypeImpl(const std::string &path) {
|
||||
if (fileMap.count(path))
|
||||
return Directory::EntryType::File;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<Directory> PartitionFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
|
||||
std::shared_ptr<Directory> PartitionFileSystem::OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) {
|
||||
// PFS doesn't have directories
|
||||
if (path != "")
|
||||
if (!path.empty())
|
||||
return nullptr;
|
||||
|
||||
std::vector<Directory::Entry> fileList;
|
||||
|
@ -39,14 +39,15 @@ namespace skyline::vfs {
|
||||
std::shared_ptr<Backing> backing; //!< The backing file of the filesystem
|
||||
std::unordered_map<std::string, PartitionFileEntry> fileMap; //!< A map that maps file names to their corresponding entry
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Backing> OpenFileImpl(const std::string &path, Backing::Mode mode) override;
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryTypeImpl(const std::string &path) override;
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) override;
|
||||
|
||||
public:
|
||||
PartitionFileSystem(const std::shared_ptr<Backing> &backing);
|
||||
|
||||
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -14,20 +14,20 @@ namespace skyline::vfs {
|
||||
std::shared_ptr<vfs::Backing> backing; //!< The parent backing
|
||||
size_t baseOffset; //!< The offset of the region in the parent backing
|
||||
|
||||
protected:
|
||||
size_t ReadImpl(span <u8> output, size_t offset) override {
|
||||
return backing->Read(output, baseOffset + offset);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param file The backing to create the RegionBacking from
|
||||
* @param offset The offset of the region start within the parent backing
|
||||
* @param size The size of the region in the parent backing
|
||||
*/
|
||||
RegionBacking(const std::shared_ptr<vfs::Backing> &backing, size_t offset, size_t size, Mode mode = {true, false, false}) : Backing(mode, size), backing(backing), baseOffset(offset) {};
|
||||
|
||||
size_t Read(span <u8> output, size_t offset = 0) {
|
||||
if (!mode.read)
|
||||
throw exception("Attempting to read a backing that is not readable");
|
||||
if (size - offset < output.size())
|
||||
throw exception("Trying to read past the end of a region backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", output.size(), size, offset);
|
||||
return backing->Read(output, baseOffset + offset);
|
||||
}
|
||||
RegionBacking(const std::shared_ptr<vfs::Backing> &backing, size_t offset, size_t size, Mode mode = {true, false, false}) : Backing(mode, size), backing(backing), baseOffset(offset) {
|
||||
if (mode.write || mode.append)
|
||||
throw exception("Cannot open a RegionBacking as writable");
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace skyline::vfs {
|
||||
TraverseDirectory(entry.siblingOffset, path);
|
||||
}
|
||||
|
||||
std::shared_ptr<Backing> RomFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
|
||||
std::shared_ptr<Backing> RomFileSystem::OpenFileImpl(const std::string &path, Backing::Mode mode) {
|
||||
try {
|
||||
const auto &entry{fileMap.at(path)};
|
||||
return std::make_shared<RegionBacking>(backing, header.dataOffset + entry.offset, entry.size, mode);
|
||||
@ -58,7 +58,7 @@ namespace skyline::vfs {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Directory::EntryType> RomFileSystem::GetEntryType(const std::string &path) {
|
||||
std::optional<Directory::EntryType> RomFileSystem::GetEntryTypeImpl(const std::string &path) {
|
||||
if (fileMap.count(path))
|
||||
return Directory::EntryType::File;
|
||||
else if (directoryMap.count(path))
|
||||
@ -67,7 +67,7 @@ namespace skyline::vfs {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<Directory> RomFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
|
||||
std::shared_ptr<Directory> RomFileSystem::OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) {
|
||||
try {
|
||||
auto &entry{directoryMap.at(path)};
|
||||
return std::make_shared<RomFileSystemDirectory>(backing, header, entry, listMode);
|
||||
|
@ -32,6 +32,13 @@ namespace skyline {
|
||||
*/
|
||||
void TraverseDirectory(u32 offset, const std::string &path);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Backing> OpenFileImpl(const std::string &path, Backing::Mode mode) override;
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryTypeImpl(const std::string &path) override;
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectoryImpl(const std::string &path, Directory::ListMode listMode) override;
|
||||
|
||||
public:
|
||||
struct RomFsHeader {
|
||||
u64 headerSize; //!< The size of the header
|
||||
@ -69,12 +76,6 @@ namespace skyline {
|
||||
std::unordered_map<std::string, RomFsDirectoryEntry> directoryMap; //!< A map that maps directory names to their corresponding entry
|
||||
|
||||
RomFileSystem(std::shared_ptr<Backing> backing);
|
||||
|
||||
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
|
||||
|
||||
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
|
||||
|
||||
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user