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