aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-05-19 11:41:16 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-05-19 11:41:16 +0200
commit70062c72cc7f0acef94a333247cc07df74cd3626 (patch)
tree1b66af2ee26e0bf2e3232fe389a0a22520dbd936
parentcf9d0332f6b4dcd7dc388133ffd8fd6edd07e1c1 (diff)
Add file_empty(), extend path_entry() to return size
-rw-r--r--libbutl/filesystem.cxx41
-rw-r--r--libbutl/filesystem.hxx24
-rw-r--r--libbutl/filesystem.ixx16
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)
{