From decd319bc1bc7d427f92feba29d408eb2edb973d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 31 Aug 2015 13:52:41 +0200 Subject: Add rmdir_r(), path_permissions() --- butl/filesystem.cxx | 126 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 46 deletions(-) (limited to 'butl/filesystem.cxx') 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 - inline constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) - { - return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris). - } - - template - inline constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) - { - return s->st_mtimespec.tv_nsec; // MacOS X. - } - - template - inline constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) - { - return s->st_mtime_n; // AIX 5.2 and later. - } - - template - 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 ( - chrono::nanoseconds (nsec (&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 (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 + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) + { + return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris). + } + + template + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) + { + return s->st_mtimespec.tv_nsec; // MacOS X. + } + + template + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) + { + return s->st_mtime_n; // AIX 5.2 and later. + } + + template + 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 ( + chrono::nanoseconds (nsec (&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 ( + s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + } + #ifndef _WIN32 // dir_entry -- cgit v1.1