replaced the virtual file system back by the original custom one
This commit is contained in:
parent
d9ae04886f
commit
64c247ba6f
22 changed files with 373 additions and 31 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -7,6 +7,3 @@
|
|||
[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
|
||||
|
|
|
@ -23,28 +23,34 @@ add_executable(Atlas-Launcher
|
|||
|
||||
# Source
|
||||
source/main.cpp
|
||||
source/script/module/debug/load.cpp
|
||||
source/script/module/debug/load.hpp
|
||||
source/script/module/debug/_load.cpp
|
||||
source/script/module/debug/_load.hpp
|
||||
source/script/module/debug/log.cpp
|
||||
source/script/module/debug/log.hpp
|
||||
source/script/engine/Engine.cpp
|
||||
source/script/engine/Engine.hpp
|
||||
source/script/module/filesystem/_load.cpp
|
||||
source/script/module/filesystem/_load.hpp
|
||||
source/script/module/filesystem/Path.cpp
|
||||
source/script/module/filesystem/Path.hpp
|
||||
)
|
||||
target_include_directories(Atlas-Launcher PRIVATE
|
||||
source/
|
||||
|
||||
# AngelScript
|
||||
external/angelscript/add_on
|
||||
|
||||
# Source
|
||||
source/
|
||||
)
|
||||
target_link_libraries(Atlas-Launcher PRIVATE
|
||||
# Libraries
|
||||
angelscript
|
||||
vfspp
|
||||
|
||||
# Tools
|
||||
# SZS
|
||||
VFS
|
||||
)
|
||||
|
||||
|
||||
# Copy the mods
|
||||
file(COPY .mods DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_subdirectory(external/angelscript/angelscript/projects/cmake)
|
||||
add_subdirectory(external/vfspp)
|
||||
add_subdirectory(external/vfs)
|
||||
# add_subdirectory(external/szs)
|
||||
|
|
18
external/vfs/CMakeLists.txt
vendored
Normal file
18
external/vfs/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
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)
|
10
external/vfs/README.md
vendored
Normal file
10
external/vfs/README.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
# 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.
|
49
external/vfs/include/VirtualFileSystem.hpp
vendored
Normal file
49
external/vfs/include/VirtualFileSystem.hpp
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
#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;
|
||||
};
|
||||
|
||||
}
|
14
external/vfs/include/exception/FileNotFoundException.hpp
vendored
Normal file
14
external/vfs/include/exception/FileNotFoundException.hpp
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
namespace vfs::exception {
|
||||
|
||||
class FileNotFoundException final : public std::runtime_error {
|
||||
public:
|
||||
explicit FileNotFoundException(const std::filesystem::path& path);
|
||||
};
|
||||
|
||||
}
|
88
external/vfs/source/VirtualFileSystem.cpp
vendored
Normal file
88
external/vfs/source/VirtualFileSystem.cpp
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
|
||||
}
|
9
external/vfs/source/exception/FileNotFoundException.cpp
vendored
Normal file
9
external/vfs/source/exception/FileNotFoundException.cpp
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "exception/FileNotFoundException.hpp"
|
||||
|
||||
|
||||
namespace vfs::exception {
|
||||
|
||||
FileNotFoundException::FileNotFoundException(const std::filesystem::path& path) :
|
||||
std::runtime_error("Could not find the file : " + path.string()) {}
|
||||
|
||||
}
|
25
external/vfs/tests/CMakeLists.txt
vendored
Normal file
25
external/vfs/tests/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
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)
|
1
external/vfs/tests/_assets/content.txt
vendored
Normal file
1
external/vfs/tests/_assets/content.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
This is a simple text file.
|
38
external/vfs/tests/test-restriction.cpp
vendored
Normal file
38
external/vfs/tests/test-restriction.cpp
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
#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
1
external/vfspp
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit f22a0b23827e0ff3faa8379dc0bad450db9ac17a
|
|
@ -1,16 +1,16 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include <vfspp/VirtualFileSystem.hpp>
|
||||
#include <vfspp/MemoryFileSystem.hpp>
|
||||
#include <angelscript.h>
|
||||
#include <VirtualFileSystem.hpp>
|
||||
#include <scriptbuilder/scriptbuilder.h>
|
||||
|
||||
#include "script/engine/Engine.hpp"
|
||||
#include "script/module/debug/load.hpp"
|
||||
#include "script/module/debug/_load.hpp"
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main_AngelScript(int argc, char* argv[]) {
|
||||
int error;
|
||||
|
||||
// engine
|
||||
|
@ -64,3 +64,29 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
return error;
|
||||
}
|
||||
|
||||
int main_vfspp(int argc, char* argv[]) {
|
||||
int error;
|
||||
|
||||
// create a virtual file system
|
||||
const auto vfs = std::make_unique<vfs::VirtualFileSystem>();
|
||||
vfs->mount(".mods/Atlas/assets", "assets");
|
||||
|
||||
// get an example file
|
||||
auto file = vfs->resolve("assets/message.txt");
|
||||
|
||||
// open and read it
|
||||
auto stream = std::ifstream(file);
|
||||
if (!stream.is_open())
|
||||
throw std::runtime_error("Could not open the file.");
|
||||
|
||||
std::string line;
|
||||
std::getline(stream, line);
|
||||
std::cout << line;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
main_vfspp(argc, argv);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <angelscript.h>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <datetime/datetime.h>
|
||||
#include <scriptany/scriptany.h>
|
||||
|
@ -12,7 +13,6 @@
|
|||
#include <scripthandle/scripthandle.h>
|
||||
#include <scripthelper/scripthelper.h>
|
||||
#include <scriptmath/scriptmath.h>
|
||||
#include <vfspp/MemoryFileSystem.hpp>
|
||||
#include <weakref/weakref.h>
|
||||
|
||||
|
||||
|
@ -38,15 +38,6 @@ Engine::Engine() {
|
|||
RegisterScriptWeakRef(this->asEngine);
|
||||
RegisterExceptionRoutines(this->asEngine);
|
||||
RegisterScriptMath(this->asEngine);
|
||||
|
||||
// initialise the file system
|
||||
this->fileSystem = std::make_unique<vfspp::VirtualFileSystem>();
|
||||
|
||||
// TODO(Faraphel): is the memory fs
|
||||
auto memoryFileSystem = std::make_unique<vfspp::MemoryFileSystem>();
|
||||
memoryFileSystem->Initialize();
|
||||
|
||||
this->fileSystem->AddFileSystem("/tmp", std::move(memoryFileSystem));
|
||||
}
|
||||
|
||||
void Engine::asCallback(const asSMessageInfo *message, void *args) {
|
||||
|
@ -84,7 +75,7 @@ Engine::~Engine() {
|
|||
this->asEngine->ShutDownAndRelease();
|
||||
}
|
||||
|
||||
asIScriptEngine *Engine::getAsEngine() const {
|
||||
asIScriptEngine* Engine::getAsEngine() const {
|
||||
return this->asEngine;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <angelscript.h>
|
||||
#include <vfspp/VirtualFileSystem.hpp>
|
||||
|
||||
|
||||
namespace atlas::script::engine {
|
||||
|
@ -27,9 +26,9 @@ public:
|
|||
* @return the AngelScript engine
|
||||
*/
|
||||
[[nodiscard]] asIScriptEngine* getAsEngine() const;
|
||||
|
||||
private:
|
||||
asIScriptEngine* asEngine;
|
||||
std::unique_ptr<vfspp::VirtualFileSystem> fileSystem;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "load.hpp"
|
||||
#include "_load.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "log.hpp"
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
namespace atlas::script::module::debug {
|
||||
|
||||
/**
|
||||
* Load the debug features into an Atlas engine
|
||||
* @param atlasEngine the Atlas engine
|
||||
*/
|
||||
void load(const engine::Engine* atlasEngine);
|
||||
|
||||
}
|
|
@ -5,6 +5,12 @@
|
|||
|
||||
namespace atlas::script::module::debug {
|
||||
|
||||
/**
|
||||
* @brief Log a message
|
||||
* @details Display a message in the execution logs
|
||||
* @param category the category of the message
|
||||
* @param message the message
|
||||
*/
|
||||
void log(const std::string& category, const std::string& message);
|
||||
|
||||
}
|
||||
|
|
8
source/script/module/filesystem/Path.cpp
Normal file
8
source/script/module/filesystem/Path.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "Path.hpp"
|
||||
|
||||
namespace atlas::script::module::filesystem {
|
||||
|
||||
Path::Path(const engine::Engine* atlasEngine, const std::string &path) {
|
||||
}
|
||||
|
||||
}
|
17
source/script/module/filesystem/Path.hpp
Normal file
17
source/script/module/filesystem/Path.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "script/engine/Engine.hpp"
|
||||
|
||||
|
||||
namespace atlas::script::module::filesystem {
|
||||
|
||||
/**
|
||||
* Represent a path in the virtual file system
|
||||
*/
|
||||
class Path {
|
||||
public:
|
||||
explicit Path(const engine::Engine* atlasEngine, const std::string& path);
|
||||
};
|
||||
|
||||
}
|
23
source/script/module/filesystem/_load.cpp
Normal file
23
source/script/module/filesystem/_load.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "_load.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
namespace atlas::script::module::filesystem {
|
||||
|
||||
void load(const engine::Engine* atlasEngine) {
|
||||
asIScriptEngine* asEngine = atlasEngine->getAsEngine();
|
||||
int error;
|
||||
|
||||
// start namespace
|
||||
error = asEngine->SetDefaultNamespace("atlas::filesystem");
|
||||
if (error < 0)
|
||||
throw std::runtime_error("Could not enter the \"atlas::filesystem\" namespace.");
|
||||
|
||||
// end namespace
|
||||
error = asEngine->SetDefaultNamespace("");
|
||||
if (error < 0)
|
||||
throw std::runtime_error("Could not reset the namespace.");
|
||||
}
|
||||
|
||||
}
|
13
source/script/module/filesystem/_load.hpp
Normal file
13
source/script/module/filesystem/_load.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "script/engine/Engine.hpp"
|
||||
|
||||
|
||||
namespace atlas::script::module::filesystem {
|
||||
|
||||
/**
|
||||
* Load the file system features into an Atlas engine
|
||||
* @param atlasEngine the Atlas engine
|
||||
*/
|
||||
void load(const engine::Engine* atlasEngine);
|
||||
|
||||
}
|
Loading…
Reference in a new issue