1 /**
2  * @file   posix.h
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * This file includes declarations of posix filesystem functions.
31  */
32 
33 #ifndef TILEDB_POSIX_FILESYSTEM_H
34 #define TILEDB_POSIX_FILESYSTEM_H
35 
36 #ifndef _WIN32
37 
38 #include <ftw.h>
39 #include <sys/types.h>
40 
41 #include <functional>
42 #include <string>
43 #include <vector>
44 
45 #include "tiledb/common/status.h"
46 #include "tiledb/common/thread_pool.h"
47 #include "tiledb/sm/config/config.h"
48 #include "tiledb/sm/filesystem/filelock.h"
49 
50 using namespace tiledb::common;
51 
52 namespace tiledb {
53 namespace sm {
54 
55 /**
56  * This class implements the POSIX filesystem functions.
57  */
58 class Posix {
59  public:
60   /** Constructor. */
61   Posix();
62 
63   /** Destructor. */
64   ~Posix() = default;
65 
66   /**
67    * Returns the absolute posix (string) path of the input in the
68    * form "file://<absolute path>"
69    */
70   static std::string abs_path(const std::string& path);
71 
72   /**
73    * Creates a new directory.
74    *
75    * @param dir The name of the directory to be created.
76    * @return Status
77    */
78   Status create_dir(const std::string& path) const;
79 
80   /**
81    * Creates an empty file.
82    *
83    * @param filename The name of the file to be created.
84    * @return Status
85    */
86   Status touch(const std::string& filename) const;
87 
88   /**
89    * Returns the directory where the program is executed.
90    *
91    * @return The directory path where the program is executed. If the program
92    * cannot retrieve the current working directory, the empty string is
93    * returned.
94    */
95   static std::string current_dir();
96 
97   /**
98    * Removes a given directory recursively.
99    *
100    * @param path The path of the directory to be deleted.
101    * @return Status
102    */
103   Status remove_dir(const std::string& path) const;
104 
105   /** Deletes the file in the input path. */
106 
107   /**
108    * Removes a given path.
109    *
110    * @param path The path of the file / empty directory to be deleted.
111    * @return Status
112    */
113   Status remove_file(const std::string& path) const;
114 
115   /**
116    * Returns the size of the input file.
117    *
118    * @param path The name of the file whose size is to be retrieved.
119    * @param nbytes Pointer to a value
120    * @return Status
121    */
122   Status file_size(const std::string& path, uint64_t* size) const;
123 
124   /**
125    * Lock a given filename and retrieve an open file descriptor handle.
126    *
127    * @param filename The filelock to lock
128    * @param fd A pointer to a file descriptor
129    * @param shared *True* if this is a shared lock, *false* if it is an
130    * exclusive lock.
131    * @return Status
132    */
133   Status filelock_lock(
134       const std::string& filename, filelock_t* fd, bool shared) const;
135 
136   /**
137    * Unlock an opened file descriptor
138    *
139    * @param fd the open file descriptor to unlock
140    * @return Status
141    */
142   Status filelock_unlock(int fd) const;
143 
144   /**
145    * Initialize this instance with the given config.
146    *
147    * @param config Config parameters.
148    * @param vfs_thread_pool ThreadPool from the parent VFS instance.
149    * @return Status
150    */
151   Status init(const Config& config, ThreadPool* vfs_thread_pool);
152 
153   /**
154    * Checks if the input is an existing directory.
155    *
156    * @param dir The directory to be checked.
157    * @return *True* if *dir* is an existing directory, and *False* otherwise.
158    */
159   bool is_dir(const std::string& path) const;
160 
161   /**
162    * Checks if the input is an existing file.
163    *
164    * @param file The file to be checked.
165    * @return *True* if *file* is an existing file, and *false* otherwise.
166    */
167   bool is_file(const std::string& path) const;
168 
169   /**
170    *
171    * Lists files one level deep under a given path.
172    *
173    * @param path  The parent path to list sub-paths.
174    * @param paths Pointer to a vector of strings to store the retrieved paths.
175    * @return Status
176    */
177   Status ls(const std::string& path, std::vector<std::string>* paths) const;
178 
179   /**
180    * Move a given filesystem path.
181    *
182    * @param old_path The old path.
183    * @param new_path The new path.
184    * @return Status
185    */
186   Status move_path(const std::string& old_path, const std::string& new_path);
187 
188   /**
189    * Copy a given filesystem file.
190    *
191    * @param old_path The old path.
192    * @param new_path The new path.
193    * @return Status
194    */
195   Status copy_file(const std::string& old_path, const std::string& new_path);
196 
197   /**
198    * Copy a given filesystem directory.
199    *
200    * @param old_path The old path.
201    * @param new_path The new path.
202    * @return Status
203    */
204   Status copy_dir(const std::string& old_path, const std::string& new_path);
205 
206   /**
207    * Reads data from a file into a buffer.
208    *
209    * @param path The name of the file.
210    * @param offset The offset in the file from which the read will start.
211    * @param buffer The buffer into which the data will be written.
212    * @param nbytes The size of the data to be read from the file.
213    * @return Status.
214    */
215   Status read(
216       const std::string& path,
217       uint64_t offset,
218       void* buffer,
219       uint64_t nbytes) const;
220 
221   /**
222    * Syncs a file or directory.
223    *
224    * @param path The name of the file.
225    * @return Status
226    */
227   Status sync(const std::string& path);
228 
229   /**
230    * Writes the input buffer to a file.
231    *
232    * If the file exists than it is created.
233    * If the file does not exist than it is appended to.
234    *
235    * @param path The name of the file.
236    * @param buffer The input buffer.
237    * @param buffer_size The size of the input buffer.
238    * @return Status
239    */
240   Status write(
241       const std::string& path, const void* buffer, uint64_t buffer_size);
242 
243  private:
244   /** Config parameters inherited from parent VFS. */
245   std::reference_wrapper<const Config> config_;
246 
247   /** Default config. */
248   Config default_config_;
249 
250   /** Thread pool from parent VFS instance. */
251   ThreadPool* vfs_thread_pool_;
252 
253   static void adjacent_slashes_dedup(std::string* path);
254 
255   static bool both_slashes(char a, char b);
256 
257   // Internal logic for 'abs_path()'.
258   static std::string abs_path_internal(const std::string& path);
259 
260   /**
261    * It takes as input an **absolute** path, and returns it in its canonicalized
262    * form, after appropriately replacing "./" and "../" in the path.
263    *
264    * @param path The input path passed by reference, which will be modified
265    *     by the function to hold the canonicalized absolute path. Note that the
266    *     path must be absolute, otherwise the function fails. In case of error
267    *     (e.g., if "../" are not properly used in *path*, or if *path* is not
268    *     absolute), the function sets the empty string (i.e., "") to *path*.
269    * @return void
270    */
271   static void purge_dots_from_path(std::string* path);
272 
273   /**
274    * Reads all nbytes from the given file descriptor, retrying as necessary.
275    *
276    * @param fd Open file descriptor to read from
277    * @param buffer Buffer to hold read data
278    * @param nbytes Number of bytes to read
279    * @param offset Offset in file to start reading from.
280    * @return Number of bytes actually read (< nbytes on error).
281    */
282   static uint64_t read_all(
283       int fd, void* buffer, uint64_t nbytes, uint64_t offset);
284 
285   static int unlink_cb(
286       const char* fpath,
287       const struct stat* sb,
288       int typeflag,
289       struct FTW* ftwbuf);
290 
291   /**
292    * Writes all nbytes to the given file descriptor, retrying as necessary.
293    *
294    * @param fd Open file descriptor to write to
295    * @param file_offset File offset at which to write.
296    * @param buffer Buffer with data to write
297    * @param nbytes Number of bytes to write
298    * @return Number of bytes actually written (< nbytes on error).
299    */
300   static uint64_t pwrite_all(
301       int fd, uint64_t file_offset, const void* buffer, uint64_t nbytes);
302 
303   /**
304    * Write data from the given buffer to the file descriptor, beginning at the
305    * given offset. Multiple threads can safely write to the same open file
306    * descriptor.
307    *
308    * @param fd Open file descriptor to write to
309    * @param file_offset Offset in the file at which to start writing
310    * @param buffer Buffer of data to write
311    * @param buffer_size Number of bytes to write
312    * @return Status
313    */
314   static Status write_at(
315       int fd, uint64_t file_offset, const void* buffer, uint64_t buffer_size);
316 
317   /**
318    * Parse config to get posix permissions for creating new files
319    * @param permissions parsed permissions are set to this parameter
320    * @return Status
321    */
322   Status get_posix_file_permissions(uint32_t* permissions) const;
323 
324   /**
325    * Parse config to get posix permissions for creating new directories
326    * @param permissions parsed permissions are set to this parameter
327    * @return Status
328    */
329   Status get_posix_directory_permissions(uint32_t* permissions) const;
330 };
331 
332 }  // namespace sm
333 }  // namespace tiledb
334 
335 #endif  // !_WIN32
336 
337 #endif  // TILEDB_POSIX_FILESYSTEM_H
338