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