jaulib v1.2.0
Jau Support Library (C++, Java, ..)
file_util.hpp
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_FILE_UTIL_HPP_
26#define JAU_FILE_UTIL_HPP_
27
28#include <jau/fraction_type.hpp>
29#include <jau/functional.hpp>
30#include <memory>
31#include <string>
32
33extern "C" {
34 // #include <sys/stat.h>
35 // for ::mode_t posix protection bits
36 #include <sys/types.h>
37}
38
39namespace jau::fs {
40
41 /** @defgroup FileUtils File Utilities
42 * File types and functionality.
43 *
44 * @{
45 */
46
47 /**
48 * Return the current working directory or empty on failure.
49 */
50 std::string get_cwd() noexcept;
51
52 /** Change working directory */
53 bool chdir(const std::string& path) noexcept;
54
55 /**
56 * Returns the absolute path of given `relpath` if existing,
57 * otherwise an empty string.
58 * @param relpath a path, might be relative
59 */
60 std::string absolute(const std::string_view& relpath) noexcept;
61
62 /**
63 * Return stripped last component from given path separated by `/`, excluding the trailing separator `/`.
64 *
65 * If no directory separator `/` is contained, return `.`.
66 *
67 * If only the root path `/` is given, return `/`.
68 *
69 * @param path given path
70 * @return leading directory name w/o slash or `.`
71 */
72 std::string dirname(const std::string_view& path) noexcept;
73
74 /**
75 * Return stripped leading directory components from given path separated by `/`.
76 *
77 * If only the root path `/` is given, return `/`.
78 *
79 * @param path given path
80 * @return last non-slash component or `.`
81 */
82 std::string basename(const std::string_view& path) noexcept;
83
84 /** Returns true if first character is `/` or - in case of Windows - `\\`. */
85 bool isAbsolute(const std::string_view& path) noexcept;
86
87 /**
88 * Representing a directory item split into dirname() and basename().
89 */
90 class dir_item {
91 private:
92 std::string dirname_;
93 std::string basename_;
94 bool empty_;
95
96 struct backed_string_view {
97 std::string backing;
98 std::string_view view;
99
100 backed_string_view() noexcept
101 : backing(), view(backing) {}
102
103 backed_string_view(const std::string& backing_, const std::string_view& view_) noexcept
104 : backing(backing_),
105 view(backing_.size() > 0 ? ((std::string_view)backing).substr(view_.data() - backing_.data(), view_.size()) : view_) {}
106
107 backed_string_view(const std::string_view& view_) noexcept
108 : backing(), view(view_) {}
109
110#if 0
111 backed_string_view(const backed_string_view& o) noexcept
112 : backing(o.backing),
113 view( o.is_backed() ? ((std::string_view)backing).substr(o.view.data() - o.backing.data(), o.view.size()) : o.view)
114 {}
115#else
116 /** Reason: Inefficient, removing the whole purpose of this class reducing std::string duplication. */
117 backed_string_view(const backed_string_view& o) noexcept = delete;
118#endif
119
120#if 0
121 backed_string_view(backed_string_view&& o) noexcept
122 : backing( std::move(o.backing) ),
123 view( std::move(o.view) )
124 {
125 fprintf(stderr, "backed_string_view move_ctor %s\n", to_string(true).c_str());
126 }
127#else
128 /** Reason: clang - for some reason - does not move a std::string, but copies it */
129 backed_string_view(backed_string_view&& o) noexcept = delete;
130#endif
131
132 bool is_backed() const noexcept { return backing.size() > 0; }
133
134 void backup() noexcept {
135 backing = std::string(view);
136 view = backing;
137 }
138 void backup(const std::string& orig) noexcept {
139 backing = orig;
140 view = backing;
141 }
142 void backup(const std::string_view& orig) noexcept {
143 backing = std::string(orig);
144 view = backing;
145 }
146 void backup_and_append(const std::string& orig, const std::string& appendix) noexcept {
147 backing = orig;
148 backing.append(appendix);
149 view = backing;
150 }
151 void backup_and_append(const std::string_view& orig, const std::string& appendix) noexcept {
152 backing = std::string(orig);
153 backing.append(appendix);
154 view = backing;
155 }
156
157 std::string to_string(const bool destailed = false) const noexcept {
158 if (destailed) {
159 return "[backing '" + backing + "', view '" + std::string(view) + "']";
160 }
161 return std::string(view);
162 }
163 };
164 static std::unique_ptr<backed_string_view> reduce(const std::string_view& path_) noexcept;
165
166 dir_item(std::unique_ptr<backed_string_view> cleanpath) noexcept;
167
168 public:
169 /** Empty item w/ `.` set for both, dirname and basename. empty() will return true; */
170 dir_item() noexcept;
171
172 /**
173 * Create a dir_item where path is split into dirname and basename after `.` and `..` has been reduced.
174 *
175 * empty() will return true if given path_ is empty
176 *
177 * @param path_ the raw path
178 */
179 dir_item(const std::string_view& path_) noexcept;
180
181 /**
182 * Create a dir_item with already cleaned dirname and basename
183 * without any further processing nor validation.
184 *
185 * empty() will return true if both, given dirname_ and basename_ is empty
186 *
187 * @param dirname__
188 * @param basename__
189 * @see reduce()
190 * @see jau::fs::dirname()
191 * @see jau::fs::basename()
192 */
193 dir_item(std::string dirname__, std::string basename__) noexcept;
194
195 /** Returns the dirname, shall not be empty and denotes `.` for current working director. */
196 const std::string& dirname() const noexcept { return dirname_; }
197
198 /** Return the basename, shall not be empty nor contain a dirname. */
199 const std::string& basename() const noexcept { return basename_; }
200
201 /**
202 * Returns a full unix path representation combining dirname() and basename().
203 */
204 std::string path() const noexcept;
205
206 /**
207 * Returns true if bot, dirname() and basename() refer to `.`, e.g.. default ctor.
208 */
209 bool empty() const noexcept { return empty_; }
210
211 bool operator==(const dir_item& rhs) const noexcept {
212 return dirname_ == rhs.dirname_ && basename_ == rhs.basename_;
213 }
214
215 bool operator!=(const dir_item& rhs) const noexcept {
216 return !(*this == rhs);
217 }
218
219 /**
220 * Returns a comprehensive string representation of this item
221 */
222 std::string to_string() const noexcept;
223 };
224
225 /**
226 * Generic file type and POSIX protection mode bits as used in file_stats, touch(), mkdir() etc.
227 *
228 * The POSIX protection mode bits reside in the lower 16-bits and are bit-wise POSIX compliant
229 * while the file type bits reside in the upper 16-bits and are platform agnostic.
230 *
231 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
232 *
233 * @see file_stats
234 * @see file_stats::mode()
235 */
236 enum class fmode_t : uint32_t {
237 /** No mode bit set */
238 none = 0,
239
240 /** Protection bit: POSIX S_ISUID */
241 set_uid = 04000,
242 /** Protection bit: POSIX S_ISGID */
243 set_gid = 02000,
244 /** Protection bit: POSIX S_ISVTX */
245 sticky = 01000,
246 /** Protection bit: POSIX S_ISUID | S_ISGID | S_ISVTX */
247 ugs_set = 07000,
248
249 /** Protection bit: POSIX S_IRUSR */
250 read_usr = 00400,
251 /** Protection bit: POSIX S_IWUSR */
252 write_usr = 00200,
253 /** Protection bit: POSIX S_IXUSR */
254 exec_usr = 00100,
255 /** Protection bit: POSIX S_IRWXU */
256 rwx_usr = 00700,
257
258 /** Protection bit: POSIX S_IRGRP */
259 read_grp = 00040,
260 /** Protection bit: POSIX S_IWGRP */
261 write_grp = 00020,
262 /** Protection bit: POSIX S_IXGRP */
263 exec_grp = 00010,
264 /** Protection bit: POSIX S_IRWXG */
265 rwx_grp = 00070,
266
267 /** Protection bit: POSIX S_IROTH */
268 read_oth = 00004,
269 /** Protection bit: POSIX S_IWOTH */
270 write_oth = 00002,
271 /** Protection bit: POSIX S_IXOTH */
272 exec_oth = 00001,
273 /** Protection bit: POSIX S_IRWXO */
274 rwx_oth = 00007,
275
276 /** Protection bit: POSIX S_IRWXU | S_IRWXG | S_IRWXO or rwx_usr | rwx_grp | rwx_oth */
277 rwx_all = 00777,
278
279 /** Default directory protection bit: Safe default: POSIX S_IRWXU | S_IRGRP | S_IXGRP or rwx_usr | read_grp | exec_grp */
280 def_dir_prot = 00750,
281
282 /** Default file protection bit: Safe default: POSIX S_IRUSR | S_IWUSR | S_IRGRP or read_usr | write_usr | read_grp */
283 def_file_prot = 00640,
284
285 /** 12 bit protection bit mask 07777 for rwx_all | set_uid | set_gid | sticky . */
286 protection_mask = 0b00000000000000000000111111111111,
287
288 /** Type: Entity is a socket, might be in combination with link. */
289 sock = 0b00000000000000000001000000000000,
290 /** Type: Entity is a block device, might be in combination with link. */
291 blk = 0b00000000000000000010000000000000,
292 /** Type: Entity is a character device, might be in combination with link. */
293 chr = 0b00000000000000000100000000000000,
294 /** Type: Entity is a fifo/pipe, might be in combination with link. */
295 fifo = 0b00000000000000001000000000000000,
296 /** Type: Entity is a directory, might be in combination with link. */
297 dir = 0b00000000000000010000000000000000,
298 /** Type: Entity is a file, might be in combination with link. */
299 file = 0b00000000000000100000000000000000,
300 /** Type: Entity is a symbolic link, might be in combination with file or dir, fifo, chr, blk or sock. */
301 link = 0b00000000000001000000000000000000,
302 /** Type: Entity gives no access to user, exclusive bit. */
303 no_access = 0b00100000000000000000000000000000,
304 /** Type: Entity does not exist, exclusive bit. */
305 not_existing = 0b01000000000000000000000000000000,
306 /** Type mask for sock | blk | chr | fifo | dir | file | link | no_access | not_existing. */
307 type_mask = 0b01100000000001111111000000000000,
308 };
309 constexpr uint32_t number(const fmode_t rhs) noexcept {
310 return static_cast<uint32_t>(rhs);
311 }
312 constexpr fmode_t operator~(const fmode_t rhs) noexcept {
313 return static_cast<fmode_t>(~number(rhs));
314 }
315 constexpr fmode_t operator^(const fmode_t lhs, const fmode_t rhs) noexcept {
316 return static_cast<fmode_t>(number(lhs) ^ number(rhs));
317 }
318 constexpr fmode_t operator|(const fmode_t lhs, const fmode_t rhs) noexcept {
319 return static_cast<fmode_t>(number(lhs) | number(rhs));
320 }
321 constexpr fmode_t operator&(const fmode_t lhs, const fmode_t rhs) noexcept {
322 return static_cast<fmode_t>(number(lhs) & number(rhs));
323 }
324 constexpr fmode_t& operator|=(fmode_t& lhs, const fmode_t rhs) noexcept {
325 lhs = static_cast<fmode_t>(number(lhs) | number(rhs));
326 return lhs;
327 }
328 constexpr fmode_t& operator&=(fmode_t& lhs, const fmode_t rhs) noexcept {
329 lhs = static_cast<fmode_t>(number(lhs) & number(rhs));
330 return lhs;
331 }
332 constexpr fmode_t& operator^=(fmode_t& lhs, const fmode_t rhs) noexcept {
333 lhs = static_cast<fmode_t>(number(lhs) ^ number(rhs));
334 return lhs;
335 }
336 constexpr bool operator==(const fmode_t lhs, const fmode_t rhs) noexcept {
337 return number(lhs) == number(rhs);
338 }
339 constexpr bool operator!=(const fmode_t lhs, const fmode_t rhs) noexcept {
340 return !(lhs == rhs);
341 }
342 constexpr bool is_set(const fmode_t mask, const fmode_t bits) noexcept {
343 return bits == (mask & bits);
344 }
345 /**
346 * Return the string representation of fmode_t
347 * @param mask the fmode_t to convert
348 * @param show_rwx if true, return verbose POSIX protection bit string representation using `rwx` for user, group and others. Otherwise simply show the octal representation (default)
349 * @return the string representation.
350 */
351 std::string to_string(const fmode_t mask, const bool show_rwx = false) noexcept;
352
353 /** Returns the POSIX protection bits: rwx_all | set_uid | set_gid | sticky, i.e. fmode_t masked with fmode_t::protection_mask. */
354 constexpr ::mode_t posix_protection_bits(const fmode_t mask) noexcept { return static_cast<::mode_t>(mask & fmode_t::protection_mask); }
355
356 /**
357 * Returns platform dependent named file descriptor of given file descriptor, if supported.
358 *
359 * Implementation returns (`%d` stands for integer):
360 * - `/dev/fd/%d` (GNU/Linux, FreeBSD, ..)
361 *
362 * Following standard POSIX mappings exist
363 * - fd 0, `/dev/fd/0`, `/dev/stdin`
364 * - fd 1, `/dev/fd/1`, `/dev/stdout`
365 * - fd 2, `/dev/fd/2`, `/dev/stderr`
366 * - fd [0-99], `/dev/fd/[0-99]`
367 *
368 * Currently implementation always returns above pattern,
369 * not handling the target OS differences.
370 *
371 * @param fd file descriptor.
372 * @return the named file descriptor or an empty string if fd < 0 or not supported by OS.
373 *
374 * @see jau::fs::from_named_fd()
375 * @see jau::fs::file_stats:has_fd()
376 */
377 std::string to_named_fd(const int fd) noexcept;
378
379 /**
380 * Returns the file descriptor from the given named file descriptor.
381 *
382 * Detected named file descriptors are (`%d` stands for integer)
383 * - `/dev/fd/%d` (GNU/Linux, FreeBSD, ..)
384 * - `/proc/self/fd/%d` (GNU/Linux)
385 *
386 * @param named_fd the named file descriptor
387 * @return file descriptor or -1 if invalid or not supported by OS.
388 *
389 * @see jau::fs::to_named_fd()
390 * @see jau::fs::file_stats:has_fd()
391 */
392 int from_named_fd(const std::string& named_fd) noexcept;
393
394 /**
395 * Platform agnostic representation of POSIX ::lstat() and ::stat()
396 * for a given pathname.
397 *
398 * Implementation follows the symbolic link, i.e. first opens
399 * the given pathname with ::lstat() and if identifying as a symbolic link
400 * opens it via ::stat() to retrieve the actual properties like size, time and ownership.
401 *
402 * Implementation supports named file descriptor, see is_fd().
403 *
404 * On `GNU/Linux` implementation uses ::statx().
405 */
407 public:
408 /**
409 * Field identifier which bit-mask indicates field_t fields
410 */
411 enum class field_t : uint32_t {
412 /** No mode bit set */
413 none = 0,
414 /** File type mode bits */
415 type = 0b0000000000000001,
416 /** POSIX file protection mode bits */
417 mode = 0b0000000000000010,
418 nlink = 0b0000000000000100,
419 uid = 0b0000000000001000,
420 gid = 0b0000000000010000,
421 atime = 0b0000000000100000,
422 mtime = 0b0000000001000000,
423 ctime = 0b0000000010000000,
424 ino = 0b0000000100000000,
425 size = 0b0000001000000000,
426 blocks = 0b0000010000000000,
427 btime = 0b0000100000000000,
428 fd = 0b0001000000000000
429 };
430
431 typedef uint32_t uid_t;
432 typedef uint32_t gid_t;
433
434 private:
435 field_t has_fields_;
436
437 dir_item item_;
438
439 std::shared_ptr<std::string> link_target_path_; // stored link-target path this symbolic-link points to if is_link(), otherwise nullptr.
440 std::shared_ptr<file_stats> link_target_; // link-target this symbolic-link points to if is_link(), otherwise nullptr.
441
442 fmode_t mode_;
443 int fd_;
444 uid_t uid_;
445 gid_t gid_;
446 uint64_t size_;
447 fraction_timespec btime_; // Birth or creation time
448 fraction_timespec atime_; // Last access
449 fraction_timespec ctime_; // Last meta-status change
450 fraction_timespec mtime_; // Last modification
451
452 int errno_res_;
453
454 /** Private class only for private make_shared(). */
455 class ctor_cookie {
456 friend file_stats;
457 uint16_t rec_level;
458 ctor_cookie(const uint16_t recursion_level_) { rec_level = recursion_level_; }
459 };
460
461 public:
462 /** Instantiate an empty file_stats with fmode_t::not_existing set. */
463 file_stats() noexcept;
464
465 /** Private ctor for private make_shared<file_stats>() intended for friends. */
466 file_stats(const ctor_cookie& cc, int dirfd, const dir_item& item, const bool dirfd_is_item_dirname) noexcept;
467
468 /**
469 * Instantiates a file_stats for the given `path`.
470 *
471 * The dir_item will be constructed without parent_dir
472 *
473 * @param path the path to produce stats for
474 */
475 file_stats(const std::string& path) noexcept;
476
477 /**
478 * Instantiates a file_stats for the given `path`.
479 *
480 * The dir_item will be constructed without parent_dir
481 *
482 * @param dirfd file descriptor of given dir_item item's directory, dir_item::dirname(), or AT_FDCWD for the current working directory of the calling process
483 * @param path the path to produce stats for
484 */
485 file_stats(const int dirfd, const std::string& path) noexcept;
486
487 /**
488 * Instantiates a file_stats for the given dir_item.
489 *
490 * @param item the dir_item to produce stats for
491 */
492 file_stats(const dir_item& item) noexcept;
493
494 /**
495 * Instantiates a file_stats for the given dir_item.
496 *
497 * @param dirfd file descriptor of given dir_item item's directory, dir_item::dirname(), or AT_FDCWD for the current working directory of the calling process
498 * @param item the dir_item to produce stats for
499 * @param dirfd_is_item_dirname if true, dir_item::basename() is relative to dirfd (default), otherwise full dir_item::path() is relative to dirfd.
500 */
501 file_stats(const int dirfd, const dir_item& item, const bool dirfd_is_item_dirname = true) noexcept;
502
503 /**
504 * Instantiates a file_stats for the given `fd` file descriptor.
505 *
506 * @param fd file descriptor of an opened file
507 */
508 file_stats(const int fd) noexcept;
509
510 /**
511 * Returns the dir_item.
512 *
513 * In case this instance is created by following a symbolic link instance,
514 * it represents the resolved path relative to the used symbolic link's dirname.
515 *
516 * @see is_link()
517 * @see path()
518 */
519 const dir_item& item() const noexcept { return item_; }
520
521 /**
522 * Returns the unix path representation.
523 *
524 * In case this instance is created by following a symbolic link instance,
525 * it represents the resolved path relative to the used symbolic link's dirname.
526 *
527 * @see is_link()
528 * @see item()
529 */
530 std::string path() const noexcept { return item_.path(); }
531
532 /**
533 * Returns the stored link-target path this symbolic-link points to if instance is a symbolic-link, otherwise nullptr.
534 *
535 * @see is_link()
536 * @see link_target()
537 * @see final_target()
538 */
539 const std::shared_ptr<std::string>& link_target_path() const noexcept { return link_target_path_; }
540
541 /**
542 * Returns the link-target this symbolic-link points to if instance is a symbolic-link, otherwise nullptr.
543 *
544 * nullptr is also returned for an erroneous symbolic-links, i.e. non-existing link-targets or recursive loop-errors.
545 *
546 * @see is_link()
547 * @see link_target_path()
548 * @see final_target()
549 */
550 const std::shared_ptr<file_stats>& link_target() const noexcept { return link_target_; }
551
552 /**
553 * Returns the final target element, either a pointer to this instance if not a symbolic-link
554 * or the final link-target a symbolic-link (chain) points to.
555 *
556 * @param link_count optional size_t pointer to store the number of symbolic links leading to the final target, excluding the final instance. 0 indicates no symbolic-link;
557 *
558 * @see is_link()
559 * @see link_target_path()
560 * @see link_target()
561 */
562 const file_stats* final_target(size_t* link_count = nullptr) const noexcept;
563
564 /** Returns true if the given field_t fields were retrieved, otherwise false. */
565 bool has(const field_t fields) const noexcept;
566
567 /** Returns the retrieved field_t fields. */
568 constexpr field_t fields() const noexcept { return has_fields_; }
569
570 /** Returns the fmode_t, file type and mode. */
571 fmode_t mode() const noexcept { return mode_; }
572
573 /** Returns the POSIX protection bit portion of fmode_t, i.e. mode() & fmode_t::protection_mask. */
574 fmode_t prot_mode() const noexcept { return mode_ & fmode_t::protection_mask; }
575
576 /** Returns the type bit portion of fmode_t, i.e. mode() & fmode_t::type_mask. */
577 fmode_t type_mode() const noexcept { return mode_ & fmode_t::type_mask; }
578
579 /**
580 * Returns the file descriptor if has_fd(), otherwise -1 for no file descriptor.
581 *
582 * @see has_fd()
583 */
584 int fd() const noexcept { return fd_; }
585
586 /** Returns the user id, owning the element. */
587 uid_t uid() const noexcept { return uid_; }
588
589 /** Returns the group id, owning the element. */
590 gid_t gid() const noexcept { return gid_; }
591
592 /**
593 * Returns the size in bytes of this element if is_file(), otherwise zero.
594 *
595 * If the element also is_link(), the linked target size is returned.
596 */
597 uint64_t size() const noexcept { return size_; }
598
599 /** Returns the birth time of this element since Unix Epoch, i.e. its creation time. */
600 const fraction_timespec& btime() const noexcept { return btime_; }
601 /** Returns the last access time of this element since Unix Epoch. */
602 const fraction_timespec& atime() const noexcept { return atime_; }
603 /** Returns the last status change time of this element since Unix Epoch. */
604 const fraction_timespec& ctime() const noexcept { return ctime_; }
605 /** Returns the last modification time of this element since Unix Epoch. */
606 const fraction_timespec& mtime() const noexcept { return mtime_; }
607
608 /** Returns the `errno` value occurred to produce this instance, or zero for no error. */
609 constexpr int errno_res() const noexcept { return errno_res_; }
610
611 /** Returns true if no error occurred */
612 constexpr bool ok() const noexcept { return 0 == errno_res_; }
613
614 /**
615 * Returns true if entity has a file descriptor.
616 *
617 * @see fd()
618 * @see jau::fs::from_named_fd()
619 * @see jau::fs::to_named_fd()
620 */
621 constexpr bool has_fd() const noexcept { return 0 <= fd_; }
622
623 /** Returns true if entity is a socket, might be in combination with is_link(). */
624 constexpr bool is_socket() const noexcept { return is_set(mode_, fmode_t::sock); }
625
626 /** Returns true if entity is a block device, might be in combination with is_link(). */
627 constexpr bool is_block() const noexcept { return is_set(mode_, fmode_t::blk); }
628
629 /** Returns true if entity is a character device, might be in combination with is_link(). */
630 constexpr bool is_char() const noexcept { return is_set(mode_, fmode_t::chr); }
631
632 /** Returns true if entity is a fifo/pipe, might be in combination with is_link(). */
633 constexpr bool is_fifo() const noexcept { return is_set(mode_, fmode_t::fifo); }
634
635 /** Returns true if entity is a directory, might be in combination with is_link(). */
636 constexpr bool is_dir() const noexcept { return is_set(mode_, fmode_t::dir); }
637
638 /** Returns true if entity is a file, might be in combination with is_link(). */
639 constexpr bool is_file() const noexcept { return is_set(mode_, fmode_t::file); }
640
641 /** Returns true if entity is a symbolic link, might be in combination with is_file(), is_dir(), is_fifo(), is_char(), is_block(), is_socket(). */
642 constexpr bool is_link() const noexcept { return is_set(mode_, fmode_t::link); }
643
644 /** Returns true if entity gives no access to user, exclusive bit. */
645 constexpr bool has_access() const noexcept { return !is_set(mode_, fmode_t::no_access); }
646
647 /** Returns true if entity does not exist, exclusive bit. */
648 constexpr bool exists() const noexcept { return !is_set(mode_, fmode_t::not_existing); }
649
650 bool operator==(const file_stats& rhs) const noexcept;
651
652 bool operator!=(const file_stats& rhs) const noexcept {
653 return !(*this == rhs);
654 }
655
656 /**
657 * Returns a comprehensive string representation of this element
658 */
659 std::string to_string() const noexcept;
660 };
661 constexpr uint32_t number(const file_stats::field_t rhs) noexcept {
662 return static_cast<uint32_t>(rhs);
663 }
664 constexpr file_stats::field_t operator~(const file_stats::field_t rhs) noexcept {
665 return static_cast<file_stats::field_t>(~number(rhs));
666 }
667 constexpr file_stats::field_t operator^(const file_stats::field_t lhs, const file_stats::field_t rhs) noexcept {
668 return static_cast<file_stats::field_t>(number(lhs) ^ number(rhs));
669 }
670 constexpr file_stats::field_t operator|(const file_stats::field_t lhs, const file_stats::field_t rhs) noexcept {
671 return static_cast<file_stats::field_t>(number(lhs) | number(rhs));
672 }
673 constexpr file_stats::field_t operator&(const file_stats::field_t lhs, const file_stats::field_t rhs) noexcept {
674 return static_cast<file_stats::field_t>(number(lhs) & number(rhs));
675 }
677 lhs = static_cast<file_stats::field_t>(number(lhs) | number(rhs));
678 return lhs;
679 }
681 lhs = static_cast<file_stats::field_t>(number(lhs) & number(rhs));
682 return lhs;
683 }
685 lhs = static_cast<file_stats::field_t>(number(lhs) ^ number(rhs));
686 return lhs;
687 }
688 constexpr bool operator==(const file_stats::field_t lhs, const file_stats::field_t rhs) noexcept {
689 return number(lhs) == number(rhs);
690 }
691 constexpr bool operator!=(const file_stats::field_t lhs, const file_stats::field_t rhs) noexcept {
692 return !(lhs == rhs);
693 }
694 constexpr bool is_set(const file_stats::field_t mask, const file_stats::field_t bits) noexcept {
695 return bits == (mask & bits);
696 }
697 std::string to_string(const file_stats::field_t mask) noexcept;
698
699 /**
700 * Create directory
701 * @param path full path to new directory
702 * @param mode fmode_t POSIX protection bits used, defaults to jau::fs::fmode_t::def_dir_prot
703 * @param verbose defaults to false
704 * @return true if successful, otherwise false
705 */
706 bool mkdir(const std::string& path, const fmode_t mode = jau::fs::fmode_t::def_dir_prot, const bool verbose = false) noexcept;
707
708 /**
709 * Touch the file with given atime and mtime and create file if not existing yet.
710 * @param path full path to file
711 * @param atime new access time
712 * @param mtime new modification time
713 * @param mode fmode_t POSIX protection bits used, defaults to jau::fs::fmode_t::def_file_prot
714 * @return true if successful, otherwise false
715 */
716 bool touch(const std::string& path, const jau::fraction_timespec& atime, const jau::fraction_timespec& mtime,
717 const fmode_t mode = jau::fs::fmode_t::def_file_prot) noexcept;
718
719 /**
720 * Touch the file with current time and create file if not existing yet.
721 * @param path full path to file
722 * @param mode fmode_t POSIX protection bits used, defaults to jau::fs::fmode_t::def_file_prot
723 * @return true if successful, otherwise false
724 */
725 bool touch(const std::string& path, const fmode_t mode = jau::fs::fmode_t::def_file_prot) noexcept;
726
727 /**
728 * `void consume_dir_item(const dir_item& item)`
729 */
730 typedef jau::function<void(const dir_item&)> consume_dir_item;
731
732 /**
733 * Returns a list of directory elements excluding `.` and `..` for the given path, non recursive.
734 *
735 * The custom consume_dir_item `digest` may also be used to filter the element, besides storing it.
736 *
737 * @param path path to directory
738 * @param digest consume_dir_item function to receive each directory item, e.g. `void consume_dir_item(const dir_item& item)`
739 * @return true if given path exists, is directory and is readable, otherwise false
740 */
741 bool get_dir_content(const std::string& path, const consume_dir_item& digest) noexcept;
742
743 /**
744 * Returns a list of directory elements excluding `.` and `..` for the given path, non recursive.
745 *
746 * The custom consume_dir_item `digest` may also be used to filter the element, besides storing it.
747 *
748 * @param dirfd file descriptor to given `path` left untouched as a copy is being used to retrieve the directory content.
749 * @param path path to directory
750 * @param digest consume_dir_item function to receive each directory item, e.g. `void consume_dir_item(const dir_item& item)`
751 * @return true if given path exists, is directory and is readable, otherwise false
752 */
753 bool get_dir_content(const int dirfd, const std::string& path, const consume_dir_item& digest) noexcept;
754
755 /**
756 * Filesystem traverse event used to call path_visitor for path elements from visit().
757 *
758 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
759 *
760 * @see path_visitor
761 * @see visit()
762 */
763 enum class traverse_event : uint16_t {
764 /** No value, neither file, symlink nor dir_entry or dir_exit. Implying an error state in file_stat, e.g. !file_stats::has_access(). */
765 none = 0,
766
767 /**
768 * Visiting a symbolic-link, either to a file or a non-existing entity. Not followed symbolic-links to a directory is expressed via dir_symlink.
769 *
770 * In case of a symbolic-link to an existing file, file is also set, i.e. file_symlink.
771 */
772 symlink = 1 << 0,
773
774 /** Visiting a file, may be in conjunction with symlink, i.e. file_symlink. */
775 file = 1 << 1,
776
777 /** Visiting a symlink to a file, i.e. symlink | file */
779
780 /**
781 * Visiting a symbolic-link to a directory which is not followed, i.e. traverse_options::follow_symlinks not set.
782 */
783 dir_symlink = 1 << 2,
784
785 /**
786 * Visiting a directory on entry, see traverse_options::dir_check_entry.
787 *
788 * This allows the path_visitor to deny traversal into the directory by returning false,
789 * otherwise continuing traversal.
790 */
791 dir_check_entry = 1 << 7,
792
793 /**
794 * Visiting a directory on entry, see traverse_options::dir_entry.
795 *
796 * If a directory is visited non-recursive, i.e. traverse_options::recursive not set,
797 * dir_entry and dir_exit are set, see dir_non_recursive.
798 *
799 * If a directory is a symbolic link which is not followed, i.e. traverse_options::follow_symlinks not set,
800 * dir_symlink is used instead.
801 */
802 dir_entry = 1 << 8,
803
804 /**
805 * Visiting a directory on exit, see traverse_options::dir_exit.
806 *
807 * If a directory is visited non-recursive, i.e. traverse_options::recursive not set,
808 * dir_entry and dir_exit are set, see dir_non_recursive.
809 *
810 * If a directory is a symbolic link which is not followed, i.e. traverse_options::follow_symlinks not set,
811 * dir_symlink is used instead.
812 */
813 dir_exit = 1 << 9,
814
815 /**
816 * Visiting a directory non-recursive, i.e. traverse_options::recursive not set.
817 *
818 * Value is a bit-mask of dir_entry | dir_exit
819 */
821 };
822 constexpr uint16_t number(const traverse_event rhs) noexcept {
823 return static_cast<uint16_t>(rhs);
824 }
825 constexpr traverse_event operator~(const traverse_event rhs) noexcept {
826 return static_cast<traverse_event>(~number(rhs));
827 }
828 constexpr traverse_event operator^(const traverse_event lhs, const traverse_event rhs) noexcept {
829 return static_cast<traverse_event>(number(lhs) ^ number(rhs));
830 }
831 constexpr traverse_event operator|(const traverse_event lhs, const traverse_event rhs) noexcept {
832 return static_cast<traverse_event>(number(lhs) | number(rhs));
833 }
834 constexpr traverse_event operator&(const traverse_event lhs, const traverse_event rhs) noexcept {
835 return static_cast<traverse_event>(number(lhs) & number(rhs));
836 }
837 constexpr traverse_event& operator|=(traverse_event& lhs, const traverse_event rhs) noexcept {
838 lhs = static_cast<traverse_event>(number(lhs) | number(rhs));
839 return lhs;
840 }
841 constexpr traverse_event& operator&=(traverse_event& lhs, const traverse_event rhs) noexcept {
842 lhs = static_cast<traverse_event>(number(lhs) & number(rhs));
843 return lhs;
844 }
845 constexpr traverse_event& operator^=(traverse_event& lhs, const traverse_event rhs) noexcept {
846 lhs = static_cast<traverse_event>(number(lhs) ^ number(rhs));
847 return lhs;
848 }
849 constexpr bool operator==(const traverse_event lhs, const traverse_event rhs) noexcept {
850 return number(lhs) == number(rhs);
851 }
852 constexpr bool operator!=(const traverse_event lhs, const traverse_event rhs) noexcept {
853 return !(lhs == rhs);
854 }
855 constexpr bool is_set(const traverse_event mask, const traverse_event bit) noexcept {
856 return bit == (mask & bit);
857 }
858 std::string to_string(const traverse_event mask) noexcept;
859
860 /**
861 * path_visitor jau::FunctionDef definition
862 * - `bool visitor(traverse_event tevt, const file_stats& item_stats, size_t depth)`
863 *
864 * Depth being the recursive directory depth starting with 1 for the initial directory.
865 *
866 * Returning `false` stops traversal in general but traverse_options::dir_check_entry
867 * will only skip traversing the denied directory.
868 */
869 typedef jau::function<bool(traverse_event, const file_stats&, size_t)> path_visitor;
870
871 /**
872 * Filesystem traverse options used to visit() path elements.
873 *
874 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
875 *
876 * @see visit()
877 * @see remove()
878 */
879 enum class traverse_options : uint16_t {
880 /** No option set */
881 none = 0,
882
883 /** Traverse through directories, i.e. perform visit, copy, remove etc actions recursively throughout the directory structure. */
884 recursive = 1 << 0,
885
886 /** Traverse through symbolic linked directories if traverse_options::recursive is set, i.e. directories with property fmode_t::link set. */
887 follow_symlinks = 1 << 1,
888
889 /** Traverse through elements in lexicographical order. This might be required when computing an order dependent outcome like a hash value. */
890 lexicographical_order = 1 << 2,
891
892 /** Call path_visitor at directory entry, allowing path_visitor to skip traversal of this directory if returning false. */
893 dir_check_entry = 1 << 7,
894
895 /** Call path_visitor at directory entry. Both, dir_entry and dir_exit can be set, only one or none. */
896 dir_entry = 1 << 8,
897
898 /** Call path_visitor at directory exit. Both, dir_entry and dir_exit can be set, only one or none. */
899 dir_exit = 1 << 9,
900
901 /** Enable verbosity mode, potentially used by a path_visitor implementation like remove(). */
902 verbose = 1 << 15
903 };
904 constexpr uint16_t number(const traverse_options rhs) noexcept {
905 return static_cast<uint16_t>(rhs);
906 }
907 constexpr traverse_options operator~(const traverse_options rhs) noexcept {
908 return static_cast<traverse_options>(~number(rhs));
909 }
910 constexpr traverse_options operator^(const traverse_options lhs, const traverse_options rhs) noexcept {
911 return static_cast<traverse_options>(number(lhs) ^ number(rhs));
912 }
913 constexpr traverse_options operator|(const traverse_options lhs, const traverse_options rhs) noexcept {
914 return static_cast<traverse_options>(number(lhs) | number(rhs));
915 }
916 constexpr traverse_options operator&(const traverse_options lhs, const traverse_options rhs) noexcept {
917 return static_cast<traverse_options>(number(lhs) & number(rhs));
918 }
919 constexpr traverse_options& operator|=(traverse_options& lhs, const traverse_options rhs) noexcept {
920 lhs = static_cast<traverse_options>(number(lhs) | number(rhs));
921 return lhs;
922 }
923 constexpr traverse_options& operator&=(traverse_options& lhs, const traverse_options rhs) noexcept {
924 lhs = static_cast<traverse_options>(number(lhs) & number(rhs));
925 return lhs;
926 }
927 constexpr traverse_options& operator^=(traverse_options& lhs, const traverse_options rhs) noexcept {
928 lhs = static_cast<traverse_options>(number(lhs) ^ number(rhs));
929 return lhs;
930 }
931 constexpr bool operator==(const traverse_options lhs, const traverse_options rhs) noexcept {
932 return number(lhs) == number(rhs);
933 }
934 constexpr bool operator!=(const traverse_options lhs, const traverse_options rhs) noexcept {
935 return !(lhs == rhs);
936 }
937 constexpr bool is_set(const traverse_options mask, const traverse_options bit) noexcept {
938 return bit == (mask & bit);
939 }
940 std::string to_string(const traverse_options mask) noexcept;
941
942 /**
943 * Visit element(s) of a given path, see traverse_options for detailed settings.
944 *
945 * All elements of type fmode_t::file, fmode_t::dir and fmode_t::no_access or fmode_t::not_existing
946 * will be visited by the given path_visitor `visitor`.
947 *
948 * Depth passed to path_visitor is the recursive directory depth and starts with 1 for the initial directory.
949 *
950 * path_visitor returning `false` stops traversal in general but traverse_options::dir_check_entry
951 * will only skip traversing the denied directory.
952 *
953 * @param path the starting path
954 * @param topts given traverse_options for this operation
955 * @param visitor path_visitor function `bool visitor(const file_stats& item_stats, size_t depth)`.
956 * @param dirfds optional empty `dirfd` stack pointer defaults to nullptr.
957 * If user provided, exposes the used `dirfd` stack, which last entry represents the currently visited directory.
958 * The `dirfd` stack starts and ends empty, i.e. all directory file descriptor are closed.
959 * In case of recursive directory traversion, the initial dir_entry visit starts with depth 1 and 2 fds, its parent and current directory.
960 * @return true if successful including no path_visitor stopped traversal by returning `false` excluding traverse_options::dir_check_entry.
961 */
962 bool visit(const std::string& path, const traverse_options topts, const path_visitor& visitor, std::vector<int>* dirfds = nullptr) noexcept;
963
964 /**
965 * Visit element(s) of a given path, see traverse_options for detailed settings.
966 *
967 * All elements of type fmode_t::file, fmode_t::dir and fmode_t::no_access or fmode_t::not_existing
968 * will be visited by the given path_visitor `visitor`.
969 *
970 * Depth passed to path_visitor is the recursive directory depth and starts with 1 for the initial directory.
971 *
972 * path_visitor returning `false` stops traversal in general but traverse_options::dir_check_entry
973 * will only skip traversing the denied directory.
974 *
975 * @param item_stats pre-fetched file_stats for a given dir_item, used for efficiency
976 * @param topts given traverse_options for this operation
977 * @param visitor path_visitor function `bool visitor(const file_stats& item_stats, size_t depth)`.
978 * @param dirfds optional empty `dirfd` stack pointer defaults to nullptr.
979 * If user provided, exposes the used `dirfd` stack, which last entry represents the currently visited directory.
980 * The `dirfd` stack starts and ends empty, i.e. all directory file descriptor are closed.
981 * In case of recursive directory traversion, the initial dir_entry visit starts with depth 1 and 2 fds, its parent and current directory.
982 * @return true if successful including no path_visitor stopped traversal by returning `false` excluding traverse_options::dir_check_entry.
983 */
984 bool visit(const file_stats& item_stats, const traverse_options topts, const path_visitor& visitor, std::vector<int>* dirfds = nullptr) noexcept;
985
986 /**
987 * Remove the given path. If path represents a director, `recursive` must be set to true.
988 *
989 * The given traverse_options `options` are handled as follows:
990 * - traverse_options::parent_dir_last will be added by implementation to operate correct
991 * - traverse_options::recursive shall shall be set by caller to remove directories
992 * - traverse_options::follow_symlinks shall be set by caller to remove symbolic linked directories recursively, which is kind of dangerous.
993 * If not set, only the symbolic link will be removed (default)
994 *
995 * Implementation is most data-race-free (DRF), utilizes following safeguards
996 * - utilizing parent directory file descriptor and `openat()` and `unlinkat()` operations against concurrent mutation
997 *
998 * @param path path to remove
999 * @param topts given traverse_options for this operation, defaults to traverse_options::none
1000 * @return true only if the file or the directory with content has been deleted, otherwise false
1001 */
1002 bool remove(const std::string& path, const traverse_options topts = traverse_options::none) noexcept;
1003
1004 /**
1005 * Compare the bytes of both files, denoted by source1 and source2.
1006 *
1007 * @param source1 first source file to compare
1008 * @param source2 second source file to compare
1009 * @param verbose defaults to false
1010 * @return true if both elements are files and their bytes are equal, otherwise false.
1011 */
1012 bool compare(const file_stats& source1, const file_stats& source2, const bool verbose = false) noexcept;
1013
1014 /**
1015 * Compare the bytes of both files, denoted by source1 and source2.
1016 *
1017 * @param source1 first source file to compare
1018 * @param source2 second source file to compare
1019 * @param verbose defaults to false
1020 * @return true if both elements are files and their bytes are equal, otherwise false.
1021 */
1022 bool compare(const std::string& source1, const std::string& source2, const bool verbose = false) noexcept;
1023
1024 /**
1025 * Filesystem copy options used to copy() path elements.
1026 *
1027 * By default, the fmode_t POSIX protection mode bits are preserved
1028 * while using the caller's uid and gid as well as current timestamps. <br />
1029 * Use copy_options::preserve_all to preserve uid and gid if allowed from the caller and access- and modification-timestamps.
1030 *
1031 * This `enum class` type fulfills `C++ named requirements: BitmaskType`.
1032 *
1033 * @see copy()
1034 */
1035 enum class copy_options : uint16_t {
1036 /** No option set */
1037 none = 0,
1038
1039 /** Traverse through directories, i.e. perform visit, copy, remove etc actions recursively throughout the directory structure. */
1040 recursive = 1 << 0,
1041
1042 /** Copy referenced symbolic linked files or directories instead of just the symbolic link with property fmode_t::link set. */
1043 follow_symlinks = 1 << 1,
1044
1045 /**
1046 * Copy source dir content into an already existing destination directory as if destination directory did not exist.
1047 *
1048 * Otherwise, if destination directory already exist, the source directory will be copied below the destination directory.
1049 */
1050 into_existing_dir = 1 << 2,
1051
1052 /**
1053 * Ignore errors from erroneous symlinks, e.g. non-existing link-targets, recursive loop-errors.or unsupported symmlinks on target filesystem.
1054 *
1055 * This flag is required to
1056 * - copy erroneous non-existing symlinks if using follow_symlinks
1057 * - copy erroneous recursive loop-error symlinks if using follow_symlinks
1058 * - ignore symlinks if not supported by target filesystem if not using follow_symlinks
1059 */
1060 ignore_symlink_errors = 1 << 8,
1061
1062 /** Overwrite existing destination files. */
1063 overwrite = 1 << 9,
1064
1065 /** Preserve uid and gid if allowed and access- and modification-timestamps, i.e. producing a most exact meta-data copy. */
1066 preserve_all = 1 << 10,
1067
1068 /** Ensure data and meta-data file synchronization is performed via ::fsync() after asynchronous copy operations of a file's content. */
1069 sync = 1 << 11,
1070
1071 /** Enable verbosity mode, show error messages on stderr. */
1072 verbose = 1 << 15
1073 };
1074 constexpr uint16_t number(const copy_options rhs) noexcept {
1075 return static_cast<uint16_t>(rhs);
1076 }
1077 constexpr copy_options operator~(const copy_options rhs) noexcept {
1078 return static_cast<copy_options>(~number(rhs));
1079 }
1080 constexpr copy_options operator^(const copy_options lhs, const copy_options rhs) noexcept {
1081 return static_cast<copy_options>(number(lhs) ^ number(rhs));
1082 }
1083 constexpr copy_options operator|(const copy_options lhs, const copy_options rhs) noexcept {
1084 return static_cast<copy_options>(number(lhs) | number(rhs));
1085 }
1086 constexpr copy_options operator&(const copy_options lhs, const copy_options rhs) noexcept {
1087 return static_cast<copy_options>(number(lhs) & number(rhs));
1088 }
1089 constexpr copy_options& operator|=(copy_options& lhs, const copy_options rhs) noexcept {
1090 lhs = static_cast<copy_options>(number(lhs) | number(rhs));
1091 return lhs;
1092 }
1093 constexpr copy_options& operator&=(copy_options& lhs, const copy_options rhs) noexcept {
1094 lhs = static_cast<copy_options>(number(lhs) & number(rhs));
1095 return lhs;
1096 }
1097 constexpr copy_options& operator^=(copy_options& lhs, const copy_options rhs) noexcept {
1098 lhs = static_cast<copy_options>(number(lhs) ^ number(rhs));
1099 return lhs;
1100 }
1101 constexpr bool operator==(const copy_options lhs, const copy_options rhs) noexcept {
1102 return number(lhs) == number(rhs);
1103 }
1104 constexpr bool operator!=(const copy_options lhs, const copy_options rhs) noexcept {
1105 return !(lhs == rhs);
1106 }
1107 constexpr bool is_set(const copy_options mask, const copy_options bit) noexcept {
1108 return bit == (mask & bit);
1109 }
1110 std::string to_string(const copy_options mask) noexcept;
1111
1112 /**
1113 * Copy the given source_path to dest_path using copy_options.
1114 *
1115 * The behavior is similar like POSIX `cp` commandline tooling.
1116 *
1117 * The following behavior is being followed regarding dest_path:
1118 * - If source_path is a directory and copy_options::recursive set
1119 * - If dest_path doesn't exist, source_path dir content is copied into the newly created dest_path.
1120 * - If dest_path exists as a directory, source_path dir will be copied below the dest_path directory
1121 * _if_ copy_options::into_existing_dir is not set. Otherwise its content is copied into the existing dest_path.
1122 * - Everything else is considered an error
1123 * - If source_path is a file
1124 * - If dest_path doesn't exist, source_path file is copied to dest_path as a file.
1125 * - If dest_path exists as a directory, source_path file will be copied below the dest_path directory.
1126 * - If dest_path exists as a file, copy_options::overwrite must be set to have it overwritten by the source_path file
1127 * - Everything else is considered an error
1128 *
1129 * Implementation either uses ::sendfile() if running under `GNU/Linux`,
1130 * otherwise POSIX ::read() and ::write().
1131 *
1132 * Implementation is most data-race-free (DRF), utilizes following safeguards on recursive directory copy
1133 * - utilizing parent directory file descriptor and `openat()` operations against concurrent mutation
1134 * - for each entered *directory*
1135 * - new destination directory is create with '.<random_number>' and user-rwx permissions only
1136 * - its file descriptor is being opened
1137 * - its user-read permission is dropped, remains user-wx permissions only
1138 * - its renamed to destination path
1139 * - all copy operations are performed inside
1140 * - at exit, its permissions are restored, etc.
1141 *
1142 * See copy_options for details.
1143 *
1144 * @param source_path
1145 * @param dest_path
1146 * @param copts
1147 * @return true if successful, otherwise false
1148 */
1149 bool copy(const std::string& source_path, const std::string& dest_path, const copy_options copts = copy_options::none) noexcept;
1150
1151 /**
1152 * Rename oldpath to newpath using POSIX `::rename()`, with the following combinations
1153 * - oldpath and newpath refer to the same file, a successful no-operation.
1154 * - oldpath file
1155 * - newpath not-existing file
1156 * - newpath existing file to be atomically replaced
1157 * - oldpath directory
1158 * - newpath not-existing directory
1159 * - newpath existing empty directory
1160 * - oldpath symlink will be renamed
1161 * - newpath symlink will be overwritten
1162 *
1163 * @param oldpath previous path
1164 * @param newpath new path
1165 * @return true only if the rename operation was successful, otherwise false
1166 */
1167 bool rename(const std::string& oldpath, const std::string& newpath) noexcept;
1168
1169 /**
1170 * Synchronizes filesystems, i.e. all pending modifications to filesystem metadata and cached file data will be written to the underlying filesystems.
1171 */
1172 void sync() noexcept;
1173
1174 struct mount_ctx {
1176 std::string target;
1178
1179 mount_ctx(std::string target_, const int loop_device_id_)
1180 : mounted(true), target(std::move(target_)), loop_device_id(loop_device_id_) {}
1181
1183 : mounted(false), target(), loop_device_id(-1) {}
1184 };
1185
1186 /**
1187 * Generic flag bit values for mount() `flags`.
1188 *
1189 * See mount(2) for a detailed description.
1190 */
1191 typedef uint64_t mountflags_t;
1192
1193 /**
1194 * Flag bit values for mount() `flags` under GNU/Linux.
1195 *
1196 * See mount(2) for a detailed description.
1197 */
1199 none = 0,
1200 rdonly = 1,
1201 nosuid = 2,
1202 nodev = 4,
1203 noexec = 8,
1204 synchronous = 16,
1205 remount = 32,
1206 mandlock = 64,
1207 dirsync = 128,
1208 noatime = 1024,
1209 nodiratime = 2048,
1210 bind = 4096,
1211 move = 8192,
1212 rec = 16384,
1213 silent = 32768,
1214 posixacl = 1 << 16,
1215 unbindable = 1 << 17,
1216 private_ = 1 << 18,
1217 slave = 1 << 19,
1218 shared = 1 << 20,
1219 relatime = 1 << 21,
1220 kernmount = 1 << 22,
1221 i_version = 1 << 23,
1222 strictatime = 1 << 24,
1223 lazytime = 1 << 25,
1224 active = 1 << 30,
1225 nouser = 1UL << 31
1226 };
1227 constexpr mountflags_t number(const mountflags_linux rhs) noexcept {
1228 return static_cast<mountflags_t>(rhs);
1229 }
1230 constexpr mountflags_linux operator~(const mountflags_linux rhs) noexcept {
1231 return static_cast<mountflags_linux>(~number(rhs));
1232 }
1233 constexpr mountflags_linux operator^(const mountflags_linux lhs, const mountflags_linux rhs) noexcept {
1234 return static_cast<mountflags_linux>(number(lhs) ^ number(rhs));
1235 }
1236 constexpr mountflags_linux operator|(const mountflags_linux lhs, const mountflags_linux rhs) noexcept {
1237 return static_cast<mountflags_linux>(number(lhs) | number(rhs));
1238 }
1239 constexpr mountflags_linux operator&(const mountflags_linux lhs, const mountflags_linux rhs) noexcept {
1240 return static_cast<mountflags_linux>(number(lhs) & number(rhs));
1241 }
1242 constexpr mountflags_linux& operator|=(mountflags_linux& lhs, const mountflags_linux rhs) noexcept {
1243 lhs = static_cast<mountflags_linux>(number(lhs) | number(rhs));
1244 return lhs;
1245 }
1246 constexpr mountflags_linux& operator&=(mountflags_linux& lhs, const mountflags_linux rhs) noexcept {
1247 lhs = static_cast<mountflags_linux>(number(lhs) & number(rhs));
1248 return lhs;
1249 }
1250 constexpr mountflags_linux& operator^=(mountflags_linux& lhs, const mountflags_linux rhs) noexcept {
1251 lhs = static_cast<mountflags_linux>(number(lhs) ^ number(rhs));
1252 return lhs;
1253 }
1254 constexpr bool operator==(const mountflags_linux lhs, const mountflags_linux rhs) noexcept {
1255 return number(lhs) == number(rhs);
1256 }
1257 constexpr bool operator!=(const mountflags_linux lhs, const mountflags_linux rhs) noexcept {
1258 return !(lhs == rhs);
1259 }
1260 constexpr bool is_set(const mountflags_linux mask, const mountflags_linux bit) noexcept {
1261 return bit == (mask & bit);
1262 }
1263 constexpr mountflags_t& operator|=(mountflags_t& lhs, const mountflags_linux rhs) noexcept {
1264 lhs |= number(rhs);
1265 return lhs;
1266 }
1267 constexpr mountflags_t& operator&=(mountflags_t& lhs, const mountflags_linux rhs) noexcept {
1268 lhs &= number(rhs);
1269 return lhs;
1270 }
1271 constexpr mountflags_t& operator^=(mountflags_t& lhs, const mountflags_linux rhs) noexcept {
1272 lhs ^= number(rhs);
1273 return lhs;
1274 }
1275
1276 /**
1277 * Attach the filesystem image named in `image_path` to `target`
1278 * using an intermediate platform specific filesystem image loop-device.
1279 *
1280 * This method either requires root permissions <br />
1281 * or the following capabilities: `cap_sys_admin`,`cap_setuid`, `cap_setgid`.
1282 *
1283 * Unmounting shall be done via umount() with mount_ctx argument to ensure
1284 * all intermediate resources are released.
1285 *
1286 * @param image_path path of image source file
1287 * @param target directory where `image_path` filesystem shall be attached to
1288 * @param fs_type type of filesystem, e.g. `squashfs`, `tmpfs`, `iso9660`, etc.
1289 * @param flags filesystem agnostic mount flags, see mountflags_linux.
1290 * @param fs_options comma separated options for the filesystem `fs_type`, see mount(8) for available options for the used filesystem.
1291 * @return mount_ctx structure containing mounted status etc
1292 *
1293 * @see mountflags_t
1294 * @see mountflags_linux
1295 * @see mount()
1296 * @see umount()
1297 */
1298 mount_ctx mount_image(const std::string& image_path, const std::string& target, const std::string& fs_type,
1299 const mountflags_t flags, const std::string& fs_options = "");
1300
1301 /**
1302 * Attach the filesystem named in `source` to `target`
1303 * using the given filesystem source directly.
1304 *
1305 * This method either requires root permissions <br />
1306 * or the following capabilities: `cap_sys_admin`,`cap_setuid`, `cap_setgid`.
1307 *
1308 * @param source filesystem path for device, directory, file or dummy-string which shall be attached
1309 * @param target directory where `source` filesystem shall be attached to
1310 * @param fs_type type of filesystem, e.g. `squashfs`, `tmpfs`, `iso9660`, etc.
1311 * @param flags filesystem agnostic mount flags, see mountflags_linux.
1312 * @param fs_options comma separated options for the filesystem `fs_type`, see mount(8) for available options for the used filesystem.
1313 * @return mount_ctx structure containing mounted status etc
1314 *
1315 * @see mountflags_t
1316 * @see mountflags_linux
1317 * @see mount_image()
1318 * @see umount()
1319 */
1320 mount_ctx mount(const std::string& source, const std::string& target, const std::string& fs_type,
1321 const mountflags_t flags, const std::string& fs_options = "");
1322
1323 /**
1324 * Generic flag bit values for umount() `flags`.
1325 *
1326 * See umount(2) for a detailed description.
1327 */
1328 typedef int umountflags_t;
1329
1330 /**
1331 * Flag bit values for umount() `flags` under GNU/Linux.
1332 *
1333 * See umount(2) for a detailed description.
1334 */
1336 force = 1,
1337 detach = 2,
1338 expire = 4,
1339 nofollow = 8
1340 };
1341 constexpr umountflags_t number(const umountflags_linux rhs) noexcept {
1342 return static_cast<umountflags_t>(rhs);
1343 }
1344 constexpr umountflags_linux operator~(const umountflags_linux rhs) noexcept {
1345 return static_cast<umountflags_linux>(~number(rhs));
1346 }
1347 constexpr umountflags_linux operator^(const umountflags_linux lhs, const umountflags_linux rhs) noexcept {
1348 return static_cast<umountflags_linux>(number(lhs) ^ number(rhs));
1349 }
1350 constexpr umountflags_linux operator|(const umountflags_linux lhs, const umountflags_linux rhs) noexcept {
1351 return static_cast<umountflags_linux>(number(lhs) | number(rhs));
1352 }
1353 constexpr umountflags_linux operator&(const umountflags_linux lhs, const umountflags_linux rhs) noexcept {
1354 return static_cast<umountflags_linux>(number(lhs) & number(rhs));
1355 }
1357 lhs = static_cast<umountflags_linux>(number(lhs) | number(rhs));
1358 return lhs;
1359 }
1361 lhs = static_cast<umountflags_linux>(number(lhs) & number(rhs));
1362 return lhs;
1363 }
1365 lhs = static_cast<umountflags_linux>(number(lhs) ^ number(rhs));
1366 return lhs;
1367 }
1368 constexpr bool operator==(const umountflags_linux lhs, const umountflags_linux rhs) noexcept {
1369 return number(lhs) == number(rhs);
1370 }
1371 constexpr bool operator!=(const umountflags_linux lhs, const umountflags_linux rhs) noexcept {
1372 return !(lhs == rhs);
1373 }
1374 constexpr bool is_set(const umountflags_linux mask, const umountflags_linux bit) noexcept {
1375 return bit == (mask & bit);
1376 }
1377 constexpr umountflags_t& operator|=(umountflags_t& lhs, const umountflags_linux rhs) noexcept {
1378 lhs |= number(rhs);
1379 return lhs;
1380 }
1381 constexpr umountflags_t& operator&=(umountflags_t& lhs, const umountflags_linux rhs) noexcept {
1382 lhs &= number(rhs);
1383 return lhs;
1384 }
1385 constexpr umountflags_t& operator^=(umountflags_t& lhs, const umountflags_linux rhs) noexcept {
1386 lhs ^= number(rhs);
1387 return lhs;
1388 }
1389
1390 /**
1391 * Detach the given mount_ctx `context`
1392 *
1393 * This method either requires root permissions <br />
1394 * or the following capabilities: `cap_sys_admin`,`cap_setuid`, `cap_setgid`.
1395 *
1396 * @param context mount_ctx previously attached via mount_image() or mount()
1397 * @param flags optional umount options, if supported by the system. See umount_options_linux.
1398 * @return true if successful, otherwise false
1399 *
1400 * @see umountflags_t
1401 * @see umountflags_linux
1402 * @see mount()
1403 * @see mount_image()
1404 */
1405 bool umount(const mount_ctx& context, const umountflags_t flags);
1406
1407 /**
1408 * Detach the topmost filesystem mounted on `target`
1409 * optionally using given `umountflags` options if supported.
1410 *
1411 * This method either requires root permissions <br />
1412 * or the following capabilities: `cap_sys_admin`,`cap_setuid`, `cap_setgid`.
1413 *
1414 * @param target directory of previously attached filesystem
1415 * @param flags optional umount options, if supported by the system. See umount_options_linux.
1416 * @return true if successful, otherwise false
1417 *
1418 * @see umountflags_t
1419 * @see umountflags_linux
1420 * @see mount()
1421 * @see mount_image()
1422 */
1423 bool umount(const std::string& target, const umountflags_t flags);
1424
1425 /**@}*/
1426
1427} // namespace jau::fs
1428
1429#endif /* JAU_FILE_UTIL_HPP_ */
Representing a directory item split into dirname() and basename().
Definition: file_util.hpp:90
std::string path() const noexcept
Returns a full unix path representation combining dirname() and basename().
Definition: file_util.cpp:321
const std::string & basename() const noexcept
Return the basename, shall not be empty nor contain a dirname.
Definition: file_util.hpp:199
bool operator!=(const dir_item &rhs) const noexcept
Definition: file_util.hpp:215
bool empty() const noexcept
Returns true if bot, dirname() and basename() refer to .
Definition: file_util.hpp:209
std::string to_string() const noexcept
Returns a comprehensive string representation of this item.
Definition: file_util.cpp:334
dir_item() noexcept
Empty item w/ .
Definition: file_util.cpp:313
bool operator==(const dir_item &rhs) const noexcept
Definition: file_util.hpp:211
const std::string & dirname() const noexcept
Returns the dirname, shall not be empty and denotes .
Definition: file_util.hpp:196
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
Definition: file_util.hpp:406
constexpr bool is_char() const noexcept
Returns true if entity is a character device, might be in combination with is_link().
Definition: file_util.hpp:630
int fd() const noexcept
Returns the file descriptor if has_fd(), otherwise -1 for no file descriptor.
Definition: file_util.hpp:584
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
Definition: file_util.hpp:648
fmode_t type_mode() const noexcept
Returns the type bit portion of fmode_t, i.e.
Definition: file_util.hpp:577
constexpr bool has_fd() const noexcept
Returns true if entity has a file descriptor.
Definition: file_util.hpp:621
const fraction_timespec & mtime() const noexcept
Returns the last modification time of this element since Unix Epoch.
Definition: file_util.hpp:606
constexpr bool is_fifo() const noexcept
Returns true if entity is a fifo/pipe, might be in combination with is_link().
Definition: file_util.hpp:633
constexpr bool is_link() const noexcept
Returns true if entity is a symbolic link, might be in combination with is_file(),...
Definition: file_util.hpp:642
constexpr bool is_file() const noexcept
Returns true if entity is a file, might be in combination with is_link().
Definition: file_util.hpp:639
const fraction_timespec & ctime() const noexcept
Returns the last status change time of this element since Unix Epoch.
Definition: file_util.hpp:604
gid_t gid() const noexcept
Returns the group id, owning the element.
Definition: file_util.hpp:590
constexpr bool is_dir() const noexcept
Returns true if entity is a directory, might be in combination with is_link().
Definition: file_util.hpp:636
field_t
Field identifier which bit-mask indicates field_t fields.
Definition: file_util.hpp:411
uint64_t size() const noexcept
Returns the size in bytes of this element if is_file(), otherwise zero.
Definition: file_util.hpp:597
constexpr bool is_socket() const noexcept
Returns true if entity is a socket, might be in combination with is_link().
Definition: file_util.hpp:624
const fraction_timespec & btime() const noexcept
Returns the birth time of this element since Unix Epoch, i.e.
Definition: file_util.hpp:600
constexpr bool has_access() const noexcept
Returns true if entity gives no access to user, exclusive bit.
Definition: file_util.hpp:645
constexpr bool ok() const noexcept
Returns true if no error occurred.
Definition: file_util.hpp:612
const std::shared_ptr< std::string > & link_target_path() const noexcept
Returns the stored link-target path this symbolic-link points to if instance is a symbolic-link,...
Definition: file_util.hpp:539
fmode_t mode() const noexcept
Returns the fmode_t, file type and mode.
Definition: file_util.hpp:571
const std::shared_ptr< file_stats > & link_target() const noexcept
Returns the link-target this symbolic-link points to if instance is a symbolic-link,...
Definition: file_util.hpp:550
uid_t uid() const noexcept
Returns the user id, owning the element.
Definition: file_util.hpp:587
constexpr int errno_res() const noexcept
Returns the errno value occurred to produce this instance, or zero for no error.
Definition: file_util.hpp:609
bool operator!=(const file_stats &rhs) const noexcept
Definition: file_util.hpp:652
fmode_t prot_mode() const noexcept
Returns the POSIX protection bit portion of fmode_t, i.e.
Definition: file_util.hpp:574
const fraction_timespec & atime() const noexcept
Returns the last access time of this element since Unix Epoch.
Definition: file_util.hpp:602
constexpr bool is_block() const noexcept
Returns true if entity is a block device, might be in combination with is_link().
Definition: file_util.hpp:627
std::string path() const noexcept
Returns the unix path representation.
Definition: file_util.hpp:530
Class template jau::function is a general-purpose static-polymorphic function wrapper.
bool mkdir(const std::string &path, const fmode_t mode=jau::fs::fmode_t::def_dir_prot, const bool verbose=false) noexcept
Create directory.
Definition: file_util.cpp:909
uint64_t mountflags_t
Generic flag bit values for mount() flags.
Definition: file_util.hpp:1191
std::string to_named_fd(const int fd) noexcept
Returns platform dependent named file descriptor of given file descriptor, if supported.
Definition: file_util.cpp:401
mount_ctx mount(const std::string &source, const std::string &target, const std::string &fs_type, const mountflags_t flags, const std::string &fs_options="")
Attach the filesystem named in source to target using the given filesystem source directly.
Definition: file_util.cpp:2071
mount_ctx mount_image(const std::string &image_path, const std::string &target, const std::string &fs_type, const mountflags_t flags, const std::string &fs_options="")
Attach the filesystem image named in image_path to target using an intermediate platform specific fil...
Definition: file_util.cpp:1944
constexpr fmode_t operator&(const fmode_t lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:321
constexpr fmode_t operator|(const fmode_t lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:318
bool copy(const std::string &source_path, const std::string &dest_path, const copy_options copts=copy_options::none) noexcept
Copy the given source_path to dest_path using copy_options.
Definition: file_util.cpp:1720
fmode_t
Generic file type and POSIX protection mode bits as used in file_stats, touch(), mkdir() etc.
Definition: file_util.hpp:236
constexpr fmode_t operator^(const fmode_t lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:315
std::string basename(const std::string_view &path) noexcept
Return stripped leading directory components from given path separated by /.
Definition: file_util.cpp:151
mountflags_linux
Flag bit values for mount() flags under GNU/Linux.
Definition: file_util.hpp:1198
std::string get_cwd() noexcept
Return the current working directory or empty on failure.
Definition: file_util.cpp:82
constexpr uint32_t number(const fmode_t rhs) noexcept
Definition: file_util.hpp:309
bool compare(const file_stats &source1, const file_stats &source2, const bool verbose=false) noexcept
Compare the bytes of both files, denoted by source1 and source2.
Definition: file_util.cpp:1268
bool visit(const std::string &path, const traverse_options topts, const path_visitor &visitor, std::vector< int > *dirfds=nullptr) noexcept
Visit element(s) of a given path, see traverse_options for detailed settings.
Definition: file_util.cpp:1169
std::string absolute(const std::string_view &relpath) noexcept
Returns the absolute path of given relpath if existing, otherwise an empty string.
Definition: file_util.cpp:102
int umountflags_t
Generic flag bit values for umount() flags.
Definition: file_util.hpp:1328
constexpr fmode_t & operator|=(fmode_t &lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:324
std::string dirname(const std::string_view &path) noexcept
Return stripped last component from given path separated by /, excluding the trailing separator /.
Definition: file_util.cpp:129
copy_options
Filesystem copy options used to copy() path elements.
Definition: file_util.hpp:1035
bool get_dir_content(const std::string &path, const consume_dir_item &digest) noexcept
Returns a list of directory elements excluding .
Definition: file_util.cpp:966
bool touch(const std::string &path, const jau::fraction_timespec &atime, const jau::fraction_timespec &mtime, const fmode_t mode=jau::fs::fmode_t::def_file_prot) noexcept
Touch the file with given atime and mtime and create file if not existing yet.
Definition: file_util.cpp:931
traverse_options
Filesystem traverse options used to visit() path elements.
Definition: file_util.hpp:879
bool rename(const std::string &oldpath, const std::string &newpath) noexcept
Rename oldpath to newpath using POSIX rename(), with the following combinations.
Definition: file_util.cpp:1916
constexpr fmode_t & operator&=(fmode_t &lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:328
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
Definition: file_util.cpp:1173
void sync() noexcept
Synchronizes filesystems, i.e.
Definition: file_util.cpp:1932
int from_named_fd(const std::string &named_fd) noexcept
Returns the file descriptor from the given named file descriptor.
Definition: file_util.cpp:410
constexpr bool is_set(const fmode_t mask, const fmode_t bits) noexcept
Definition: file_util.hpp:342
bool umount(const mount_ctx &context, const umountflags_t flags)
Detach the given mount_ctx context
Definition: file_util.cpp:2143
constexpr fmode_t & operator^=(fmode_t &lhs, const fmode_t rhs) noexcept
Definition: file_util.hpp:332
umountflags_linux
Flag bit values for umount() flags under GNU/Linux.
Definition: file_util.hpp:1335
constexpr fmode_t operator~(const fmode_t rhs) noexcept
Definition: file_util.hpp:312
bool chdir(const std::string &path) noexcept
Change working directory.
Definition: file_util.cpp:98
bool isAbsolute(const std::string_view &path) noexcept
Returns true if first character is / or - in case of Windows - \\.
Definition: file_util.cpp:172
traverse_event
Filesystem traverse event used to call path_visitor for path elements from visit().
Definition: file_util.hpp:763
constexpr ::mode_t posix_protection_bits(const fmode_t mask) noexcept
Returns the POSIX protection bits: rwx_all | set_uid | set_gid | sticky, i.e.
Definition: file_util.hpp:354
jau::function< bool(traverse_event, const file_stats &, size_t)> path_visitor
path_visitor jau::FunctionDef definition
Definition: file_util.hpp:869
@ exec_usr
Protection bit: POSIX S_IXUSR.
@ exec_grp
Protection bit: POSIX S_IXGRP.
@ def_file_prot
Default file protection bit: Safe default: POSIX S_IRUSR | S_IWUSR | S_IRGRP or read_usr | write_usr ...
@ write_grp
Protection bit: POSIX S_IWGRP.
@ no_access
Type: Entity gives no access to user, exclusive bit.
@ set_uid
Protection bit: POSIX S_ISUID.
@ write_usr
Protection bit: POSIX S_IWUSR.
@ ugs_set
Protection bit: POSIX S_ISUID | S_ISGID | S_ISVTX.
@ link
Type: Entity is a symbolic link, might be in combination with file or dir, fifo, chr,...
@ sock
Type: Entity is a socket, might be in combination with link.
@ chr
Type: Entity is a character device, might be in combination with link.
@ rwx_oth
Protection bit: POSIX S_IRWXO.
@ sticky
Protection bit: POSIX S_ISVTX.
@ rwx_usr
Protection bit: POSIX S_IRWXU.
@ read_usr
Protection bit: POSIX S_IRUSR.
@ dir
Type: Entity is a directory, might be in combination with link.
@ rwx_all
Protection bit: POSIX S_IRWXU | S_IRWXG | S_IRWXO or rwx_usr | rwx_grp | rwx_oth.
@ file
Type: Entity is a file, might be in combination with link.
@ protection_mask
12 bit protection bit mask 07777 for rwx_all | set_uid | set_gid | sticky .
@ blk
Type: Entity is a block device, might be in combination with link.
@ read_grp
Protection bit: POSIX S_IRGRP.
@ read_oth
Protection bit: POSIX S_IROTH.
@ not_existing
Type: Entity does not exist, exclusive bit.
@ rwx_grp
Protection bit: POSIX S_IRWXG.
@ fifo
Type: Entity is a fifo/pipe, might be in combination with link.
@ write_oth
Protection bit: POSIX S_IWOTH.
@ set_gid
Protection bit: POSIX S_ISGID.
@ def_dir_prot
Default directory protection bit: Safe default: POSIX S_IRWXU | S_IRGRP | S_IXGRP or rwx_usr | read_g...
@ type_mask
Type mask for sock | blk | chr | fifo | dir | file | link | no_access | not_existing.
@ exec_oth
Protection bit: POSIX S_IXOTH.
@ ignore_symlink_errors
Ignore errors from erroneous symlinks, e.g.
@ none
No option set.
@ overwrite
Overwrite existing destination files.
@ preserve_all
Preserve uid and gid if allowed and access- and modification-timestamps, i.e.
@ into_existing_dir
Copy source dir content into an already existing destination directory as if destination directory di...
@ lexicographical_order
Traverse through elements in lexicographical order.
@ verbose
Enable verbosity mode, potentially used by a path_visitor implementation like remove().
@ follow_symlinks
Traverse through symbolic linked directories if traverse_options::recursive is set,...
@ recursive
Traverse through directories, i.e.
@ dir_symlink
Visiting a symbolic-link to a directory which is not followed, i.e.
@ dir_non_recursive
Visiting a directory non-recursive, i.e.
@ dir_check_entry
Visiting a directory on entry, see traverse_options::dir_check_entry.
@ dir_entry
Visiting a directory on entry, see traverse_options::dir_entry.
@ symlink
Visiting a symbolic-link, either to a file or a non-existing entity.
@ dir_exit
Visiting a directory on exit, see traverse_options::dir_exit.
@ file_symlink
Visiting a symlink to a file, i.e.
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2022 Gothel Software e.K.
Definition: file_util.hpp:39
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
STL namespace.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
std::string target
Definition: file_util.hpp:1176
mount_ctx(std::string target_, const int loop_device_id_)
Definition: file_util.hpp:1179