// boost/filesystem/directory.hpp ------------------------------------------// // < ----------------------------------------------------------------------- > // < Copyright © 2001 Dietmar Kühl, All Rights Reserved > // < Copyright © 2002 Beman Dawes and Jan Langer. > // < > // < Permission to use, copy, modify, distribute and sell this > // < software for any purpose is hereby granted without fee, provided > // < that the above copyright notice appears in all copies and that > // < both that copyright notice and this permission notice appear in > // < supporting documentation. The authors make no representations about > // < the suitability of this software for any purpose. It is provided > // < "as is" without express or implied warranty. > // < ----------------------------------------------------------------------- > // See http://www.boost.org for most recent version including documentation. //----------------------------------------------------------------------------// #ifndef BOOST_FILESYSTEM_DIRECTORY_HPP #define BOOST_FILESYSTEM_DIRECTORY_HPP #include "boost/smart_ptr.hpp" #include "boost/iterator.hpp" #include "boost/operators.hpp" #include //----------------------------------------------------------------------------// // An implementation must provide std::string overloads for the free functions, // and a char specialization for class templates. // // An implementation may provide std::wstring overloads for the free functions, // and wchar_t specializations for class templates. // // An implementation may provide other std::basic_string overloads for the free // functions, and equivalent specializations for class templates. // // Unless otherwise specified: // // * The internal form of path arguments is unspecified. They may represent // either absolute paths, or relative paths if supported by the operating // system. // * Any function may throw if an argument is not well-formed. // * Path arguments of an empty string are not well-formed. // * In addition to the specific "Throws" specified for a function, // all functions will throw if the operating system cannot sucessfully // complete the indicated operation. There is no rollback guarantee; a // failed operation may have altered the state of the external file system. // // Remember that other threads, processes, or computers may have access to a // file system. As an example of the difficulties this can cause, consider // that the following assert may fail: // // assert( exists( "foo" ) == exists( "foo" ) ); //----------------------------------------------------------------------------// namespace boost { namespace filesystem { // operations on files and directories -------------------------------------// // Rationale for specifying overloaded functions rather than function // templates: Since the functions are required to work with both // std::basic_string and pointers to built-in character types, using the // same approach as the standard does with basic_string free functions // would require five overloads for the two argument functions: // void move( const std::basic_string & old_path, // const std::basic_string & new_path ); // void move( const std::basic_string & old_path, // const CharT * new_path ); // void move( const CharT * old_path, // const std::basic_string & new_path ); // void move( const char * old_path, const char * new_path ); // void move( const wchar_t * old_path, const wchar_t * new_path ); // The approach chosen is believed to be equivalent, but simpler because // it relies on the basic_string automatic conversion constructor. // std::wstring overloads follow std::string signatures below. // Rationale for providing some attributes via free functions rather // than property map: These are so commonly used that simple syntax and // guaranteed presence outweight other considerations. // The general approach is to provide a set of basic functions, and then // an additional set of convenience functions. The convenience functions // could be implemented in terms of the basic functions, although for // efficiency an implementation might not choose to do so. // // The basic functions are fairly low level, and non-recursive, and (for // maximum safety) are strict about what is considered an error. // // The convenience functions provide composite operations, and may be // expanded to include recursion, regular expressions, and other filtering. // Basic operations ----------------------------------------------------// // TODO: Should there be directory_entry overloads for exists(), // is_directory(), etc? Some of the composite operations would // more efficient if so. bool exists( const std::string & path ); // Returns: true if the file or directory represented by path exists // in the underlying file system. // Throws: if it cannot be determined if path exists. bool is_directory( const std::string & path ); // Throws: If path doesn't exist // Note: May return false for all paths except the root on some flat // directory structure systems. inline bool is_file( const std::string & path ) { return !is_directory( path ); } // Throws: If path doesn't exist bool is_read_only( const std::string & path ); // Throws: If path doesn't exist // Note: !is_read_only() doesn't imply writable; permissions or the like // may make a non-read-only file still not writable. void create_directory( const std::string & dir_path ); // Effects: Creates a new empty directory. // Throws: If the operating system cannot create the new directory. // Note: Non-recursive. Thus at the minimum it is required that // exists(branch(path)) && !exists(leaf(path)). void remove_directory( const std::string & dir_path ); // Effects: Deletes the directory represented by dir_path from the // file system. // Throws: if !exist( dir_path ) // || !is_directory( dir_path ) // || !is_empty( dir_path ) void remove_file( const std::string & file_path ); // Effects: Deletes the file represented by file_path from the // file system. // Throws: if !exist( file_path ) // || !is_file( dir_path ) void copy_file( const std::string & old_file_path, const std::string & new_file_path ); // Effects: Copies the file represented by old_file_path to new_file_path. // Throws: if !exists( old_file_path ) || exists( new_file_path ) // || !is_file( old_file_path ). // Rationale: A separate name makes clearer the distinction between this // function and the directory contents "copy" and "copy_all" below. By // having a separate function, which mix of "_all", files, and directories // are legal is clearer, and copy_file itself is simpler. void rename( const std::string & old_path, const std::string new_path ); // Effects: Renames the file or directory represented by old_path // to new_path. // Throws: if !exists( old_path ) || exists( new_path ). // Note: Move and rename are the same operation. // TODO: Which is a better name? "remove" or "rename"? Why? template< typename CharT > std::basic_string initial_directory(); // Effects: The first time called, stores an absolute directory path. // The path is determined: // If possible, the path of the initial working directory when main() // was called. Otherwise, if possible, the current working directory. // Otherwise, if possible, a reasonable directory (such as the root // directory on a single rooted filesystem). Otherwise, if possible, // compile or link. Otherwise, throws an exception. // Returns: The stored path. // Rationale for not simply specifying the return as "initial working // directory when main() was called": That directory isn't known on all // platforms; indeed there may not even be a concept of "current working // directory". The semantics are chosen to come as close to that as // possible (and encourage but not require language runtime support). // Note: It would be good practice in a program dependent on // initial_directory() to call it immediately on entering main(). // That protects against a called function altering the current working // directory (using a native platform function) and then calling // initial_directory(). // Convenience operations ----------------------------------------------// // TODO: Some of these are inline for purposes of exposition. An efficient // implementation would almost certainly not inline these because they can // be implemented more efficiently using native API calls, property // attributes or even directory_entry's. void remove( const std::string & path ); // Effects: As if: // if ( exists(path) ) // if ( is_file(path) remove_file(path); // else remove_directory(path); // else throw filesystem error( ... ); bool remove_if_exists( const std::string & path ); // Effects: if exists( path ), deletes the file or directory // represented by path from the file system. // Returns: exists( path ) before effects applied. // Throws: if is_directory( path ) && the directory is not empty. // Rationale for inclusion of the function: if the aim is simply to // satisfy the post-condition !exist(path), throwing on !exist(path) // is excessively strick. Requested by Rob Stewart. Somewhat controversial. void remove_all( const std::string & dir_path ); // Effects: Deletes the directory represented by dir_path from the file // system, after first, recursively, removing all its contents. // Throws: if !exist( path ) || ( !is_directory( path ). // Note: // remove_all( "foo" ); // removes "foo" and its contents. // prune_all( "foo" ); // removes "foo" contents, but not "foo" itself. inline bool existing_file( const std::string & path ) { return exists( path ) && is_file( path ); } inline bool existing_directory( const std::string & path ) { return exists( path ) && is_directory( path ); } void create_missing_directories( const std::string & path ); // Effects: Calls create_directory() as many times as needed to create // the file system path represented by the path argument. // Throws: if existing_file( path ) /* These functions are still speculative, and so are commented out. They are shown because it is difficult to understand some of the rationale for the design of the other functions in this header without know that these potentially exist. bool is_empty( const std::string & dir_path ); Unclear if useful enough to justify inclusion. Would make some specifications clearer, but that doesn't mean real code needs it. Even less clear if a version which worked on files would be useful. // prune works on the contents of dir_path, not dir_path itself. // Rationale for not naming the functions "remove": remove has different // semantics; it works on the directory itself rather than the directory's // contents. Thus a different name as an alert to the differing semantics. void prune( const std::string & dir_path ); void prune( const std::string & dir_path, const std::string & name ); void prune( const std::string & dir_path, const boost::regex & name_filter ); template void prune( const std::string & dir_path, Predicate pred_filter ); // recursive versions void prune_all( const std::string & dir_path ); // Note: // remove_all( "foo" ); // removes "foo" and its contents. // prune_all( "foo" ); // removes "foo" contents, but not "foo" itself. void prune_all( const std::string & dir_path, const std::string & name ); void prune_all( const std::string & dir_path, const boost::regex & name_filter ); template void prune_all( const std::string & dir_path, Predicate pred_filter ); // Rationale for not providing name, regex, or predicate filtered versions // of remove() or remove_all(): The implication of filtering is that the // starting directory may not be empty on completion of operations. Thus // trying to remove it makes no sense. // TODO: would it be clearer to name the following copy_directory and // and copy_directory_all? // copy also works on path content. void copy( const std::string & old_dir_path, const std::string & new_dir_path ); void copy( const std::string & old_dir_path, const std::string & new_dir_path, const std::string & name );, void copy( const std::string & old_dir_path, const std::string & new_dir_path, const boost::regex & name_filter );, template void copy( const std::string & old_dir_path, const std::string & new_dir_path, BinaryPredicate pred_filter ); // recursive versions void copy_all( const std::string & old_dir_path, const std::string & new_dir_path ); void copy_all( const std::string & old_dir_path, const std::string & new_dir_path, const std::string & name );, void copy_all( const std::string & old_dir_path, const std::string & new_dir_path, const boost::regex & name_filter );, template void copy_all( const std::string & old_dir_path, const std::string & new_dir_path, BinaryPredicate pred_filter ); */ // std::wstring overloads ----------------------------------------------// #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) bool exists( const std::wstring & path ); bool is_directory( const std::wstring & path ); inline bool is_file( const std::wstring & path ) { return !is_directory( path ); } bool is_read_only( const std::wstring & path ); void create_directory( const std::wstring & dir_path ); // TODO: complete this section ... #endif // BOOST_NO_STD_WSTRING // opaque types passed as magic cookies ------------------------------------// namespace detail { template< class CharT > struct basic_dir_itr_rep; template< class CharT > struct basic_dir_entry_rep; } // basic_directory_entry ---------------------------------------------------// template< class CharT > class basic_directory_entry { public: // The semantics of default construction and construction from a path // can't be fully nailed down until the attribute specs are nailed down. // So for now assume the only way to get a useful basic_directory_entry // is by dereferencing a basic_directory_iterator or copy construction. // explicit basic_directory_entry( const std::basic_string & path ); basic_directory_entry(); // users should avoid until specs complete basic_directory_entry( const basic_directory_entry & rhs ); // Effects: deep copy basic_directory_entry & operator=( const basic_directory_entry & rhs ); // Effects: deep copy ~basic_directory_entry(); const std::basic_string & name() const; const std::basic_string & directory_path() const; const std::basic_string & path() const; // Return: compose( directory_path(), name() ) // Rationale for providing path(): makes much common user code simpler. // Rationale for not providing operator== is that it is so difficult // as to be practically impossible (see design docs for details) to // tell if two paths are the same. // There are some implementation details which require access // to the representation. Since it is an opaque type, and thus harmless, // and there are compiler issues with template friends, Dietmar provided // access functions. typedef detail::basic_dir_entry_rep rep_t; rep_t & rep() { return *m_imp; } rep_t const & rep() const { return *m_imp; } private: boost::scoped_ptr m_imp; }; typedef basic_directory_entry directory_entry; #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) typedef basic_directory_entry wdirectory_entry; #endif // basic_directory_iterator ------------------------------------------------// // TODO: It might be a considerable convenience to provide either separate // iterators, or else iterator adaptors to do breadth-first and depth-first // recursive directory iteratation. Not needed for initial submission. template< class CharT > class basic_directory_iterator: public boost::iterator< std::input_iterator_tag, basic_directory_entry< CharT > >, public boost::equality_comparable< basic_directory_iterator< CharT > >, public boost::dereferenceable< basic_directory_iterator< CharT >, const basic_directory_entry< CharT > * >, public boost::incrementable< basic_directory_iterator< CharT > > { public: typedef boost::iterator< std::input_iterator_tag, basic_directory_entry > base; typedef typename base::value_type value_type; typedef typename base::difference_type difference_type; typedef typename base::pointer pointer; typedef typename base::reference reference; typedef typename base::iterator_category iterator_category; basic_directory_iterator(); explicit basic_directory_iterator( const std::basic_string & dirpath ); ~basic_directory_iterator(); // compiler generates copy constructor and copy assignment bool operator==( const basic_directory_iterator & ) const; basic_directory_entry const & operator*() const; basic_directory_iterator & operator++ (); private: typedef detail::basic_dir_itr_rep rep_t; boost::shared_ptr m_imp; }; typedef basic_directory_iterator directory_iterator; #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) typedef basic_directory_iterator wdirectory_iterator; #endif } // namespace filesystem } // namespace boost #endif // BOOST_FILESYSTEM_DIRECTORY_HPP