aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-09-29 13:04:29 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-09-29 13:04:29 +0200
commitefd154a6af61e80be1b0c46642cefd73cc83d7ed (patch)
treef41400d27727800d7f72317f80ee8e43285792b4
parentcdc67ad0cf1e102568396b0649dd18ea1223d785 (diff)
Add auto_rmfile and auto_rmdir
-rw-r--r--butl/filesystem48
-rw-r--r--butl/filesystem.cxx8
-rw-r--r--butl/filesystem.ixx35
3 files changed, 77 insertions, 14 deletions
diff --git a/butl/filesystem b/butl/filesystem
index 5b1c656..c3340d7 100644
--- a/butl/filesystem
+++ b/butl/filesystem
@@ -55,20 +55,20 @@ namespace butl
mkdir_status
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
- // reported by throwing std::system_error.
+ // Try to remove the directory returning not_exist if it does not exist
+ // and not_empty if it is not empty. Unless ignore_error is true, all
+ // other errors are reported by throwing std::system_error.
//
enum class rmdir_status {success, not_exist, not_empty};
rmdir_status
- try_rmdir (const dir_path&);
+ try_rmdir (const dir_path&, bool ignore_error = false);
// The '-r' (recursive) version of the above. Note that it will
// never return not_empty.
//
rmdir_status
- try_rmdir_r (const dir_path&);
+ try_rmdir_r (const dir_path&, bool ignore_error = false);
// As above but throws rather than returns not_exist if the directory
// does not exist, so check before calling. If the second argument is
@@ -78,13 +78,45 @@ namespace butl
rmdir_r (const dir_path&, bool dir = true);
// Try to remove the file (or symlinks) returning not_exist if
- // it does not exist. All other errors are reported by throwing
- // std::system_error.
+ // it does not exist. Unless ignore_error is true, all other
+ // errors are reported by throwing std::system_error.
//
enum class rmfile_status {success, not_exist};
rmfile_status
- try_rmfile (const path&);
+ try_rmfile (const path&, bool ignore_error = false);
+
+ // Automatically try to remove the path on destruction unless cancelled.
+ // Since the non-cancelled destruction will normally happen as a result
+ // of an exception, the failure to remove the path is silently ignored.
+ //
+ template <typename P>
+ struct auto_rm
+ {
+ explicit
+ auto_rm (P p = P ()): path_ (std::move (p)) {}
+
+ void
+ cancel () {path_ = P ();}
+
+ const P&
+ path () {return path_;}
+
+ // Movable-only type. Move-assignment cancels the lhs object.
+ //
+ auto_rm (auto_rm&&);
+ auto_rm& operator= (auto_rm&&);
+ auto_rm (const auto_rm&) = delete;
+ auto_rm& operator= (const auto_rm&) = delete;
+
+ ~auto_rm ();
+
+ private:
+ P path_;
+ };
+
+ using auto_rmfile = auto_rm<path>;
+ using auto_rmdir = auto_rm<dir_path>; // Note: recursive (rm_r).
// Return timestamp_nonexistent if the entry at the specified path
// does not exist or is not a path. All other errors are reported
diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx
index f1341ee..5a43cd2 100644
--- a/butl/filesystem.cxx
+++ b/butl/filesystem.cxx
@@ -81,7 +81,7 @@ namespace butl
}
rmdir_status
- try_rmdir (const dir_path& p)
+ try_rmdir (const dir_path& p, bool ignore_error)
{
rmdir_status r (rmdir_status::success);
@@ -91,7 +91,7 @@ namespace butl
r = rmdir_status::not_exist;
else if (errno == ENOTEMPTY || errno == EEXIST)
r = rmdir_status::not_empty;
- else
+ else if (!ignore_error)
throw system_error (errno, system_category ());
}
@@ -125,7 +125,7 @@ namespace butl
}
rmfile_status
- try_rmfile (const path& p)
+ try_rmfile (const path& p, bool ignore_error)
{
rmfile_status r (rmfile_status::success);
@@ -133,7 +133,7 @@ namespace butl
{
if (errno == ENOENT || errno == ENOTDIR)
r = rmfile_status::not_exist;
- else
+ else if (!ignore_error)
throw system_error (errno, system_category ());
}
diff --git a/butl/filesystem.ixx b/butl/filesystem.ixx
index 256cbba..3b72b4a 100644
--- a/butl/filesystem.ixx
+++ b/butl/filesystem.ixx
@@ -5,16 +5,47 @@
namespace butl
{
inline rmdir_status
- try_rmdir_r (const dir_path& p)
+ try_rmdir_r (const dir_path& p, bool ignore_error)
{
bool e (dir_exists (p)); //@@ What if it exists but is not a directory?
if (e)
- rmdir_r (p);
+ rmdir_r (p, ignore_error);
return e ? rmdir_status::success : rmdir_status::not_exist;
}
+ // auto_rm
+ //
+ template <typename P>
+ inline auto_rm<P>::
+ auto_rm (auto_rm&& x)
+ : path_ (std::move (x.path_))
+ {
+ x.cancel ();
+ }
+
+ template <typename P>
+ inline auto_rm<P>& auto_rm<P>::
+ operator= (auto_rm&& x)
+ {
+ if (this != &x)
+ {
+ path_ = std::move (x.path_);
+ x.cancel ();
+ }
+
+ return *this;
+ }
+
+ template <>
+ inline auto_rm<path>::
+ ~auto_rm () {if (!path_.empty ()) try_rmfile (path_, true);}
+
+ template <>
+ inline auto_rm<dir_path>::
+ ~auto_rm () {if (!path_.empty ()) try_rmdir_r (path_, true);}
+
// permissions
//
inline permissions operator& (permissions x, permissions y) {return x &= y;}