MySQL  8.0.21
Source Code Documentation
filesystem.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License, version 2.0,
6  as published by the Free Software Foundation.
7 
8  This program is also distributed with certain software (including
9  but not limited to OpenSSL) that is licensed under separate terms,
10  as designated in a particular file or component or in included license
11  documentation. The authors of MySQL hereby grant you an additional
12  permission to link the program and your derivative works with the
13  separately licensed software that they have included with MySQL.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24 
25 #ifndef MYSQL_HARNESS_FILESYSTEM_INCLUDED
26 #define MYSQL_HARNESS_FILESYSTEM_INCLUDED
27 
28 #include "harness_export.h"
29 
30 #include <memory>
31 #include <ostream>
32 #include <stdexcept>
33 #include <string>
34 
35 #ifndef _WIN32
36 #include <fcntl.h>
37 #endif
38 
39 #ifdef _WIN32
40 #include <aclapi.h>
41 #endif
42 
43 namespace mysql_harness {
44 
45 /**
46  * @defgroup Filesystem Platform-independent file system operations
47  *
48  * This module contain platform-independent file system operations.
49  */
50 
51 /**
52  * Class representing a path in a file system.
53  *
54  * @ingroup Filesystem
55  *
56  * Paths are used to access files in the file system and can be either
57  * relative or absolute. Absolute paths have a slash (`/`) first in
58  * the path, otherwise, the path is relative.
59  */
60 class HARNESS_EXPORT Path {
61  friend std::ostream &operator<<(std::ostream &out, const Path &path) {
62  out << path.path_;
63  return out;
64  }
65 
66  public:
67  /**
68  * Enum used to identify file types.
69  */
70 
71  enum class FileType {
72  /** An error occurred when trying to get file type, but it is *not*
73  * that the file was not found. */
74  STATUS_ERROR,
75 
76  /** Empty path was given */
77  EMPTY_PATH,
78 
79  /** The file was not found. */
80  FILE_NOT_FOUND,
81 
82  /** The file is a regular file. */
83  REGULAR_FILE,
84 
85  /** The file is a directory. */
86  DIRECTORY_FILE,
87 
88  /** The file is a symbolic link. */
89  SYMLINK_FILE,
90 
91  /** The file is a block device */
92  BLOCK_FILE,
93 
94  /** The file is a character device */
95  CHARACTER_FILE,
96 
97  /** The file is a FIFO */
98  FIFO_FILE,
99 
100  /** The file is a UNIX socket */
101  SOCKET_FILE,
102 
103  /** The type of the file is unknown, either because it was not
104  * fetched yet or because stat(2) reported something else than the
105  * above. */
106  TYPE_UNKNOWN,
107  };
108 
109  friend HARNESS_EXPORT std::ostream &operator<<(std::ostream &out,
110  FileType type);
111 
112  Path() noexcept;
113 
114  /**
115  * Construct a path
116  *
117  * @param path Non-empty string denoting the path.
118  */
119  /** @overload */ // throws std::invalid_argument
120  Path(const std::string &path); // NOLINT(runtime/explicit)
121 
122  /** @overload */ // throws std::invalid_argument
123  Path(const char *path); // NOLINT(runtime/explicit)
124 
125  /**
126  * Create a path from directory, basename, and extension.
127  */
128  static Path make_path(const Path &directory, const std::string &basename,
129  const std::string &extension);
130 
131  bool operator==(const Path &rhs) const;
132  bool operator!=(const Path &rhs) const { return !(*this == rhs); }
133 
134  /**
135  * Path ordering operator.
136  *
137  * This is mainly used for ordered containers. The paths are ordered
138  * lexicographically.
139  */
140  bool operator<(const Path &rhs) const;
141 
142  /**
143  * Get the file type.
144  *
145  * The file type is normally cached so if the file type under a path
146  * changes it is necessary to force a refresh.
147  *
148  * @param refresh Set to `true` if the file type should be
149  * refreshed, default to `false`.
150  *
151  * @return The type of the file.
152  */
153  FileType type(bool refresh = false) const;
154 
155  /**
156  * Check if the file is a directory.
157  */
158  bool is_directory() const;
159 
160  /**
161  * Check if the file is a regular file.
162  */
163  bool is_regular() const;
164 
165  /**
166  * Check if the path is absolute or not
167  *
168  * The path is considered absolute if it starts with one of:
169  * Unix: '/'
170  * Windows: '/' or '\' or '.:' (where . is any character)
171  * else:
172  * it's considered relative (empty path is also relative in such respect)
173  */
174  bool is_absolute() const;
175 
176  /**
177  * Check if path exists
178  */
179  bool exists() const;
180 
181  /*
182  * @brief Checks if path exists and can be opened for reading.
183  *
184  * @return true if path exists and can be opened for reading,
185  * false otherwise.
186  */
187  bool is_readable() const;
188 
189  /**
190  * Get the directory name of the path.
191  *
192  * This will strip the last component of a path, assuming that the
193  * what remains is a directory name. If the path is a relative path
194  * that do not contain any directory separators, a dot will be
195  * returned (denoting the current directory).
196  *
197  * @note No checking of the components are done, this is just simple
198  * path manipulation.
199  *
200  * @return A new path object representing the directory portion of
201  * the path.
202  */
203  Path dirname() const;
204 
205  /**
206  * Get the basename of the path.
207  *
208  * Return the basename of the path: the path without the directory
209  * portion.
210  *
211  * @note No checking of the components are done, this is just simple
212  * path manipulation.
213  *
214  * @return A new path object representing the basename of the path.
215  * the path.
216  */
217  Path basename() const;
218 
219  /**
220  * Append a path component to the current path.
221  *
222  * This function will append a path component to the path using the
223  * apropriate directory separator.
224  *
225  * @param other Path component to append to the path.
226  */
227  void append(const Path &other);
228 
229  /**
230  * Join two path components to form a new path.
231  *
232  * This function will join the two path components using a
233  * directory separator.
234  *
235  * @note This will return a new `Path` object. If you want to modify
236  * the existing path object, you should use `append` instead.
237  *
238  * @param other Path component to be appended to the path
239  */
240  Path join(const Path &other) const;
241 
242  /** @overload */
243  Path join(const char *other) const { return join(Path(other)); }
244 
245  /**
246  * Returns the canonical form of the path, resolving relative paths.
247  */
248  Path real_path() const;
249 
250  /**
251  * Get a C-string representation to the path.
252  *
253  * @note This will return a pointer to the internal representation
254  * of the path and hence will become a dangling pointer when the
255  * `Path` object is destroyed.
256  *
257  * @return Pointer to a null-terminated C-string.
258  */
259  const char *c_str() const { return path_.c_str(); }
260 
261  /**
262  * Get a string representation of the path.
263  *
264  * @return Instance of std::string containing the path.
265  */
266  const std::string &str() const noexcept { return path_; }
267 
268  /**
269  * Test if path is set
270  *
271  * @return Test result
272  */
273  bool is_set() const noexcept { return (type_ != FileType::EMPTY_PATH); }
274 
275  /**
276  * Directory separator string.
277  *
278  * @note This is platform-dependent and defined in the apropriate
279  * source file.
280  */
281  static const char *const directory_separator;
282 
283  /**
284  * Root directory string.
285  *
286  * @note This is platform-dependent and defined in the apropriate
287  * source file.
288  */
289  static const char *const root_directory;
290 
291  operator bool() const noexcept { return is_set(); }
292 
293  private:
294  void validate_non_empty_path() const; // throws std::invalid_argument
295 
296  std::string path_;
297  mutable FileType type_;
298 };
299 
300 /**
301  * Class representing a directory in a file system.
302  *
303  * @ingroup Filesystem
304  *
305  * In addition to being a refinement of `Path`, it also have functions
306  * that make it act like a container of paths and support iterating
307  * over the entries in a directory.
308  *
309  * An example of how it could be used is:
310  * @code
311  * for (auto&& entry: Directory(path))
312  * std::cout << entry << std::endl;
313  * @endcode
314  */
315 class HARNESS_EXPORT Directory : public Path {
316  public:
317  /**
318  * Directory iterator for iterating over directory entries.
319  *
320  * A directory iterator is an input iterator.
321  */
322  class HARNESS_EXPORT DirectoryIterator {
323  friend class Directory;
324 
325  public:
326  using value_type = Path;
327  using iterator_category = std::input_iterator_tag;
328  using difference_type = std::ptrdiff_t;
329  using pointer = value_type *;
331 
332  DirectoryIterator(const Path &path,
333  const std::string &pattern = std::string());
334 
335  // Create an end iterator
337 
338  /**
339  * Destructor.
340  *
341  * @note We need this *declared* because the default constructor
342  * try to generate a default constructor for shared_ptr on State
343  * below, which does not work since it is not visible. The
344  * destructor need to be *defined* in the corresponding .cc file
345  * since the State type is visible there (but you can use a
346  * default definition).
347  */
349 
350  // We need these since the default move/copy constructor is
351  // deleted when you define a destructor.
352 #if !defined(_MSC_VER) || (_MSC_VER >= 1900)
355 #endif
356 
357  /** Standard iterator operators */
358  /** @{ */
359  Path operator*() const;
361  Path operator->() { return this->operator*(); }
362  bool operator!=(const DirectoryIterator &other) const;
363 
364  // This avoids C2678 (no binary operator found) in MSVC,
365  // MSVC's std::copy implementation (used by TestFilesystem) uses operator==
366  // (while GCC's implementation uses operator!=).
367  bool operator==(const DirectoryIterator &other) const {
368  return !(this->operator!=(other));
369  }
370  /** @} */
371 
372  private:
373  /**
374  * Path to the root of the directory
375  */
376  const Path path_;
377 
378  /**
379  * Pattern that matches entries iterated over.
380  */
381  std::string pattern_;
382 
383  /*
384  * Platform-dependent container for iterator state.
385  *
386  * The definition of this class is different for different
387  * platforms, meaning that it is not defined here at all but
388  * rather in the corresponding `filesystem-<platform>.cc` file.
389  *
390  * The directory iterator is the most critical piece since it holds
391  * an iteration state for the platform: something that requires
392  * different types on the platforms.
393  */
394  class State;
395  std::shared_ptr<State> state_;
396  };
397 
398  /**
399  * Construct a directory instance.
400  *
401  * Construct a directory instance in different ways depending on the
402  * version of the constructor used.
403  */
404  Directory(const std::string &path) // NOLINT(runtime/explicit)
405  : Path(path) {} // throws std::invalid_argument
406 
407  /** @overload */ // throws std::invalid_argument
408  Directory(const Path &path); // NOLINT(runtime/explicit)
409 
410  Directory(const Directory &) = default;
411  Directory &operator=(const Directory &) = default;
412  ~Directory();
413 
414  /**
415  * Iterator to first entry.
416  *
417  * @return Returns an iterator pointing to the first entry.
418  */
419  DirectoryIterator begin();
420 
421  /**
422  * Iterator past-the-end of entries.
423  *
424  * @return Returns an iterator pointing *past-the-end* of the entries.
425  */
427 
428  /**
429  * Iterate over entries matching a glob.
430  */
431  DirectoryIterator glob(const std::string &glob);
432 };
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 //
436 // Utility free functions
437 //
438 ////////////////////////////////////////////////////////////////////////////////
439 
440 /** @brief Removes a directory.
441  *
442  * @ingroup Filesystem
443  *
444  * @param dir path of the directory to be removed; this directory must be empty
445  *
446  * @return 0 on success, -1 on error and sets errno
447  */
448 HARNESS_EXPORT
449 int delete_dir(const std::string &dir) noexcept;
450 
451 /** @brief Removes a file.
452  *
453  * @ingroup Filesystem
454  *
455  * @param path of the file to be removed
456  *
457  * @return 0 on success, -1 on error
458  */
459 HARNESS_EXPORT
460 int delete_file(const std::string &path) noexcept;
461 
462 /** @brief Removes directory and all its contents.
463  *
464  * @ingroup Filesystem
465  *
466  * @param dir path of the directory to be removed
467  *
468  * @return 0 on success, -1 on error
469  */
470 HARNESS_EXPORT
471 int delete_dir_recursive(const std::string &dir) noexcept;
472 
473 /** @brief Creates a temporary directory with partially-random name and returns
474  * its path.
475  *
476  * Creates a directory with a name of form {prefix}-{6 random alphanumerals}.
477  * For example, a possible directory name created by a call to
478  * get_tmp_dir("foo") might be: foo-3f9x0z
479  *
480  * Such directory is usually meant to be used as a temporary directory (thus the
481  * "_tmp_" in the name of this function).
482  *
483  * @ingroup Filesystem
484  *
485  * @param name name to be used as a directory name prefix
486  *
487  * @return path to the created directory
488  *
489  * @throws std::runtime_error if operation failed
490  */
491 HARNESS_EXPORT
492 std::string get_tmp_dir(const std::string &name = "router");
493 
494 // TODO: description
495 // TODO: move to some other place?
496 HARNESS_EXPORT
497 std::string get_plugin_dir(const std::string &runtime_dir);
498 
499 HARNESS_EXPORT
500 std::string get_tests_data_dir(const std::string &runtime_dir);
501 
502 #ifdef _WIN32
503 /**
504  * Deleter for smart pointers pointing to objects allocated with `std::malloc`.
505  */
506 template <typename T>
507 class StdFreeDeleter {
508  public:
509  void operator()(T *ptr) { std::free(ptr); }
510 };
511 
512 /**
513  * Retrieves file's DACL security descriptor.
514  *
515  * @param[in] file_name File name.
516  *
517  * @return File's DACL security descriptor.
518  *
519  * @throw std::exception Failed to retrieve security descriptor.
520  */
521 HARNESS_EXPORT std::unique_ptr<SECURITY_DESCRIPTOR, decltype(&free)>
522 get_security_descriptor(const std::string &file_name);
523 
524 #endif
525 
526 #ifndef _WIN32
527 using perm_mode = mode_t;
528 HARNESS_EXPORT
529 extern const perm_mode kStrictDirectoryPerm;
530 #else
531 using perm_mode = int;
532 HARNESS_EXPORT
533 extern const perm_mode kStrictDirectoryPerm;
534 #endif
535 
536 /** @brief Creates a directory
537  * *
538  * @param dir name (or path) of the directory to create
539  * @param mode permission mode for the created directory
540  * @param recursive if true then immitated unix `mkdir -p` recursively
541  * creating parent directories if needed
542  * @retval 0 operation succeeded
543  * @retval -1 operation failed because of wrong parameters
544  * @retval > 0 errno for failure to mkdir() system call
545  */
546 HARNESS_EXPORT
547 int mkdir(const std::string &dir, perm_mode mode, bool recursive = false);
548 
549 /**
550  * Changes file access permissions to be fully accessible by all users.
551  *
552  * On Unix, the function sets file permission mask to 777.
553  * On Windows, Everyone group is granted full access to the file.
554  *
555  * @param[in] file_name File name.
556  *
557  * @throw std::exception Failed to change file permissions.
558  */
559 void HARNESS_EXPORT make_file_public(const std::string &file_name);
560 
561 #ifdef _WIN32
562 /**
563  * Changes file access permissions to be readable by all users.
564  *
565  * On Windows, Everyone group is granted read access to the file.
566  *
567  * @param[in] file_name File name.
568  *
569  * @throw std::exception Failed to change file permissions.
570  */
571 void make_file_readable_for_everyone(const std::string &file_name);
572 #endif
573 
574 /**
575  * Changes file access permissions to be accessible only by a limited set of
576  * users.
577  *
578  * On Unix, the function sets file permission mask to 600.
579  * On Windows, all permissions to this file are removed for Everyone group,
580  * LocalService account gets read (and optionally write) access.
581  *
582  * @param[in] file_name File name.
583  * @param[in] read_only_for_local_service Weather the LocalService user on
584  * Windows should get only the read access (if false will grant write access
585  * too). Not used on non-Windows.
586  *
587  * @throw std::exception Failed to change file permissions.
588  */
589 void HARNESS_EXPORT
590 make_file_private(const std::string &file_name,
591  const bool read_only_for_local_service = true);
592 
593 /**
594  * Changes file access permissions to be read only.
595  *
596  * On Unix, the function sets file permission mask to 555.
597  * On Windows, all permissions to this file are read access only for Everyone
598  * group, LocalService account gets read access.
599  *
600  * @param[in] file_name File name.
601  *
602  * @throw std::exception Failed to change file permissions.
603  */
604 void HARNESS_EXPORT make_file_readonly(const std::string &file_name);
605 
606 /**
607  * Verifies access permissions of a file.
608  *
609  * On Unix systems it throws if file's permissions differ from 600.
610  * On Windows it throws if file can be accessed by Everyone group.
611  *
612  * @param[in] file_name File to be verified.
613  *
614  * @throw std::exception File access rights are too permissive or
615  * an error occurred.
616  * @throw std::system_error OS and/or filesystem doesn't support file
617  * permissions.
618  */
619 
620 void HARNESS_EXPORT check_file_access_rights(const std::string &file_name);
621 
622 } // namespace mysql_harness
623 
624 #endif /* MYSQL_HARNESS_FILESYSTEM_INCLUDED */
Class representing a path in a file system.
Definition: filesystem.h:60
const std::string & str() const noexcept
Get a string representation of the path.
Definition: filesystem.h:266
Path operator->()
Definition: filesystem.h:361
bool operator!=(const Path &rhs) const
Definition: filesystem.h:132
#define free(A)
Definition: fts0ast.h:42
std::string pattern_
Pattern that matches entries iterated over.
Definition: filesystem.h:381
const char * c_str() const
Get a C-string representation to the path.
Definition: filesystem.h:259
void HARNESS_EXPORT make_file_private(const std::string &file_name, const bool read_only_for_local_service=true)
Changes file access permissions to be accessible only by a limited set of users.
Definition: filesystem.cc:706
HARNESS_EXPORT int delete_dir(const std::string &dir) noexcept
Removes a directory.
Definition: filesystem-posix.cc:290
const Path path_
Path to the root of the directory.
Definition: filesystem.h:376
HARNESS_EXPORT int delete_file(const std::string &path) noexcept
Removes a file.
Definition: filesystem-posix.cc:292
#define bool
Definition: config_static.h:42
Ssl_acceptor_context_property_type & operator++(Ssl_acceptor_context_property_type &property_type)
Increment operator for Ssl_acceptor_context_type Used by iterator.
Definition: ssl_acceptor_context_data.cc:112
Definition: filesystem-posix.cc:106
HARNESS_EXPORT std::string get_plugin_dir(const std::string &runtime_dir)
Definition: filesystem.cc:237
mode
Definition: file_handle.h:58
Path join(const char *other) const
Definition: filesystem.h:243
static const char *const root_directory
Root directory string.
Definition: filesystem.h:289
std::string join(Container cont, const std::string &delim)
join elements of an container into a string seperated by a delimiter.
Definition: string.h:144
HARNESS_EXPORT std::string get_tmp_dir(const std::string &name="router")
Creates a temporary directory with partially-random name and returns its path.
Definition: filesystem-posix.cc:296
string dirname(const string &path)
Definition: utilities.cc:40
HARNESS_EXPORT int mkdir(const std::string &dir, perm_mode mode, bool recursive=false)
Creates a directory *.
Definition: filesystem.cc:290
static const char *const directory_separator
Directory separator string.
Definition: filesystem.h:281
FileType type_
Definition: filesystem.h:297
std::input_iterator_tag iterator_category
Definition: filesystem.h:327
void HARNESS_EXPORT make_file_public(const std::string &file_name)
Changes file access permissions to be fully accessible by all users.
Definition: filesystem.cc:697
std::ptrdiff_t difference_type
Definition: filesystem.h:328
std::shared_ptr< State > state_
Definition: filesystem.h:394
static int exists(node_address *name, node_list const *nodes, u_int with_uid)
Definition: node_list.cc:101
bool is_set() const noexcept
Test if path is set.
Definition: filesystem.h:273
std::unique_ptr< SECURITY_DESCRIPTOR, decltype(&free)> get_security_descriptor(const std::string &file_name)
Definition: filesystem-windows.cc:351
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:188
static char * path
Definition: mysqldump.cc:131
string basename(const string &path)
Definition: utilities.cc:48
case opt name
Definition: sslopt-case.h:32
void HARNESS_EXPORT make_file_readonly(const std::string &file_name)
Changes file access permissions to be read only.
Definition: filesystem.cc:737
HARNESS_EXPORT const perm_mode kStrictDirectoryPerm
Definition: filesystem.cc:40
std::string path_
Definition: filesystem.h:296
Class representing a directory in a file system.
Definition: filesystem.h:315
Definition: common.h:39
void append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
Definition: suite_stubs.c:73
bool operator==(const IPAddress &a, const IPAddress &b)
Definition: ip_address.cc:55
friend std::ostream & operator<<(std::ostream &out, const Path &path)
Definition: filesystem.h:61
std::string dir
Double write files location.
Definition: buf0dblwr.cc:73
bool operator!=(const unexpected< E1 > &a, const unexpected< E2 > &b)
Definition: expected.h:1080
Directory(const std::string &path)
Construct a directory instance.
Definition: filesystem.h:404
Directory iterator for iterating over directory entries.
Definition: filesystem.h:322
constexpr bool operator<(basic_string_view< charT, traits > a, basic_string_view< charT, traits > b) noexcept
Definition: string_view.h:469
std::ostream & operator<<(std::ostream &out, Path::FileType type)
Definition: filesystem.cc:189
bool operator==(const DirectoryIterator &other) const
Definition: filesystem.h:367
mode_t perm_mode
Definition: filesystem.h:527
HARNESS_EXPORT int delete_dir_recursive(const std::string &dir) noexcept
Removes directory and all its contents.
Definition: filesystem.cc:221
void HARNESS_EXPORT check_file_access_rights(const std::string &file_name)
Verifies access permissions of a file.
Definition: filesystem.cc:423
FileType
Enum used to identify file types.
Definition: filesystem.h:71
bool_t is_set(node_set set, node_no i)
Definition: node_set.cc:216
HARNESS_EXPORT std::string get_tests_data_dir(const std::string &runtime_dir)
Definition: filesystem.cc:253