#include "VirtualFileSystem.hpp" #include #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; } }