// file : butl/filesystem -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BUTL_FILESYSTEM #define BUTL_FILESYSTEM #include // mode_t #ifndef _WIN32 # include // DIR, struct dirent, *dir() #endif #include // ptrdiff_t #include // move() #include #include #include 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. // bool dir_exists (const path&); // Return true if the path is to an existing regular file. Note that // this function resolves symlinks. // bool file_exists (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 // implementation will do to make sure the path is actually a // directory. // // You should also probably use the default mode 0777 and let the // umask mechanism adjust it to the user's preferences. // // Errors are reported by throwing std::system_error. // enum class mkdir_status {success, already_exists}; mkdir_status try_mkdir (const 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 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. // enum class rmdir_status {success, not_exist, not_empty}; rmdir_status try_rmdir (const path&); // 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. // enum class rmfile_status {success, not_exist}; rmfile_status try_rmfile (const path&); // Directory entry iteration. // enum class entry_type { unknown, regular, directory, symlink, other }; class dir_entry { public: typedef butl::path path_type; // Symlink target type in case of the symlink, ltype() otherwise. // entry_type type () const; entry_type ltype () const; // Entry path (excluding the base). To get the full path, do // base () / path (). // const path_type& path () const {return p_;} const dir_path& base () const {return b_;} dir_entry () = default; dir_entry (entry_type t, path_type p, dir_path b) : t_ (t), p_ (std::move (p)), b_ (std::move (b)) {} private: entry_type type (bool link) const; private: friend class dir_iterator; mutable entry_type t_ = entry_type::unknown; // Lazy evaluation. mutable entry_type lt_ = entry_type::unknown; // Lazy evaluation. path_type p_; dir_path b_; }; class dir_iterator { public: typedef dir_entry value_type; typedef const dir_entry* pointer; typedef const dir_entry& reference; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; ~dir_iterator (); dir_iterator () = default; explicit dir_iterator (const dir_path&); dir_iterator (const dir_iterator&) = delete; dir_iterator& operator= (const dir_iterator&) = delete; dir_iterator (dir_iterator&& x); dir_iterator& operator= (dir_iterator&&); dir_iterator& operator++ () {next (); return *this;} reference operator* () const {return e_;} pointer operator-> () const {return &e_;} friend bool operator== (const dir_iterator&, const dir_iterator&); friend bool operator!= (const dir_iterator&, const dir_iterator&); private: void next (); private: dir_entry e_; #ifndef _WIN32 DIR* h_ {nullptr}; #else // Check move implementation. // # error Win32 implementation lacking #endif }; // Range-based for loop support. // // for (const auto& de: dir_iterator (dir_path ("/tmp"))) ... // // Note that the "range" (which is the "begin" iterator), is no // longer usable. In other words, don't do this: // // dir_iterator i (...); // for (...: i) ... // ++i; // Invalid. // inline dir_iterator begin (dir_iterator& i) {return std::move (i);} inline dir_iterator end (const dir_iterator&) {return dir_iterator ();} } #include #endif // BUTL_FILESYSTEM