| 1 | //===----------------------------------------------------------------------===// |
| 2 | // DuckDB |
| 3 | // |
| 4 | // duckdb/common/virtual_file_system.hpp |
| 5 | // |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #pragma once |
| 10 | |
| 11 | #include "duckdb/common/file_system.hpp" |
| 12 | #include "duckdb/common/map.hpp" |
| 13 | |
| 14 | namespace duckdb { |
| 15 | |
| 16 | // bunch of wrappers to allow registering protocol handlers |
| 17 | class VirtualFileSystem : public FileSystem { |
| 18 | public: |
| 19 | VirtualFileSystem(); |
| 20 | |
| 21 | unique_ptr<FileHandle> OpenFile(const string &path, uint8_t flags, FileLockType lock = FileLockType::NO_LOCK, |
| 22 | FileCompressionType compression = FileCompressionType::UNCOMPRESSED, |
| 23 | FileOpener *opener = nullptr) override; |
| 24 | |
| 25 | void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override { |
| 26 | handle.file_system.Read(handle, buffer, nr_bytes, location); |
| 27 | }; |
| 28 | |
| 29 | void Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override { |
| 30 | handle.file_system.Write(handle, buffer, nr_bytes, location); |
| 31 | } |
| 32 | |
| 33 | int64_t Read(FileHandle &handle, void *buffer, int64_t nr_bytes) override { |
| 34 | return handle.file_system.Read(handle, buffer, nr_bytes); |
| 35 | } |
| 36 | |
| 37 | int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes) override { |
| 38 | return handle.file_system.Write(handle, buffer, nr_bytes); |
| 39 | } |
| 40 | |
| 41 | int64_t GetFileSize(FileHandle &handle) override { |
| 42 | return handle.file_system.GetFileSize(handle); |
| 43 | } |
| 44 | time_t GetLastModifiedTime(FileHandle &handle) override { |
| 45 | return handle.file_system.GetLastModifiedTime(handle); |
| 46 | } |
| 47 | FileType GetFileType(FileHandle &handle) override { |
| 48 | return handle.file_system.GetFileType(handle); |
| 49 | } |
| 50 | |
| 51 | void Truncate(FileHandle &handle, int64_t new_size) override { |
| 52 | handle.file_system.Truncate(handle, new_size); |
| 53 | } |
| 54 | |
| 55 | void FileSync(FileHandle &handle) override { |
| 56 | handle.file_system.FileSync(handle); |
| 57 | } |
| 58 | |
| 59 | // need to look up correct fs for this |
| 60 | bool DirectoryExists(const string &directory) override { |
| 61 | return FindFileSystem(path: directory)->DirectoryExists(directory); |
| 62 | } |
| 63 | void CreateDirectory(const string &directory) override { |
| 64 | FindFileSystem(path: directory)->CreateDirectory(directory); |
| 65 | } |
| 66 | |
| 67 | void RemoveDirectory(const string &directory) override { |
| 68 | FindFileSystem(path: directory)->RemoveDirectory(directory); |
| 69 | } |
| 70 | |
| 71 | bool ListFiles(const string &directory, const std::function<void(const string &, bool)> &callback, |
| 72 | FileOpener *opener = nullptr) override { |
| 73 | return FindFileSystem(path: directory)->ListFiles(directory, callback, opener); |
| 74 | } |
| 75 | |
| 76 | void MoveFile(const string &source, const string &target) override { |
| 77 | FindFileSystem(path: source)->MoveFile(source, target); |
| 78 | } |
| 79 | |
| 80 | bool FileExists(const string &filename) override { |
| 81 | return FindFileSystem(path: filename)->FileExists(filename); |
| 82 | } |
| 83 | |
| 84 | bool IsPipe(const string &filename) override { |
| 85 | return FindFileSystem(path: filename)->IsPipe(filename); |
| 86 | } |
| 87 | virtual void RemoveFile(const string &filename) override { |
| 88 | FindFileSystem(path: filename)->RemoveFile(filename); |
| 89 | } |
| 90 | |
| 91 | virtual vector<string> Glob(const string &path, FileOpener *opener = nullptr) override { |
| 92 | return FindFileSystem(path)->Glob(path, opener); |
| 93 | } |
| 94 | |
| 95 | void RegisterSubSystem(unique_ptr<FileSystem> fs) override { |
| 96 | sub_systems.push_back(x: std::move(fs)); |
| 97 | } |
| 98 | |
| 99 | void UnregisterSubSystem(const string &name) override { |
| 100 | for (auto sub_system = sub_systems.begin(); sub_system != sub_systems.end(); sub_system++) { |
| 101 | if (sub_system->get()->GetName() == name) { |
| 102 | sub_systems.erase(position: sub_system); |
| 103 | return; |
| 104 | } |
| 105 | } |
| 106 | throw InvalidInputException("Could not find filesystem with name %s" , name); |
| 107 | } |
| 108 | |
| 109 | void RegisterSubSystem(FileCompressionType compression_type, unique_ptr<FileSystem> fs) override { |
| 110 | compressed_fs[compression_type] = std::move(fs); |
| 111 | } |
| 112 | |
| 113 | vector<string> ListSubSystems() override { |
| 114 | vector<string> names(sub_systems.size()); |
| 115 | for (idx_t i = 0; i < sub_systems.size(); i++) { |
| 116 | names[i] = sub_systems[i]->GetName(); |
| 117 | } |
| 118 | return names; |
| 119 | } |
| 120 | |
| 121 | std::string GetName() const override { |
| 122 | return "VirtualFileSystem" ; |
| 123 | } |
| 124 | |
| 125 | private: |
| 126 | FileSystem *FindFileSystem(const string &path) { |
| 127 | for (auto &sub_system : sub_systems) { |
| 128 | if (sub_system->CanHandleFile(fpath: path)) { |
| 129 | return sub_system.get(); |
| 130 | } |
| 131 | } |
| 132 | return default_fs.get(); |
| 133 | } |
| 134 | |
| 135 | private: |
| 136 | vector<unique_ptr<FileSystem>> sub_systems; |
| 137 | map<FileCompressionType, unique_ptr<FileSystem>> compressed_fs; |
| 138 | const unique_ptr<FileSystem> default_fs; |
| 139 | }; |
| 140 | |
| 141 | } // namespace duckdb |
| 142 | |