Extra functions for filesystem

Greetings, A long, long time ago, I proposed adding a few more convenience functions to filesystem. http://lists.boost.org/Archives/boost/2006/08/109740.php Despite a positive response and a followup patch, those functions never got incorporated. Did it just fall through the cracks, or was there a more substantive reason those functions never got added? Otherwise, it does not seem possible to implement "cp -a". Thanks, Walter Landry wlandry@caltech.edu

On Wed, Jan 14, 2009 at 4:00 AM, Walter Landry <wlandry@caltech.edu> wrote:
Greetings,
A long, long time ago, I proposed adding a few more convenience functions to filesystem.
http://lists.boost.org/Archives/boost/2006/08/109740.php
Despite a positive response and a followup patch, those functions never got incorporated. Did it just fall through the cracks, or was there a more substantive reason those functions never got added?
AFAIK, it just fell through the cracks. I've created a ticket, #2657 so that won't happen this time around.
Otherwise, it does not seem possible to implement "cp -a".
Interesting. I'd appreciate it if you could send me your patches. That might speed up the process a bit. Thanks, --Beman

"Beman Dawes" <bdawes@acm.org> wrote:
I'd appreciate it if you could send me your patches. That might speed up the process a bit.
Here you go. It is a patch against svn head. I have compiled the code on Linux, but not on Windows. It is not heavily tested. Cheers, Walter Landry wlandry@caltech.edu Index: boost/filesystem/operations.hpp =================================================================== --- boost/filesystem/operations.hpp (revision 50613) +++ boost/filesystem/operations.hpp (working copy) @@ -159,11 +159,15 @@ file_size_api( const std::string & ph ); BOOST_FILESYSTEM_DECL space_pair space_api( const std::string & ph ); + BOOST_FILESYSTEM_DECL uintmax_pair + nlink_api( const std::string & ph ); BOOST_FILESYSTEM_DECL time_pair last_write_time_api( const std::string & ph ); BOOST_FILESYSTEM_DECL system::error_code last_write_time_api( const std::string & ph, std::time_t new_value ); BOOST_FILESYSTEM_DECL system::error_code + get_readlink_api( const std::string & p, std::string & ph ); + BOOST_FILESYSTEM_DECL system::error_code get_current_path_api( std::string & ph ); BOOST_FILESYSTEM_DECL system::error_code set_current_path_api( const std::string & ph ); @@ -181,6 +185,8 @@ rename_api( const std::string & from, const std::string & to ); BOOST_FILESYSTEM_DECL system::error_code copy_file_api( const std::string & from, const std::string & to ); + BOOST_FILESYSTEM_DECL system::error_code + copy_directory_api( const std::string & from, const std::string & to ); # if defined(BOOST_WINDOWS_API) @@ -199,12 +205,16 @@ file_size_api( const std::wstring & ph ); BOOST_FILESYSTEM_DECL space_pair space_api( const std::wstring & ph ); + BOOST_FILESYSTEM_DECL uintmax_pair + nlink_api( const std::wstring & ph ); BOOST_FILESYSTEM_DECL system::error_code get_full_path_name_api( const std::wstring & ph, std::wstring & target ); BOOST_FILESYSTEM_DECL time_pair last_write_time_api( const std::wstring & ph ); BOOST_FILESYSTEM_DECL system::error_code last_write_time_api( const std::wstring & ph, std::time_t new_value ); + BOOST_FILESYSTEM_DECL system::error_code + get_readlink_api( const std::wstring & p, std::wstring & ph ); BOOST_FILESYSTEM_DECL system::error_code get_current_path_api( std::wstring & ph ); BOOST_FILESYSTEM_DECL system::error_code @@ -225,6 +235,8 @@ rename_api( const std::wstring & from, const std::wstring & to ); BOOST_FILESYSTEM_DECL system::error_code copy_file_api( const std::wstring & from, const std::wstring & to ); + BOOST_FILESYSTEM_DECL system::error_code + copy_directory_api( const std::wstring & from, const std::wstring & to ); # endif # endif @@ -401,6 +413,17 @@ return result.second; } + BOOST_FS_FUNC(boost::uintmax_t) nlink( const Path & ph ) + { + detail::uintmax_pair result + = detail::nlink_api( ph.external_file_string() ); + if ( result.first != 0 ) + boost::throw_exception( basic_filesystem_error<Path>( + "boost::filesystem::nlink", ph, result.first ) ); + return result.second; + } + + BOOST_FS_FUNC(std::time_t) last_write_time( const Path & ph ) { detail::time_pair result @@ -515,6 +538,50 @@ from_path, to_path, ec ) ); } + BOOST_FS_FUNC(void) copy_directory( const Path & from_path, + const Path & to_path ) + { + system::error_code result = detail::copy_directory_api( + from_path.external_directory_string(), + to_path.external_directory_string() ); + if ( result != 0 ) + boost::throw_exception( basic_filesystem_error<Path>( + "boost::filesystem::copy_directory", + from_path, to_path, result ) ); + } + + BOOST_FS_FUNC(void) copy_symlink( const Path & from_path, + const Path & to_path ) + { + create_symlink(readlink(from_path),to_path); + } + + BOOST_FS_FUNC(void) copy( const Path & from_path, + const Path & to_path ) + { + file_status s(symlink_status(from_path)); + if(is_symlink(s)) + { + copy_symlink(from_path,to_path); + } + else if(is_directory(s)) + { + copy_directory(from_path,to_path); + } + else if(is_regular_file(s)) + { + copy_file(from_path,to_path); + } + else + { + boost::throw_exception( basic_filesystem_error<Path>( + "boost::filesystem::copy", + from_path, to_path, + system::error_code(system::errc::operation_not_supported, + boost::system::system_category)) ); + } + } + template< class Path > Path current_path() { @@ -536,6 +603,17 @@ } template< class Path > + Path readlink(const Path &source_ph) + { + typename Path::external_string_type ph; + system::error_code result; + if ( (result = detail::get_readlink_api( source_ph.external_file_string(), ph )) != 0 ) + boost::throw_exception( basic_filesystem_error<Path>( + "boost::filesystem::current_path", result ) ); + return Path( Path::traits_type::to_internal( ph ) ); + } + + template< class Path > const Path & initial_path() { static Path init_path; @@ -676,6 +754,11 @@ inline space_info space( const wpath & ph ) { return space<wpath>( ph ); } + inline boost::uintmax_t nlink( const path & ph ) + { return nlink<path>( ph ); } + inline boost::uintmax_t nlink( const wpath & ph ) + { return nlink<wpath>( ph ); } + inline std::time_t last_write_time( const path & ph ) { return last_write_time<path>( ph ); } inline std::time_t last_write_time( const wpath & ph ) @@ -736,6 +819,21 @@ inline void copy_file( const wpath & from_path, const wpath & to_path ) { return copy_file<wpath>( from_path, to_path ); } + inline void copy_directory( const path & from_path, const path & to_path ) + { return copy_directory<path>( from_path, to_path ); } + inline void copy_directory( const wpath & from_path, const wpath & to_path ) + { return copy_directory<wpath>( from_path, to_path ); } + + inline void copy_symlink( const path & from_path, const path & to_path ) + { return copy_symlink<path>( from_path, to_path ); } + inline void copy_symlink( const wpath & from_path, const wpath & to_path ) + { return copy_symlink<wpath>( from_path, to_path ); } + + inline void copy( const path & from_path, const path & to_path ) + { return copy<path>( from_path, to_path ); } + inline void copy( const wpath & from_path, const wpath & to_path ) + { return copy<wpath>( from_path, to_path ); } + inline path system_complete( const path & ph ) { return system_complete<path>( ph ); } inline wpath system_complete( const wpath & ph ) Index: libs/filesystem/src/operations.cpp =================================================================== --- libs/filesystem/src/operations.cpp (revision 50613) +++ libs/filesystem/src/operations.cpp (working copy) @@ -180,6 +180,9 @@ inline bool create_directory( const std::wstring & dir ) { return ::CreateDirectoryW( dir.c_str(), 0 ) != 0; } + inline bool copy_directory( const std::wstring & from, + const std::wstring & to ) + { return ::CreateDirectoryExW( from.c_str(), to.c_str(), 0 ) != 0; } #if _WIN32_WINNT >= 0x500 inline bool create_hard_link( const std::wstring & to_ph, const std::wstring & from_ph ) @@ -371,6 +374,26 @@ return result; } + + template< class String > + boost::filesystem::detail::uintmax_pair + nlink_template( const String & ph ) + { + // Link count info is only available through GetFileInformationByHandle + handle_wrapper p1( + create_file( ph1.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); + int error1(0); // save error code in case we have to throw + if ( p1.handle == INVALID_HANDLE_VALUE ) + error1 = ::GetLastError(); + // at this point, the handle is known to be valid + BY_HANDLE_FILE_INFORMATION info1; + if ( !::GetFileInformationByHandle( p1.handle, &info1 ) ) + { return std::make_pair( ::GetLastError(), false ); } + return std::make_pair( 0,info1.nNumberOfLinks); + } + inline DWORD get_current_directory( DWORD sz, char * buf ) { return ::GetCurrentDirectoryA( sz, buf ); } @@ -556,6 +579,19 @@ return std::make_pair( error, false ); } + inline bool copy_directory( const std::string & from, + const std::string & to ) + { return ::CreateDirectoryExA( from.c_str(), to.c_str(), 0 ) != 0; } + + template<class String> + boost::filesystem::detail::query_pair + copy_directory_template( const String & from, const String & to ) + { + if ( copy_directory( from, to ) ) + return std::make_pair( error_code(0), true ); + return std::make_pair( error_code(::GetLastError()), false ); + } + #if _WIN32_WINNT >= 0x500 inline bool create_hard_link( const std::string & to_ph, const std::string & from_ph ) @@ -656,6 +692,15 @@ { return space_template( ph ); } BOOST_FILESYSTEM_DECL + fs::detail::uintmax_pair nlink_api( const std::wstring & ph ) + { return nlink_template( ph ); } + + BOOST_FILESYSTEM_DECL + system::error_code + get_readlink_api( const std::wstring &source_ph, std::wstring & ph ) + { return ERROR_NOT_SUPPORTED; } + + BOOST_FILESYSTEM_DECL error_code get_current_path_api( std::wstring & ph ) { return get_current_path_template( ph ); } @@ -681,6 +726,10 @@ create_directory_api( const std::wstring & ph ) { return create_directory_template( ph ); } + BOOST_FILESYSTEM_DECL error_code + copy_directory_api( const std::wstring & from, const std::wstring & to ) + { return copy_directory_template(from,to); } + #if _WIN32_WINNT >= 0x500 BOOST_FILESYSTEM_DECL error_code create_hard_link_api( const std::wstring & to_ph, @@ -834,6 +883,15 @@ { return space_template( ph ); } BOOST_FILESYSTEM_DECL + fs::detail::uintmax_pair nlink_api( const std::string & ph ) + { return nlink_template( ph ); } + + BOOST_FILESYSTEM_DECL + system::error_code + get_readlink_api( const std::string & source_ph, std::string & ph ) + { return ERROR_NOT_SUPPORTED; } + + BOOST_FILESYSTEM_DECL error_code get_current_path_api( std::string & ph ) { return get_current_path_template( ph ); } @@ -859,6 +917,10 @@ create_directory_api( const std::string & ph ) { return create_directory_template( ph ); } + BOOST_FILESYSTEM_DECL system::error_code + copy_directory_api( const std::string & from, const std::string & to ) + { return copy_directory_template(from,to); } + #if _WIN32_WINNT >= 0x500 BOOST_FILESYSTEM_DECL error_code create_hard_link_api( const std::string & to_ph, @@ -1088,6 +1150,16 @@ return result; } + BOOST_FILESYSTEM_DECL uintmax_pair + nlink_api( const std::string & ph ) + { + struct stat path_stat; + if ( ::stat( ph.c_str(), &path_stat ) != 0 ) + return std::make_pair( error_code( errno, system_category ), 0 ); + return std::make_pair( ok, + static_cast<boost::uintmax_t>(path_stat.st_nlink) ); + } + BOOST_FILESYSTEM_DECL time_pair last_write_time_api( const std::string & ph ) { @@ -1109,6 +1181,31 @@ return error_code( ::utime( ph.c_str(), &buf ) != 0 ? errno : 0, system_category ); } + BOOST_FILESYSTEM_DECL system::error_code + get_readlink_api( const std::string & source_ph, std::string & ph ) + { + for ( std::size_t path_max = 32;; path_max *=2 ) // loop 'til buffer large enough + { + boost::scoped_array<char> + buf( new char[path_max] ); + ssize_t result; + if ( (result=::readlink( source_ph.c_str(), buf.get(), + path_max) ) == -1 ) + { + return system::error_code(errno,system::system_category); + } + else + { + if(result!=static_cast<ssize_t>(path_max)) + { + ph = buf.get(); + break; + } + } + } + return system::error_code(0,system::system_category); + } + BOOST_FILESYSTEM_DECL error_code get_current_path_api( std::string & ph ) { @@ -1154,6 +1251,17 @@ return std::make_pair( ok, false ); } + BOOST_FILESYSTEM_DECL system::error_code + copy_directory_api( const std::string & from_dir_ph, + const std::string & to_dir_ph ) + { + struct stat from_stat; + if ( (::stat( from_dir_ph.c_str(), &from_stat ) != 0) + || ::mkdir(to_dir_ph.c_str(),from_stat.st_mode)!=0) + return system::error_code(errno,system::system_category); + return system::error_code(0,system::system_category); + } + BOOST_FILESYSTEM_DECL error_code create_hard_link_api( const std::string & to_ph, const std::string & from_ph )

On Wed, Jan 14, 2009 at 04:00, Walter Landry <wlandry@caltech.edu> wrote:
A long, long time ago, I proposed adding a few more convenience functions to filesystem.
http://lists.boost.org/Archives/boost/2006/08/109740.php
Despite a positive response and a followup patch, those functions never got incorporated. Did it just fall through the cracks, or was there a more substantive reason those functions never got added? Otherwise, it does not seem possible to implement "cp -a".
I'm quite interested in readlink, since it's a prerequisite for uncomplete ( https://svn.boost.org/trac/boost/ticket/1976 ).
participants (3)
-
Beman Dawes
-
Scott McMurray
-
Walter Landry