aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-08-31 13:52:41 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-08-31 13:52:41 +0200
commitdecd319bc1bc7d427f92feba29d408eb2edb973d (patch)
treeee8195bc563a58161f8e0c4ae8ce601f3f8a4a58
parent32e8dbc3558a7b9ddecad50a9eb241b5e36f6c02 (diff)
Add rmdir_r(), path_permissions()
-rw-r--r--butl/filesystem64
-rw-r--r--butl/filesystem.cxx126
-rw-r--r--butl/filesystem.ixx29
3 files changed, 162 insertions, 57 deletions
diff --git a/butl/filesystem b/butl/filesystem
index 0a5d7eb..9168f19 100644
--- a/butl/filesystem
+++ b/butl/filesystem
@@ -12,6 +12,7 @@
#endif
#include <cstddef> // ptrdiff_t
+#include <cstdint> // uint16_t
#include <utility> // move()
#include <iterator>
@@ -20,14 +21,6 @@
namespace butl
{
- // Return timestamp_nonexistent if the entry at the specified path
- // does not exist or is not a path. All other errors are reported
- // by throwing std::system_error. Note that this function resolves
- // symlinks.
- //
- timestamp
- file_mtime (const path&);
-
// Return true if the path is to an existing directory. Note that
// this function resolves symlinks.
//
@@ -54,13 +47,13 @@ namespace butl
enum class mkdir_status {success, already_exists};
mkdir_status
- try_mkdir (const path&, mode_t = 0777);
+ try_mkdir (const dir_path&, mode_t = 0777);
// The '-p' version of the above (i.e., it creates the parent
// directories if necessary).
//
mkdir_status
- try_mkdir_p (const path&, mode_t = 0777);
+ try_mkdir_p (const dir_path&, mode_t = 0777);
// Try to remove the directory returning not_exist if it does not
// exist and not_empty if it is not empty. All other errors are
@@ -69,7 +62,19 @@ namespace butl
enum class rmdir_status {success, not_exist, not_empty};
rmdir_status
- try_rmdir (const path&);
+ try_rmdir (const dir_path&);
+
+ // The '-r' (recursive) version of the above. Note that it will
+ // never return not_empty.
+ //
+ rmdir_status
+ try_rmdir_r (const dir_path&);
+
+ // As above but throws rather than returns not_exist if the directory
+ // does not exist, so check before calling.
+ //
+ void
+ rmdir_r (const dir_path&);
// Try to remove the file (or symlinks) returning not_exist if
// it does not exist. All other errors are reported by throwing
@@ -80,6 +85,43 @@ namespace butl
rmfile_status
try_rmfile (const path&);
+ // Return timestamp_nonexistent if the entry at the specified path
+ // does not exist or is not a path. All other errors are reported
+ // by throwing std::system_error. Note that this function resolves
+ // symlinks.
+ //
+ timestamp
+ file_mtime (const path&);
+
+ // 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
+ };
+
+ permissions operator& (permissions, permissions);
+ permissions operator| (permissions, permissions);
+ permissions operator&= (permissions&, permissions);
+ permissions operator|= (permissions&, permissions);
+
+ permissions
+ path_permissions (const path&);
+
// Directory entry iteration.
//
enum class entry_type
diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx
index 2a1fad9..90e8e81 100644
--- a/butl/filesystem.cxx
+++ b/butl/filesystem.cxx
@@ -15,48 +15,6 @@ using namespace std;
namespace butl
{
- // Figuring out whether we have the nanoseconds in some form.
- //
- template <typename S>
- inline constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec)
- {
- return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris).
- }
-
- template <typename S>
- inline constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec)
- {
- return s->st_mtimespec.tv_nsec; // MacOS X.
- }
-
- template <typename S>
- inline constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n)
- {
- return s->st_mtime_n; // AIX 5.2 and later.
- }
-
- template <typename S>
- inline constexpr int nsec (...) {return 0;}
-
- timestamp
- file_mtime (const path& p)
- {
- struct stat s;
- if (::stat (p.string ().c_str (), &s) != 0)
- {
- if (errno == ENOENT || errno == ENOTDIR)
- return timestamp_nonexistent;
- else
- throw system_error (errno, system_category ());
- }
-
- return S_ISREG (s.st_mode)
- ? system_clock::from_time_t (s.st_mtime) +
- chrono::duration_cast<duration> (
- chrono::nanoseconds (nsec<struct stat> (&s)))
- : timestamp_nonexistent;
- }
-
bool
dir_exists (const path& p)
{
@@ -88,7 +46,7 @@ namespace butl
}
mkdir_status
- try_mkdir (const path& p, mode_t m)
+ try_mkdir (const dir_path& p, mode_t m)
{
mkdir_status r (mkdir_status::success);
@@ -109,11 +67,11 @@ namespace butl
}
mkdir_status
- try_mkdir_p (const path& p, mode_t m)
+ try_mkdir_p (const dir_path& p, mode_t m)
{
if (!p.root ())
{
- path d (p.directory ());
+ dir_path d (p.directory ());
if (!dir_exists (d))
try_mkdir_p (d, m);
@@ -123,7 +81,7 @@ namespace butl
}
rmdir_status
- try_rmdir (const path& p)
+ try_rmdir (const dir_path& p)
{
rmdir_status r (rmdir_status::success);
@@ -140,6 +98,29 @@ namespace butl
return r;
}
+ void
+ rmdir_r (const dir_path& p)
+ {
+ // An nftw()-based implementation (for platforms that support it)
+ // might be a faster way.
+ //
+ for (const dir_entry& de: dir_iterator (p))
+ {
+ path ep (p / de.path ()); //@@ Would be good to reuse the buffer.
+
+ if (de.ltype () == entry_type::directory)
+ rmdir_r (path_cast<dir_path> (ep));
+ else
+ try_rmfile (ep);
+ }
+
+ rmdir_status r (try_rmdir (p));
+
+ if (r != rmdir_status::success)
+ throw system_error (r == rmdir_status::not_empty ? ENOTEMPTY : ENOENT,
+ system_category ());
+ }
+
rmfile_status
try_rmfile (const path& p)
{
@@ -156,6 +137,59 @@ namespace butl
return r;
}
+ // Figuring out whether we have the nanoseconds in some form.
+ //
+ template <typename S>
+ inline constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec)
+ {
+ return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris).
+ }
+
+ template <typename S>
+ inline constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec)
+ {
+ return s->st_mtimespec.tv_nsec; // MacOS X.
+ }
+
+ template <typename S>
+ inline constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n)
+ {
+ return s->st_mtime_n; // AIX 5.2 and later.
+ }
+
+ template <typename S>
+ inline constexpr int nsec (...) {return 0;}
+
+ timestamp
+ file_mtime (const path& p)
+ {
+ struct stat s;
+ if (::stat (p.string ().c_str (), &s) != 0)
+ {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return timestamp_nonexistent;
+ else
+ throw system_error (errno, system_category ());
+ }
+
+ return S_ISREG (s.st_mode)
+ ? system_clock::from_time_t (s.st_mtime) +
+ chrono::duration_cast<duration> (
+ chrono::nanoseconds (nsec<struct stat> (&s)))
+ : timestamp_nonexistent;
+ }
+
+ permissions
+ path_permissions (const path& p)
+ {
+ struct stat s;
+ if (::stat (p.string ().c_str (), &s) != 0)
+ throw system_error (errno, system_category ());
+
+ return static_cast<permissions> (
+ s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ }
+
#ifndef _WIN32
// dir_entry
diff --git a/butl/filesystem.ixx b/butl/filesystem.ixx
index 2d2690f..256cbba 100644
--- a/butl/filesystem.ixx
+++ b/butl/filesystem.ixx
@@ -4,6 +4,35 @@
namespace butl
{
+ inline rmdir_status
+ try_rmdir_r (const dir_path& p)
+ {
+ bool e (dir_exists (p)); //@@ What if it exists but is not a directory?
+
+ if (e)
+ rmdir_r (p);
+
+ return e ? rmdir_status::success : rmdir_status::not_exist;
+ }
+
+ // permissions
+ //
+ inline permissions operator& (permissions x, permissions y) {return x &= y;}
+ inline permissions operator| (permissions x, permissions y) {return x &= y;}
+ inline permissions operator&= (permissions& x, permissions y)
+ {
+ return x = static_cast<permissions> (
+ static_cast<std::uint16_t> (x) &
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline permissions operator|= (permissions& x, permissions y)
+ {
+ return x = static_cast<permissions> (
+ static_cast<std::uint16_t> (x) |
+ static_cast<std::uint16_t> (y));
+ }
+
// dir_entry
//
inline entry_type dir_entry::