diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-05-19 11:41:16 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-05-19 11:41:16 +0200 |
commit | 70062c72cc7f0acef94a333247cc07df74cd3626 (patch) | |
tree | 1b66af2ee26e0bf2e3232fe389a0a22520dbd936 | |
parent | cf9d0332f6b4dcd7dc388133ffd8fd6edd07e1c1 (diff) |
Add file_empty(), extend path_entry() to return size
-rw-r--r-- | libbutl/filesystem.cxx | 41 | ||||
-rw-r--r-- | libbutl/filesystem.hxx | 24 | ||||
-rw-r--r-- | libbutl/filesystem.ixx | 16 |
3 files changed, 57 insertions, 24 deletions
diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index 6a64073..18b4d22 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -49,8 +49,8 @@ namespace butl file_exists (const char* p, bool fl) { auto pe (path_entry (p, fl)); - return pe.first && (pe.second == entry_type::regular || - (!fl && pe.second == entry_type::symlink)); + return pe.first && (pe.second.type == entry_type::regular || + (!fl && pe.second.type == entry_type::symlink)); } bool @@ -63,18 +63,18 @@ namespace butl dir_exists (const char* p) { auto pe (path_entry (p, true)); - return pe.first && pe.second == entry_type::directory; + return pe.first && pe.second.type == entry_type::directory; } #ifndef _WIN32 - pair<bool, entry_type> + pair<bool, entry_stat> path_entry (const char* p, bool fl) { struct stat s; if ((fl ? stat (p, &s) : lstat (p, &s)) != 0) { if (errno == ENOENT || errno == ENOTDIR) - return make_pair (false, entry_type::unknown); + return make_pair (false, entry_stat {entry_type::unknown, 0}); else throw_generic_error (errno); } @@ -91,10 +91,10 @@ namespace butl else if (S_ISBLK (m) || S_ISCHR (m) || S_ISFIFO (m) || S_ISSOCK (m)) t = entry_type::other; - return make_pair (true, t); + return make_pair (true, entry_stat {t, static_cast<uint64_t> (s.st_size)}); } #else - pair<bool, entry_type> + pair<bool, entry_stat> path_entry (const char* p, bool) { // A path like 'C:', while being a root path in our terminology, is not as @@ -113,9 +113,10 @@ namespace butl DWORD attr (GetFileAttributesA (p)); if (attr == INVALID_FILE_ATTRIBUTES) // Presumably not exists. - return make_pair (false, entry_type::unknown); + return make_pair (false, entry_stat {entry_type::unknown, 0}); - entry_type t (entry_type::unknown); + entry_type et (entry_type::unknown); + uint64_t es (0); // S_ISLNK/S_IFDIR are not defined for Win32 but it does have symlinks. // We will consider symlink entry to be of the unknown type. Note that @@ -123,12 +124,12 @@ namespace butl // if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0) { - struct _stat s; + struct __stat64 s; // For 64-bit size. - if (_stat (p, &s) != 0) + if (_stat64 (p, &s) != 0) { if (errno == ENOENT || errno == ENOTDIR) - return make_pair (false, entry_type::unknown); + return make_pair (false, entry_stat {entry_type::unknown, 0}); else throw_generic_error (errno); } @@ -136,15 +137,17 @@ namespace butl auto m (s.st_mode); if (S_ISREG (m)) - t = entry_type::regular; + et = entry_type::regular; else if (S_ISDIR (m)) - t = entry_type::directory; + et = entry_type::directory; // //else if (S_ISLNK (m)) - // t = entry_type::symlink; + // et = entry_type::symlink; + + es = static_cast<uint64_t> (s.st_size); } - return make_pair (true, t); + return make_pair (true, entry_stat {et, es}); } #endif @@ -500,10 +503,10 @@ namespace butl if (!ovr && te.first) throw_generic_error (EEXIST); - bool td (te.first && te.second == entry_type::directory); + bool td (te.first && te.second.type == entry_type::directory); auto fe (path_entry (from)); - bool fd (fe.first && fe.second == entry_type::directory); + bool fd (fe.first && fe.second.type == entry_type::directory); // If source and destination filesystem entries exist, they both must be // either directories or not directories. @@ -1265,7 +1268,7 @@ namespace butl auto pe (path_entry (start_dir / p, true)); if (pe.first && - ((pe.second == entry_type::directory) == p.to_directory ())) + ((pe.second.type == entry_type::directory) == p.to_directory ())) return func (move (p), string (), false); return true; diff --git a/libbutl/filesystem.hxx b/libbutl/filesystem.hxx index 4fa1021..a6d7a4a 100644 --- a/libbutl/filesystem.hxx +++ b/libbutl/filesystem.hxx @@ -21,7 +21,7 @@ #endif #include <cstddef> // ptrdiff_t -#include <cstdint> // uint16_t +#include <cstdint> // uint16_t, etc #include <utility> // move(), pair #include <iterator> #include <functional> @@ -73,23 +73,37 @@ namespace butl other }; + // Filesystem entry info. The size is only meaningful for regular files. + // + struct entry_stat + { + entry_type type; + std::uint64_t size; + }; + // Return a flag indicating if the path is to an existing file system entry // and its type if so. Note that by default this function doesn't follow // symlinks. // - LIBBUTL_EXPORT std::pair<bool, entry_type> + LIBBUTL_EXPORT std::pair<bool, entry_stat> path_entry (const char*, bool follow_symlinks = false); - inline std::pair<bool, entry_type> + inline std::pair<bool, entry_stat> path_entry (const path& p, bool fs = false) { return path_entry (p.string ().c_str (), fs);} // Return true if the directory is empty. Note that the path must exist - // and be a directory. + // and be a directory. This function follows symlinks. // - LIBBUTL_EXPORT bool + bool dir_empty (const dir_path&); + // Return true if the file is empty. Note that the path must exist and be a + // regular file. This function follows symlinks. + // + bool + file_empty (const path&); + // Try to create a directory unless it already exists. If you expect // the directory to exist and performance is important, then you // should first call dir_exists() above since that's what this diff --git a/libbutl/filesystem.ixx b/libbutl/filesystem.ixx index eb9984b..a6fae64 100644 --- a/libbutl/filesystem.ixx +++ b/libbutl/filesystem.ixx @@ -7,9 +7,25 @@ namespace butl inline bool dir_empty (const dir_path& d) { + // @@ Could 0 size be a valid and faster way? + // return dir_iterator (d) == dir_iterator (); } + inline bool + file_empty (const path& f) + { + auto p (path_entry (f)); + + if (p.first && p.second.type == entry_type::regular) + return p.second.size == 0; + + throw_generic_error ( + p.first + ? (p.second.type == entry_type::directory ? EISDIR : EINVAL) + : ENOENT); + } + inline rmdir_status try_rmdir_r (const dir_path& p, bool ignore_error) { |