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