1 #pragma once 2 3 #include <sys/mount.h> 4 5 #include <filesystem> 6 #include <initializer_list> 7 #include <numeric> 8 #include <string> 9 10 namespace estoraged 11 { 12 13 /** @class FilesystemInterface 14 * @brief Interface to the filesystem operations that eStoraged needs. 15 * @details This class is used to mock out the filesystem operations. 16 */ 17 class FilesystemInterface 18 { 19 public: 20 virtual ~FilesystemInterface() = default; 21 22 FilesystemInterface() = default; 23 FilesystemInterface(const FilesystemInterface&) = delete; 24 FilesystemInterface& operator=(const FilesystemInterface&) = delete; 25 26 FilesystemInterface(FilesystemInterface&&) = delete; 27 FilesystemInterface& operator=(FilesystemInterface&&) = delete; 28 29 /** @brief Runs the mkfs command to create the filesystem. 30 * @details Used for mocking purposes. 31 * 32 * @param[in] logicalVolumePath - path to the mapped LUKS device. 33 * 34 * @returns 0 on success, nonzero on failure. 35 */ 36 virtual int runMkfs(const std::string& logicalVolumePath, 37 std::initializer_list<std::string> options = {}) = 0; 38 39 /** @brief Wrapper around mount(). 40 * @details Used for mocking purposes. 41 * 42 * @param[in] source - device where the filesystem is located. 43 * @param[in] target - path to where the filesystem should be mounted. 44 * @param[in] filesystemType - (e.g. "ext4"). 45 * @param[in] mountflags - flags bit mask (see mount() documentation). 46 * @param[in] data - options for specific filesystem type, can be NULL 47 * (see mount() documentation). 48 * 49 * @returns On success, zero is returned. On error, -1 is returned, and 50 * errno is set to indicate the error. 51 */ 52 virtual int doMount(const char* source, const char* target, 53 const char* filesystemtype, unsigned long mountflags, 54 const void* data) = 0; 55 56 /** @brief Wrapper around umount(). 57 * @details Used for mocking purposes. 58 * 59 * @param[in] target - path location where the filesystem is mounted. 60 * 61 * @returns On success, zero is returned. On error, -1 is returned, and 62 * errno is set to indicate the error. 63 */ 64 virtual int doUnmount(const char* target) = 0; 65 66 /** @brief Wrapper around std::filesystem::create_directory. 67 * @details Used for mocking purposes. 68 * 69 * @param[in] p - path to directory that should be created. 70 * 71 * @returns true on success, false otherwise. 72 */ 73 virtual bool createDirectory(const std::filesystem::path& p) = 0; 74 75 /** @brief Wrapper around std::filesystem::remove. 76 * @details Used for mocking purposes. 77 * 78 * @param[in] p - path to directory that should be removed. 79 * 80 * @returns true on success, false otherwise. 81 */ 82 virtual bool removeDirectory(const std::filesystem::path& p) = 0; 83 84 /** @brief Wrapper around std::filesystem::is_directory 85 * 86 * @param[in] p - path to directory that we want to query. 87 * 88 * @returns true if the path exists and represents a directory. 89 */ 90 virtual bool directoryExists(const std::filesystem::path& p) = 0; 91 92 /** @brief Wrapper around fsck. 93 * @details Used for mocking purposes. 94 * 95 * @param[in] logicalVolumePath - path to device with filesystem 96 * @param[in] options - Other options to pass into fsck 97 * 98 * @returns 0 on success, nonzero on failure. 99 */ 100 virtual int runFsck(const std::string& logicalVolumePath, 101 const std::string& options) = 0; 102 }; 103 104 /** @class Filesystem 105 * @brief Implements FilesystemInterface 106 */ 107 class Filesystem : public FilesystemInterface 108 { 109 public: 110 ~Filesystem() override = default; 111 Filesystem() = default; 112 Filesystem(const Filesystem&) = delete; 113 Filesystem& operator=(const Filesystem&) = delete; 114 115 Filesystem(Filesystem&&) = delete; 116 Filesystem& operator=(Filesystem&&) = delete; 117 runMkfs(const std::string & logicalVolumePath,std::initializer_list<std::string> options)118 int runMkfs(const std::string& logicalVolumePath, 119 std::initializer_list<std::string> options) override 120 { 121 std::string mkfsCommand("mkfs.ext4 "); 122 mkfsCommand.reserve( 123 mkfsCommand.size() + logicalVolumePath.size() + options.size() + 124 std::accumulate(options.begin(), options.end(), 0, 125 [](size_t sum, const std::string& s) { 126 return sum + s.size(); 127 })); 128 129 for (const std::string& s : options) 130 { 131 mkfsCommand.append(s); 132 mkfsCommand.push_back(' '); 133 } 134 135 mkfsCommand.append(logicalVolumePath); 136 137 // calling 'system' uses a command processor //NOLINTNEXTLINE 138 return system(mkfsCommand.c_str()); 139 } 140 doMount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)141 int doMount(const char* source, const char* target, 142 const char* filesystemtype, unsigned long mountflags, 143 const void* data) override 144 { 145 return mount(source, target, filesystemtype, mountflags, data); 146 } 147 doUnmount(const char * target)148 int doUnmount(const char* target) override 149 { 150 return umount(target); 151 } 152 createDirectory(const std::filesystem::path & p)153 bool createDirectory(const std::filesystem::path& p) override 154 { 155 return std::filesystem::create_directory(p); 156 } 157 removeDirectory(const std::filesystem::path & p)158 bool removeDirectory(const std::filesystem::path& p) override 159 { 160 return std::filesystem::remove(p); 161 } 162 directoryExists(const std::filesystem::path & p)163 bool directoryExists(const std::filesystem::path& p) override 164 { 165 return std::filesystem::is_directory(std::filesystem::status(p)); 166 } 167 runFsck(const std::string & logicalVolumePath,const std::string & options)168 int runFsck(const std::string& logicalVolumePath, 169 const std::string& options) override 170 { 171 std::string fsckCommand("fsck " + logicalVolumePath + " " + options); 172 // calling 'system' uses a command processor //NOLINTNEXTLINE 173 return system(fsckCommand.c_str()); 174 } 175 }; 176 } // namespace estoraged 177