mirror of
https://github.com/boostorg/filesystem.git
synced 2026-01-29 19:42:08 +00:00
Add copy_file() for POSIX, full operations_test now enabled and passing for POSIX and Windows
[SVN r28831]
This commit is contained in:
@@ -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 },
|
||||
|
||||
@@ -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
|
||||
|
||||
10
src/path.cpp
10
src/path.cpp
@@ -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() );
|
||||
}
|
||||
|
||||
@@ -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 ) );
|
||||
|
||||
Reference in New Issue
Block a user