From 775b6ff8a89cb37438e0bb6519e95994aeb2da80 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 11 May 2005 19:59:23 +0000 Subject: [PATCH] Add copy_file() for POSIX, full operations_test now enabled and passing for POSIX and Windows [SVN r28831] --- src/exception.cpp | 1 + src/operations.cpp | 151 ++++++++++++++++++++------------------- src/path.cpp | 10 +-- test/operations_test.cpp | 29 ++++---- 4 files changed, 100 insertions(+), 91 deletions(-) diff --git a/src/exception.cpp b/src/exception.cpp index b62e67c..4f83989 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -79,6 +79,7 @@ namespace { EACCES, fs::security_error }, { EROFS, fs::read_only_error }, { EIO, fs::io_error }, + { EINVAL, fs::path_error }, { ENAMETOOLONG, fs::path_error }, { ENOENT, fs::not_found_error }, { ENOTDIR, fs::not_directory_error }, diff --git a/src/operations.cpp b/src/operations.cpp index 6223534..33f4635 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -404,22 +404,6 @@ namespace return 0; } - inline boost::filesystem::system_error_type - move_file( const char * from, const char * to ) - { return ::MoveFileA( from, to ); } - - inline boost::filesystem::system_error_type - move_file( const wchar_t * from, const wchar_t * to ) - { return ::MoveFileW( from, to ); } - - template - boost::filesystem::system_error_type - inline rename_template( const String & from, const String & to ) - { - return move_file( from.c_str(), to.c_str() ) - ? 0 : ::GetLastError(); - } - inline bool create_directory( const std::string & dir ) { return ::CreateDirectoryA( dir.c_str(), 0 ) != 0; } inline bool create_directory( const std::wstring & dir ) @@ -585,11 +569,31 @@ namespace boost BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type rename_api( const std::string & from, const std::string & to ) - { return rename_template( from, to ); } + { + return ::MoveFileA( from.c_str(), to.c_str() ) + ? 0 : ::GetLastError(); + } BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type rename_api( const std::wstring & from, const std::wstring & to ) - { return rename_template( from, to ); } + { + return ::MoveFileW( from.c_str(), to.c_str() ) + ? 0 : ::GetLastError(); + } + + BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type + copy_file_api( const std::string & from, const std::string & to ) + { + return ::CopyFileA( from.c_str(), to.c_str(), /*fail_if_exists=*/true ) + ? 0 : ::GetLastError(); + } + + BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type + copy_file_api( const std::wstring & from, const std::wstring & to ) + { + return ::CopyFileW( from.c_str(), to.c_str(), /*fail_if_exists=*/true ) + ? 0 : ::GetLastError(); + } BOOST_FILESYSTEM_DECL bool create_file_api( const std::wstring & ph, std::ios_base::openmode mode ) // true if succeeds @@ -854,9 +858,21 @@ namespace boost return 0; } + BOOST_FILESYSTEM_DECL fs::detail::query_pair + create_directory_api( const std::string & ph ) + { + if ( ::mkdir( ph.c_str(), S_IRWXU|S_IRWXG|S_IRWXO ) == 0 ) + { return std::make_pair( 0, true ); } + if ( errno != EEXIST ) + { return std::make_pair( errno, false ); } + if ( status_api( ph ) != fs::directory_flag ) + { return std::make_pair( ENOTDIR, false ); } + return std::make_pair( 0, false ); + } + BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type create_hard_link_api( const std::string & existing_ph, - const std::string & new__ph ) + const std::string & new_ph ) { // we don't allow hard links to directories; too non-portable if ( status_api( existing_ph ) == fs::directory_flag ) @@ -892,6 +908,50 @@ namespace boost ? errno : 0; } + BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type + copy_file_api( const std::string & from_file_ph, + const std::string & to_file_ph ) + { + const std::size_t buf_sz = 32768; + boost::scoped_array buf( new char [buf_sz] ); + int infile=0, outfile=0; // init quiets compiler warning + struct stat from_stat; + + if ( ::stat( from_file_ph.c_str(), &from_stat ) != 0 + || (infile = ::open( from_file_ph.c_str(), + O_RDONLY )) < 0 + || (outfile = ::open( to_file_ph.c_str(), + O_WRONLY | O_CREAT | O_EXCL, + from_stat.st_mode )) < 0 ) + { + if ( infile >= 0 ) ::close( infile ); + return errno; + } + + ssize_t sz, sz_read=1, sz_write; + while ( sz_read > 0 + && (sz_read = ::read( infile, buf.get(), buf_sz )) > 0 ) + { + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + sz_write = 0; + do + { + if ( (sz = ::write( outfile, buf.get(), sz_read - sz_write )) < 0 ) + { + sz_read = sz; // cause read loop termination + break; // and error to be thrown after closes + } + sz_write += sz; + } while ( sz_write < sz_read ); + } + + if ( ::close( infile) < 0 ) sz_read = -1; + if ( ::close( outfile) < 0 ) sz_read = -1; + + return sz_read < 0 ? errno : 0; + } + BOOST_FILESYSTEM_DECL boost::filesystem::system_error_type dir_itr_first( void *& handle, const std::string & dir, std::string & target ) @@ -949,56 +1009,3 @@ namespace boost } // namespace detail } // namespace filesystem } // namespace boost - -#if 0 - -namespace boost -{ - namespace filesystem - { - - - BOOST_FILESYSTEM_DECL void copy_file( const path & from_file_ph, - const path & to_file_ph ) - { -# ifdef BOOST_POSIX_API - // TODO: Ask POSIX experts if this is the best way to copy a file - - const std::size_t buf_sz = 32768; - boost::scoped_array buf( new char [buf_sz] ); - int infile=0, outfile=0; // init quiets compiler warning - struct stat from_stat; - - if ( ::stat( from_file_ph.string().c_str(), &from_stat ) != 0 - || (infile = ::open( from_file_ph.string().c_str(), - O_RDONLY )) < 0 - || (outfile = ::open( to_file_ph.string().c_str(), - O_WRONLY | O_CREAT | O_EXCL, - from_stat.st_mode )) < 0 ) - { - if ( infile != 0 ) ::close( infile ); - boost::throw_exception( filesystem_error( - "boost::filesystem::copy_file", - from_file_ph, to_file_ph, fs::detail::system_error_code() ) ); - } - - ssize_t sz; - while ( (sz = ::read( infile, buf.get(), buf_sz )) > 0 - && (sz = ::write( outfile, buf.get(), sz )) > 0 ) {} - - ::close( infile ); - ::close( outfile ); - - if ( sz != 0 ) -# else - if ( !::CopyFileA( from_file_ph.string().c_str(), - to_file_ph.string().c_str(), /*fail_if_exists=*/true ) ) -# endif - boost::throw_exception( filesystem_error( - "boost::filesystem::copy_file", - from_file_ph, to_file_ph, fs::detail::system_error_code() ) ); - } - - } // namespace filesystem -} // namespace boost -#endif diff --git a/src/path.cpp b/src/path.cpp index 1b0e967..0c87b99 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -20,6 +20,8 @@ #include "../src//utf8_codecvt_facet.hpp" #include +#include + namespace { // for operating systems where UTF-8 is not the preferred external @@ -47,9 +49,9 @@ namespace boost if ( convertor.out( state, src.c_str(), src.c_str()+src.size(), from_next, work.get(), work.get()+work_size, to_next ) != std::codecvt_base::ok ) - boost::throw_exception( wfilesystem_error( + boost::throw_exception( boost::filesystem::wfilesystem_error( "boost::filesystem::wpath::to_external conversion error", - ph, path_error ) ); + ph, EINVAL ) ); *to_next = '\0'; return external_string_type( work.get() ); } @@ -65,8 +67,8 @@ namespace boost if ( convertor.in( state, src.c_str(), src.c_str()+src.size(), from_next, work.get(), work.get()+work_size, to_next ) != std::codecvt_base::ok ) - boost::throw_exception( wfilesystem_error( - "boost::filesystem::wpath::to_internal conversion error" ) ); + boost::throw_exception( boost::filesystem::wfilesystem_error( + "boost::filesystem::wpath::to_internal conversion error", EINVAL ) ); *to_next = L'\0'; return internal_string_type( work.get() ); } diff --git a/test/operations_test.cpp b/test/operations_test.cpp index 11219da..73757ae 100644 --- a/test/operations_test.cpp +++ b/test/operations_test.cpp @@ -349,29 +349,28 @@ int test_main( int argc, char * argv[] ) // [case 1] make sure can't rename() a non-existent file BOOST_CHECK( !fs::exists( d1 / "f99" ) ); BOOST_CHECK( !fs::exists( d1 / "f98" ) ); -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, d1 / "f99", d1 / "f98" ), -/// fs::not_found_error ) ); -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, fs::path(""), d1 / "f98" ), -/// fs::not_found_error ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, d1 / "f99", d1 / "f98" ), + fs::not_found_error ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, fs::path(""), d1 / "f98" ), + fs::not_found_error ) ); // [case 2] rename() target.empty() -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, file_ph, "" ), -/// fs::not_found_error ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, file_ph, "" ), + fs::not_found_error ) ); -#if 0 // [case 3] make sure can't rename() to an existent file or directory -/// BOOST_CHECK( fs::exists( dir / "f1" ) ); + BOOST_CHECK( fs::exists( dir / "f1" ) ); BOOST_CHECK( fs::exists( d1 / "f2" ) ); -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", d1 / "f2" ) ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", d1 / "f2" ) ) ); // several POSIX implementations (cygwin, openBSD) report ENOENT instead of EEXIST, // so we don't verify error type on the above test. -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, dir, d1 ) ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, dir, d1 ) ) ); // [case 4A] can't rename() file to a nonexistent parent directory BOOST_CHECK( !fs::is_directory( dir / "f1" ) ); BOOST_CHECK( !fs::exists( dir / "d3/f3" ) ); -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", dir / "d3/f3" ), -/// fs::not_found_error ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, dir / "f1", dir / "d3/f3" ), + fs::not_found_error ) ); // [case 4B] rename() file in same directory BOOST_CHECK( fs::exists( d1 / "f2" ) ); @@ -397,8 +396,8 @@ int test_main( int argc, char * argv[] ) BOOST_CHECK( fs::exists( d1 ) ); BOOST_CHECK( !fs::exists( dir / "d3/d5" ) ); BOOST_CHECK( !fs::exists( dir / "d3" ) ); -/// BOOST_CHECK( throws_fs_error( bind( fs::rename, d1, dir / "d3/d5" ), -/// fs::not_found_error ) ); + BOOST_CHECK( throws_fs_error( bind( fs::rename, d1, dir / "d3/d5" ), + fs::not_found_error ) ); // [case 5B] rename() on directory fs::path d3( dir / "d3" ); @@ -428,7 +427,7 @@ int test_main( int argc, char * argv[] ) BOOST_CHECK( fs::exists( d1 ) ); BOOST_CHECK( !fs::exists( d2 / "d20" ) ); BOOST_CHECK( fs::exists( d1 / "f2" ) ); -#endif + // remove() tests on file file_ph = dir / "shortlife"; BOOST_CHECK( !fs::exists( file_ph ) );