Boost logo

Boost :

Subject: Re: [boost] Extra functions for filesystem
From: Walter Landry (wlandry_at_[hidden])
Date: 2009-01-16 13:23:42


"Beman Dawes" <bdawes_at_[hidden]> 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_at_[hidden]

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 )


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk