replaced my own vfs library by an external better vfs project

This commit is contained in:
faraphel 2024-08-21 18:20:29 +02:00
parent fa9d8b5d86
commit a5b4723ac1
14 changed files with 23 additions and 274 deletions

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "external/wit"]
path = external/wit
url = https://git.faraphel.fr/Atlas/library-wit
[submodule "external/vfspp"]
path = external/vfspp
url = https://github.com/nextgeniuspro/vfspp

View file

@ -2,19 +2,10 @@ cmake_minimum_required(VERSION 3.28)
project(Atlas-Launcher LANGUAGES CXX)
# set(CMAKE_AUTOMOC ON)
# set(CMAKE_AUTOUIC ON)
# set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# find_package(Qt6 REQUIRED COMPONENTS
# Core
# Gui
# Widgets
# )
add_executable(Atlas-Launcher
source/main.cpp
@ -31,17 +22,12 @@ target_include_directories(Atlas-Launcher PRIVATE
target_link_libraries(Atlas-Launcher PRIVATE
# Libraries
angelscript
vfspp
# Tools
VFS
SZS
# Qt Framework
# Qt::Core
# Qt::Gui
# Qt::Widgets
# SZS
)
add_subdirectory(external/angelscript/angelscript/projects/cmake)
add_subdirectory(external/vfs)
add_subdirectory(external/szs)
add_subdirectory(external/vfspp)
# add_subdirectory(external/szs)

View file

@ -9,3 +9,5 @@ Mario Kart Wii mods launcher
AngelScript - The C/C++ like sandboxed script language allowing for the
mods developer to write efficient and low-level code that can be trusted
by a user.
vfspp - A C++ library that implement a virtual file system.

View file

@ -1,18 +0,0 @@
cmake_minimum_required(VERSION 3.28)
project(VFS LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(VFS STATIC
source/VirtualFileSystem.cpp
source/exception/FileNotFoundException.cpp
include/exception/FileNotFoundException.hpp
)
target_include_directories(VFS PUBLIC
include/
)
add_subdirectory(tests)

View file

@ -1,10 +0,0 @@
# Restricted Virtual File System
This is a micro-library used to create a virtual file system to restrict access
to the host file system while still being able to mount directories that can be accessed.
As of right now, this is an incredibly simple implementation of this system that
work by mapping virtual directory path to a corresponding real directory path, replacing
them while resolving the path and reject all others paths that have not been mounted
to avoid access to other files.
It does not emulate a real file system nor allow control over permissions of the files.

View file

@ -1,49 +0,0 @@
#pragma once
#include <filesystem>
namespace vfs {
/**
* Represent a virtual file system.
* Real directory can be mounted to safely interact with the real file system.
*/
class VirtualFileSystem {
public:
explicit VirtualFileSystem();
~VirtualFileSystem();
std::filesystem::path getWorkingDirectory() const;
void setWorkingDirectory(const std::filesystem::path& virtualPath);
/**
* Mount a real directory into the virtual file system
* @param sourcePath the path to the directory in the real file system
* @param virtualDestinationPath the path to the directory in the virtual file system
*/
void mount(const std::filesystem::path& sourcePath, const std::filesystem::path& virtualDestinationPath) const;
/**
* Unmount a directory from the virtual file system
* @param virtualPath the path to the directory in the virtual file system
*/
void unmount(const std::filesystem::path& virtualPath) const;
/**
* Get the real path on the host file system from its virtual path
* @param virtualPath the virtual path
* @return the real path
*/
std::filesystem::path resolve(const std::filesystem::path& virtualPath) const;
private:
/// the internal temporary directory
std::filesystem::path rootDirectoryPath;
/// the virtual current working directory. Always relative.
std::filesystem::path virtualWorkingDirectory;
};
}

View file

@ -1,14 +0,0 @@
#pragma once
#include <stdexcept>
#include <filesystem>
namespace vfs::exception {
class FileNotFoundException final : public std::runtime_error {
public:
explicit FileNotFoundException(const std::filesystem::path& path);
};
}

View file

@ -1,88 +0,0 @@
#include "VirtualFileSystem.hpp"
#include <iostream>
#include "exception/FileNotFoundException.hpp"
namespace vfs {
VirtualFileSystem::VirtualFileSystem() {
// create the temporary directory
char temporaryDirectoryPathTemplate[] = "/tmp/vfs-XXXXXX";
const char* temporaryDirectoryPath = mkdtemp(temporaryDirectoryPathTemplate);
// check for any issue while creating the directory
if (temporaryDirectoryPath == nullptr)
throw std::runtime_error("Could not create a temporary directory for the virtual file system.");
// store it as a standard path
this->rootDirectoryPath = std::filesystem::path(temporaryDirectoryPath);
// set the virtual working directory at the root
this->setWorkingDirectory("./");
}
VirtualFileSystem::~VirtualFileSystem() {
// delete everything in the temporary directory
std::error_code error;
remove_all(this->rootDirectoryPath, error);
// check for any error
if (error)
std::cerr << "Could not clean the VFS : " + error.message() << std::endl;
}
std::filesystem::path VirtualFileSystem::getWorkingDirectory() const {
return this->virtualWorkingDirectory;
}
void VirtualFileSystem::setWorkingDirectory(const std::filesystem::path& virtualPath) {
if (!virtualPath.is_relative())
throw std::runtime_error("The working directory need to be a relative path (for the virtual file system root).");
// set the new working directory
this->virtualWorkingDirectory = virtualPath;
}
void VirtualFileSystem::mount(const std::filesystem::path& sourcePath, const std::filesystem::path& virtualDestinationPath) const {
// create a symlink from the directory to our temporary directory
const std::filesystem::path realDestinationPath = this->resolve(virtualDestinationPath);
// create a symlink to the directory to mount in our virtual file system directory
std::error_code error;
create_directory_symlink(absolute(sourcePath), realDestinationPath, error);
// check for any error while creating the symlink
if (error)
throw std::runtime_error("Could not mount the directory in the virtual file system. Reason: " + error.message());
}
void VirtualFileSystem::unmount(const std::filesystem::path& virtualPath) const {
// get the real path of the given virtual path
const std::filesystem::path realPath = this->resolve(virtualPath);
// check if it is a symbolic link
if (!is_symlink(realPath))
throw std::runtime_error("Not a mounted directory !");
// delete the symlink
remove(realPath);
}
std::filesystem::path VirtualFileSystem::resolve(const std::filesystem::path& virtualPath) const {
// normalize the path by solving the special symbols first.
std::filesystem::path normalizedVirtualPath = virtualPath.lexically_normal();
if (virtualPath.is_relative()) {
// if the path is relative, prepend the working directory
normalizedVirtualPath = this->virtualWorkingDirectory / normalizedVirtualPath;
} else {
// convert it into a relative path for the root
normalizedVirtualPath = relative(normalizedVirtualPath.lexically_normal(), "/");
}
// get the real path by prepending the real root directory path
return this->rootDirectoryPath / normalizedVirtualPath;
}
}

View file

@ -1,9 +0,0 @@
#include "exception/FileNotFoundException.hpp"
namespace vfs::exception {
FileNotFoundException::FileNotFoundException(const std::filesystem::path& path) :
std::runtime_error("Could not find the file : " + path.string()) {}
}

View file

@ -1,25 +0,0 @@
cmake_minimum_required(VERSION 3.28)
project(Test-VFS LANGUAGES CXX)
enable_testing()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Test executable
add_executable(Test-VFS
test-restriction.cpp
)
# Libraries
target_link_libraries(Test-VFS PRIVATE
# Code to test
VFS
)
# Copy the assets to run the tests
file(COPY _assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
# Test
add_test(NAME Test-VFS COMMAND Test-VFS)

View file

@ -1 +0,0 @@
This is a simple text file.

View file

@ -1,38 +0,0 @@
#include <filesystem>
#include <iostream>
#include <VirtualFileSystem.hpp>
int main() {
// TODO(Faraphel): use a real unit test framework ?
// create a basic virtual file system
vfs::VirtualFileSystem fs;
// mount a directory into our system
fs.mount("_assets", "/assets");
// TEST: check if a file outside of an allowed mounted directory can't be resolved
try {
const std::filesystem::path path = fs.resolve("/content.txt");
throw std::runtime_error("[Test 1] - Impossible path should not be resolved !");
} catch (const std::runtime_error& exception) {}
// TEST: check if a file in a mounted directory can be resolved
try {
const std::filesystem::path path = fs.resolve("/assets/content.txt");
// auto file = QFile(path);
// file.open(QIODeviceBase::Text | QIODevice::ReadOnly);
// std::cout << file.readAll().toStdString() << std::endl;
} catch (const std::runtime_error& exception) {
throw std::runtime_error("[Test 2] - Path could not be accessed !");
}
// TEST: cannot bypass security with the ".." parent directory syntax
try {
// const std::filesystem::path path = fs.resolve("/assets/../content.txt");
// throw std::runtime_error("[Test 3] - Resolved impossible path");
} catch (const std::runtime_error& exception) {
}
}

1
external/vfspp vendored Submodule

@ -0,0 +1 @@
Subproject commit f22a0b23827e0ff3faa8379dc0bad450db9ac17a

View file

@ -1,9 +1,11 @@
#include <iostream>
#include <memory>
#include "angelscript.h"
#include "scriptstdstring/scriptstdstring.h"
#include "scriptbuilder/scriptbuilder.h"
#include <vfspp/VirtualFileSystem.hpp>
#include <vfspp/MemoryFileSystem.hpp>
#include <angelscript.h>
#include <scriptstdstring/scriptstdstring.h>
#include <scriptbuilder/scriptbuilder.h>
void print(const std::string& in) {
@ -14,6 +16,13 @@ void print(const std::string& in) {
int main(int argc, char* argv[]) {
int error;
// prepare a virtual file system
auto fileSystem = std::make_unique<vfspp::VirtualFileSystem>();
auto fileSystemTmp = std::make_shared<vfspp::MemoryFileSystem>();
fileSystemTmp->Initialize();
fileSystem->AddFileSystem("/tmp", fileSystemTmp);
// engine
asIScriptEngine* engine = asCreateScriptEngine();
if (engine == nullptr)