nostalgia/deps/ox/src/ox/fs/filesystem/filesystem.hpp

355 lines
11 KiB
C++

/*
* Copyright 2015 - 2018 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/fs/filestore/filestoretemplate.hpp>
#include <ox/fs/filesystem/types.hpp>
#include "directory.hpp"
namespace ox {
class FileSystem {
public:
virtual ~FileSystem() = default;
virtual ox::Error mkdir(const char *path, bool recursive = false) = 0;
/**
* Moves an entry from one directory to another.
* @param src the path to the file
* @param dest the path of the destination directory
*/
virtual ox::Error move(const char *src, const char *dest) = 0;
virtual ox::Error read(const char *path, void *buffer, std::size_t buffSize) = 0;
virtual ox::Error read(uint64_t inode, void *buffer, std::size_t size) = 0;
virtual ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) = 0;
virtual ox::Error remove(const char *path, bool recursive = false) = 0;
virtual ox::Error resize(uint64_t size, void *buffer = nullptr) = 0;
virtual ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
virtual ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
virtual ox::ValErr<FileStat> stat(uint64_t inode) = 0;
virtual ox::ValErr<FileStat> stat(const char *path) = 0;
virtual uint64_t spaceNeeded(uint64_t size) = 0;
virtual uint64_t available() = 0;
virtual uint64_t size() const = 0;
virtual uint8_t *buff() = 0;
virtual ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) = 0;
virtual bool valid() const = 0;
};
/**
* FileSystemTemplate used to create file system that wraps around a FileStore,
* taking an inode size and a directory type as parameters.
*
* Note: Directory parameter must have a default constructor.
*/
template<typename FileStore, typename Directory>
class FileSystemTemplate: public FileSystem {
private:
static constexpr auto InodeFsData = 2;
struct __attribute__((packed)) FileSystemData {
LittleEndian<typename FileStore::InodeId_t> rootDirInode;
};
FileStore m_fs;
public:
FileSystemTemplate() = default;
FileSystemTemplate(FileStore fs);
~FileSystemTemplate();
[[nodiscard]] static ox::Error format(void *buff, uint64_t buffSize);
[[nodiscard]] ox::Error mkdir(const char *path, bool recursive = false) override;
[[nodiscard]] ox::Error move(const char *src, const char *dest) override;
[[nodiscard]] ox::Error read(const char *path, void *buffer, std::size_t buffSize) override;
[[nodiscard]] ox::Error read(uint64_t inode, void *buffer, std::size_t size) override;
[[nodiscard]] ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) override;
template<typename F>
[[nodiscard]] ox::Error ls(const char *dir, F cb);
[[nodiscard]] ox::Error remove(const char *path, bool recursive = false) override;
[[nodiscard]] ox::Error resize(uint64_t size, void *buffer = nullptr) override;
[[nodiscard]] ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
[[nodiscard]] ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
[[nodiscard]] ox::ValErr<FileStat> stat(uint64_t inode) override;
[[nodiscard]] ox::ValErr<FileStat> stat(const char *path) override;
uint64_t spaceNeeded(uint64_t size) override;
uint64_t available() override;
uint64_t size() const override;
uint8_t *buff() override;
[[nodiscard]] ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) override;
bool valid() const override;
private:
[[nodiscard]] ValErr<FileSystemData> fileSystemData() const noexcept;
/**
* Finds the inode ID at the given path.
*/
[[nodiscard]] ValErr<uint64_t> find(const char *path) const noexcept;
[[nodiscard]] ValErr<Directory> rootDir() const noexcept;
};
template<typename FileStore, typename Directory>
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(FileStore fs) {
m_fs = fs;
}
template<typename FileStore, typename Directory>
FileSystemTemplate<FileStore, Directory>::~FileSystemTemplate() {
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) {
oxReturnError(FileStore::format(buff, buffSize));
FileStore fs(buff, buffSize);
constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2;
Directory rootDir(fs, rootDirInode);
oxReturnError(rootDir.init());
FileSystemData fd;
fd.rootDirInode = rootDirInode;
oxTrace("ox::fs::FileSystemTemplate::format") << "rootDirInode:" << fd.rootDirInode;
oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd)));
if (fs.read(fd.rootDirInode).valid()) {
oxTrace("ox::fs::FileSystemTemplate::format::error") << "FileSystemTemplate::format did not correctly create root directory";
}
return OxError(0);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::mkdir(const char *path, bool recursive) {
oxTrace("ox::fs::FileSystemTemplate::mkdir") << "path:" << path << "recursive:" << recursive;
auto rootDir = this->rootDir();
oxReturnError(rootDir.error);
return rootDir.value.mkdir(path, recursive);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char *dest) {
auto fd = fileSystemData();
oxReturnError(fd.error);
Directory rootDir(m_fs, fd.value.rootDirInode);
auto inode = rootDir.find(src);
oxReturnError(inode.error);
oxReturnError(rootDir.write(dest, inode));
oxReturnError(rootDir.remove(src));
return OxError(0);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buffer, std::size_t buffSize) {
auto fd = fileSystemData();
oxReturnError(fd.error);
Directory rootDir(m_fs, fd.value.rootDirInode);
auto inode = rootDir.find(path);
oxReturnError(inode.error);
return read(inode, buffer, buffSize);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, void *buffer, std::size_t buffSize) {
return m_fs.read(inode, buffer, buffSize);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) {
return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size);
}
template<typename FileStore, typename Directory>
template<typename F>
ox::Error FileSystemTemplate<FileStore, Directory>::ls(const char *path, F cb) {
auto s = stat(path);
oxReturnError(s.error);
Directory dir(m_fs, s.value.inode);
return dir.ls(cb);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) {
auto fd = fileSystemData();
oxReturnError(fd.error);
Directory rootDir(m_fs, fd.value.rootDirInode);
auto inode = rootDir.find(path);
oxReturnError(inode.error);
auto st = stat(inode);
oxReturnError(st.error);
if (st.value.fileType == FileType_NormalFile || recursive) {
if (auto err = rootDir.remove(path)) {
// removal failed, try putting the index back
oxLogError(rootDir.write(path, inode));
return err;
}
} else {
oxTrace("FileSystemTemplate::remove::fail") << "Tried to remove directory without recursive setting.";
return OxError(1);
}
return OxError(0);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) {
oxReturnError(m_fs.resize(size, buffer));
return OxError(0);
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
auto inode = find(path);
if (inode.error) {
inode.value = m_fs.generateInodeId();
}
auto rootDir = this->rootDir();
oxReturnError(rootDir.error);
oxReturnError(rootDir.value.write(path, inode));
oxReturnError(write(inode, buffer, size, fileType));
return 0;
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType) {
return m_fs.write(inode, buffer, size, fileType);
}
template<typename FileStore, typename Directory>
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode) {
auto s = m_fs.stat(inode);
FileStat out;
out.inode = s.value.inode;
out.links = s.value.links;
out.size = s.value.size;
out.fileType = s.value.fileType;
return {out, s.error};
}
template<typename FileStore, typename Directory>
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(const char *path) {
auto inode = find(path);
if (inode.error) {
return {{}, inode.error};
}
return stat(inode.value);
}
template<typename FileStore, typename Directory>
uint64_t FileSystemTemplate<FileStore, Directory>::spaceNeeded(uint64_t size) {
return m_fs.spaceNeeded(size);
}
template<typename FileStore, typename Directory>
uint64_t FileSystemTemplate<FileStore, Directory>::available() {
return m_fs.available();
}
template<typename FileStore, typename Directory>
uint64_t FileSystemTemplate<FileStore, Directory>::size() const {
return m_fs.size();
}
template<typename FileStore, typename Directory>
uint8_t *FileSystemTemplate<FileStore, Directory>::buff() {
return m_fs.buff();
}
template<typename FileStore, typename Directory>
ox::Error FileSystemTemplate<FileStore, Directory>::walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) {
return m_fs.walk(cb);
}
template<typename FileStore, typename Directory>
bool FileSystemTemplate<FileStore, Directory>::valid() const {
return m_fs.valid();
}
template<typename FileStore, typename Directory>
ValErr<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSystemTemplate<FileStore, Directory>::fileSystemData() const noexcept {
FileSystemData fd;
auto err = m_fs.read(InodeFsData, &fd, sizeof(fd));
if (err != 0) {
return {fd, err};
}
return fd;
}
template<typename FileStore, typename Directory>
ValErr<uint64_t> FileSystemTemplate<FileStore, Directory>::find(const char *path) const noexcept {
auto fd = fileSystemData();
if (fd.error) {
return {0, fd.error};
}
Directory rootDir(m_fs, fd.value.rootDirInode);
auto inode = rootDir.find(path);
if (inode.error) {
return {0, inode.error};
}
return inode.value;
}
template<typename FileStore, typename Directory>
ValErr<Directory> FileSystemTemplate<FileStore, Directory>::rootDir() const noexcept {
auto fd = fileSystemData();
if (fd.error) {
return {{}, fd.error};
}
return Directory(m_fs, fd.value.rootDirInode);
}
extern template class FileSystemTemplate<FileStore16, Directory16>;
extern template class FileSystemTemplate<FileStore32, Directory32>;
using FileSystem16 = FileSystemTemplate<FileStore16, Directory16>;
using FileSystem32 = FileSystemTemplate<FileStore32, Directory32>;
}