diff options
Diffstat (limited to 'libbutl/filesystem.hxx')
-rw-r--r-- | libbutl/filesystem.hxx | 164 |
1 files changed, 116 insertions, 48 deletions
diff --git a/libbutl/filesystem.hxx b/libbutl/filesystem.hxx index 8804b04..0f5fb0b 100644 --- a/libbutl/filesystem.hxx +++ b/libbutl/filesystem.hxx @@ -36,6 +36,32 @@ namespace butl { + // Path permissions. + // + enum class permissions: std::uint16_t + { + // Note: matching POSIX values. + // + xo = 0001, + wo = 0002, + ro = 0004, + + xg = 0010, + wg = 0020, + rg = 0040, + + xu = 0100, + wu = 0200, + ru = 0400, + + none = 0 + }; + + inline permissions operator& (permissions, permissions); + inline permissions operator| (permissions, permissions); + inline permissions operator&= (permissions&, permissions); + inline permissions operator|= (permissions&, permissions); + // Return true if the path is to an existing regular file. Note that by // default this function follows symlinks. Underlying OS errors are reported // by throwing std::system_error, unless ignore_error is true (in which case @@ -215,8 +241,8 @@ namespace butl // Movable-only type. Move-assignment cancels the lhs object. // - auto_rm (auto_rm&&); - auto_rm& operator= (auto_rm&&); + auto_rm (auto_rm&&) noexcept; + auto_rm& operator= (auto_rm&&) noexcept; auto_rm (const auto_rm&) = delete; auto_rm& operator= (const auto_rm&) = delete; @@ -381,11 +407,13 @@ namespace butl inline cpflags operator&= (cpflags&, cpflags); inline cpflags operator|= (cpflags&, cpflags); - // Copy a regular file, including its permissions, and optionally timestamps. - // Throw std::system_error on failure. Fail if the destination file exists - // and the overwrite_content flag is not set. Leave permissions of an - // existing destination file intact unless the overwrite_permissions flag is - // set. Delete incomplete copies before throwing. + // Copy a regular file, including its permissions (unless custom permissions + // are specified), and optionally timestamps. Throw std::system_error on + // failure. Fail if the destination file exists and the overwrite_content + // flag is not set. Leave permissions of an existing destination file intact + // (including if custom permissions are specified) unless the + // overwrite_permissions flag is set. Delete incomplete copies before + // throwing. // // Note that in case of overwriting, the existing destination file gets // truncated (not deleted) prior to being overwritten. As a side-effect, @@ -397,7 +425,10 @@ namespace butl // fail. // LIBBUTL_SYMEXPORT void - cpfile (const path& from, const path& to, cpflags = cpflags::none); + cpfile (const path& from, + const path& to, + cpflags = cpflags::none, + optional<permissions> perm = nullopt); // Copy a regular file into (inside) an existing directory. // @@ -605,32 +636,6 @@ namespace butl return dir_atime (p.string ().c_str (), t); } - // Path permissions. - // - enum class permissions: std::uint16_t - { - // Note: matching POSIX values. - // - xo = 0001, - wo = 0002, - ro = 0004, - - xg = 0010, - wg = 0020, - rg = 0040, - - xu = 0100, - wu = 0200, - ru = 0400, - - none = 0 - }; - - inline permissions operator& (permissions, permissions); - inline permissions operator| (permissions, permissions); - inline permissions operator&= (permissions&, permissions); - inline permissions operator|= (permissions&, permissions); - // Get path permissions. Throw std::system_error on failure. Note that this // function resolves symlinks. // @@ -652,12 +657,45 @@ namespace butl // Symlink target type in case of the symlink, ltype() otherwise. // + // If type() returns entry_type::unknown then this entry is inaccessible + // (ltype() also returns entry_type::unknown) or is a dangling symlink + // (ltype() returns entry_type::symlink). Used with the detect_dangling + // dir_iterator mode. Note that on POSIX ltype() can never return unknown + // (because it is part of the directory iteration result). + // entry_type type () const; entry_type ltype () const; + // Modification and access times of the filesystem entry if it is not a + // symlink and of the symlink target otherwise. + // + // These are provided as an optimization if they can be obtained as a + // byproduct of work that is already being done anyway (iteration itself, + // calls to [l]type(), etc). If (not yet) available, timestamp_unknown is + // returned. + // + // Specifically: + // + // - On Windows mtime is always set by dir_iterator for entries other than + // reparse points. + // + // - On all platforms mtime and atime are always set for symlink targets + // by dir_iterator in the {detect,ignore}_dangling modes. + // + // - On all platforms mtime and atime can potentially be set by [l]type() + // if the stat() call is required to retrieve the type information (the + // native directory entry iterating API doesn't provide it, the type of + // the symlink target is queried, etc). + // + timestamp + mtime () const {return mtime_;} + + timestamp + atime () const {return atime_;} + // Entry path (excluding the base). To get the full path, do // base () / path (). // @@ -668,8 +706,17 @@ namespace butl base () const {return b_;} dir_entry () = default; - dir_entry (entry_type t, path_type p, dir_path b) - : t_ (t), p_ (std::move (p)), b_ (std::move (b)) {} + + dir_entry (entry_type t, + path_type p, + dir_path b, + timestamp mt = timestamp_unknown, + timestamp at = timestamp_unknown) + : t_ (t), + mtime_ (mt), + atime_ (at), + p_ (std::move (p)), + b_ (std::move (b)) {} private: entry_type @@ -678,8 +725,14 @@ namespace butl private: friend class dir_iterator; - mutable entry_type t_ = entry_type::unknown; // Lazy evaluation. - mutable entry_type lt_ = entry_type::unknown; // Lazy evaluation. + // Note: lazy evaluation. + // + mutable optional<entry_type> t_; // Entry type. + mutable optional<entry_type> lt_; // Symlink target type. + + mutable timestamp mtime_ = timestamp_unknown; + mutable timestamp atime_ = timestamp_unknown; + path_type p_; dir_path b_; }; @@ -696,12 +749,15 @@ namespace butl ~dir_iterator (); dir_iterator () = default; - // If it is requested to ignore dangling symlinks, then the increment - // operator will skip symlinks that refer to non-existing or inaccessible - // targets. That implies that it will always try to stat() symlinks. + // If the mode is either ignore_dangling or detect_dangling, then stat() + // the entry and either ignore inaccessible/dangling entry or return it + // with the corresponding dir_entry type set to unknown (see dir_entry + // type()/ltype() for details). // + enum mode {no_follow, detect_dangling, ignore_dangling}; + explicit - dir_iterator (const dir_path&, bool ignore_dangling); + dir_iterator (const dir_path&, mode); dir_iterator (const dir_iterator&) = delete; dir_iterator& operator= (const dir_iterator&) = delete; @@ -727,10 +783,10 @@ namespace butl #ifndef _WIN32 DIR* h_ = nullptr; #else - intptr_t h_ = -1; + intptr_t h_ = -1; // INVALID_HANDLE_VALUE #endif - bool ignore_dangling_ = false; + mode mode_ = no_follow; }; // Range-based for loop support. @@ -821,9 +877,20 @@ namespace butl // (a/b/, b*/, true) // (a/b/c/, c*/, false) // - // Note that recursive iterating through directories currently goes - // depth-first which make sense for the cleanup use cases. In future we may - // want to make it controllable. + // Note that recursive iterating through directories currently goes depth- + // first which make sense for the cleanup use cases. In the future we may + // want to make this controllable. + // + // If the match flags contain follow_symlinks, then call the dangling + // callback function for inaccessible/dangling entries if specified, and + // throw appropriate std::system_error otherwise. If the callback function + // returns true, then inaccessible/dangling entry is ignored. Otherwise, + // the entire search is stopped. + // + // Note also that if pattern is not simple (that is, contains directory + // components), then some symlinks (those that are matched against the + // directory components) may still be followed and thus the dangling + // function called. // LIBBUTL_SYMEXPORT void path_search (const path& pattern, @@ -831,7 +898,8 @@ namespace butl const std::string& pattern, bool interm)>&, const dir_path& start = dir_path (), - path_match_flags = path_match_flags::follow_symlinks); + path_match_flags = path_match_flags::follow_symlinks, + const std::function<bool (const dir_entry&)>& dangling = nullptr); // Same as above, but behaves as if the directory tree being searched // through contains only the specified entry. The start directory is used if |