Add copy_file() for POSIX, full operations_test now enabled and passing for POSIX and Windows

[SVN r28831]
This commit is contained in:
Beman Dawes
2005-05-11 19:59:23 +00:00
parent 999dc0a4f2
commit 775b6ff8a8
4 changed files with 100 additions and 91 deletions

View File

@@ -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 },

View File

@@ -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<class String>
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<char> 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<char> 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

View File

@@ -20,6 +20,8 @@
#include "../src//utf8_codecvt_facet.hpp"
#include <boost/scoped_array.hpp>
#include <cerrno>
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() );
}

View File

@@ -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<fs::path>, d1 / "f99", d1 / "f98" ),
fs::not_found_error ) );
BOOST_CHECK( throws_fs_error( bind( fs::rename<fs::path>, 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<fs::path>, 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<fs::path>, 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<fs::path>, 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<fs::path>, 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<fs::path>, 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 ) );