Refactored copy_file, added copy_options, deprecated copy_option.

The copy_file operation implementation has been inlined into the
detail::copy_file function. The part that copies the file body has been
extracted to a separate function, so that addition of specialized copy
implementations later is possible.

Added copy_options enum, which reflects the enum from C++20. Currently,
only overwrite_existing option is supported. Other options will be added
later.

The old enum copy_option is deprecated in favor of copy_options.

Updated docs to reflect recent changes to copy_file behavior.
This commit is contained in:
Andrey Semashev 2020-05-05 18:25:30 +03:00
parent 4f3d762a31
commit f199152b7d
6 changed files with 212 additions and 154 deletions

View File

@ -748,7 +748,7 @@ nothing else.&quot;</p>
{
status_error, file_not_found, regular_file, directory_file,
symlink_file, block_file, character_file, fifo_file, socket_file,
type_unknown
reparse_file, type_unknown
};
enum <a href="#Enum-perms">perms</a>
@ -771,16 +771,23 @@ nothing else.&quot;</p>
uintmax_t available; // free space available to non-privileged process
};
enum class <a name="copy_options">copy_options</a>
{
none,
overwrite_existing
};
// Deprecated, use <a href="#copy_options">copy_options</a> instead
enum class <a name="copy_option">copy_option</a>
{
none
none = copy_options::none,
fail_if_exists = none,
overwrite_if_exists
overwrite_if_exists = copy_options::overwrite_existing
};
enum class <a name="directory_options">directory_options</a>
{
none
none,
skip_permission_denied,
follow_directory_symlink,
pop_on_error
@ -789,7 +796,7 @@ nothing else.&quot;</p>
// Deprecated, use <a href="#directory_options">directory_options</a> instead
enum class <a name="symlink_option">symlink_option</a>
{
none = directory_options::none
none = directory_options::none,
no_recurse = none,
recurse = directory_options::follow_directory_symlink
};
@ -815,9 +822,14 @@ nothing else.&quot;</p>
void <a href="#copy_file">copy_file</a>(const path&amp; from, const path&amp; to,
system::error_code&amp; ec);
void <a href="#copy_file">copy_file</a>(const path&amp; from, const path&amp; to,
<a href="#copy_option">copy_option</a> option);
<a href="#copy_options">copy_options</a> options);
void <a href="#copy_file">copy_file</a>(const path&amp; from, const path&amp; to,
<a href="#copy_option">copy_option</a> option, system::error_code&amp; ec);
<a href="#copy_options">copy_options</a> options, system::error_code&amp; ec);
// Deprecated, use overloads taking <a href="#copy_options">copy_options</a> instead
void <a href="#copy_file">copy_file</a>(const path&amp; from, const path&amp; to,
<a href="#copy_option">copy_option</a> options);
void <a href="#copy_file">copy_file</a>(const path&amp; from, const path&amp; to,
<a href="#copy_option">copy_option</a> options, system::error_code&amp; ec);
void <a href="#copy_symlink">copy_symlink</a>(const path&amp; existing_symlink,
const path&amp; new_symlink);
@ -3078,7 +3090,7 @@ if(is_symlink(s))
else if(is_directory(s))
copy_directory(from, to<i>[</i><code>, ec</code><i>]</i>);
else if(is_regular_file(s))
copy_file(from, to, copy_option::fail_if_exists<i>[</i><code>, ec</code><i>]</i>);
copy_file(from, to, copy_options::none<i>[</i><code>, ec</code><i>]</i>);
else
<i> Report error as specified in <a href="#Error-reporting">Error reporting</a>.</i></pre>
</blockquote>
@ -3123,16 +3135,26 @@ void copy_directory(const path&amp; from, const path&amp; to, system::error_code
<pre>void copy_file(const path&amp; from, const path&amp; to);
void copy_file(const path&amp; from, const path&amp; to, system::error_code&amp; ec);</pre>
<blockquote>
<p><i>Effects: </i><code>copy_file(from, to, copy_option::fail_if_exists</code><i>[</i><code>, ec</code><i>]</i><code>)</code>.</p>
<p><i>Effects: </i><code>copy_file(from, to, copy_options::none</code><i>[</i><code>, ec</code><i>]</i><code>)</code>.</p>
<p><i>Throws:</i> As specified in <a href="#Error-reporting">Error reporting</a>.</p>
</blockquote>
<pre>void <a name="copy_file">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_option">copy_option</a> option);
void <a name="copy_file2">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_option">copy_option</a> option, system::error_code&amp; ec);</pre>
<pre>void <a name="copy_file">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_options">copy_options</a> options);
void <a name="copy_file2">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_options">copy_options</a> options, system::error_code&amp; ec);
void <a name="copy_file3">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_option">copy_option</a> options);
void <a name="copy_file4">copy_file</a>(const path&amp; from, const path&amp; to, <a href="#copy_option">copy_option</a> options, system::error_code&amp; ec);</pre>
<blockquote>
<p><i>Effects:</i> If <code>option == copy_option::</code><code>fail_if_exists &amp;&amp; exists(to)</code>, an error is reported. Otherwise, the contents and attributes of the file <code>from</code> resolves to are copied to the file <code>to</code> resolves to.</p>
<p><i>Effects:</i> Report an error if:
<ul>
<li><code>!is_regular_file(from)</code>, or</li>
<li><code>exists(to) &amp;&amp; !is_regular_file(to)</code>, or</li>
<li><code>exists(to) &amp;&amp; equivalent(from, to)</code>, or</li>
<li><code>exists(to) &amp;&amp; (options & copy_options::overwrite_existing) == copy_options::none</code>.</li>
</ul>
Otherwise, the contents and attributes of the file <code>from</code> resolves to are copied to the file <code>to</code> resolves to.</p>
<p><i>Throws:</i> As specified in <a href="#Error-reporting">Error reporting</a>.</p>
<p>[<i>Note:</i> The overloads taking <a href="#copy_option"><code>copy_option</code></a> are deprecated. Their effect is equivalent to the corresponding overloads taking <a href="#copy_options"><code>copy_options</code></a> after casting the <code>options</code> argument to <a href="#copy_options"><code>copy_options</code></a>.]</p>
</blockquote>
<pre>void <a name="copy_symlink">copy_symlink</a>(const path&amp; existing_symlink, const path&amp; new_symlink);
void copy_symlink(const path&amp; existing_symlink, const path&amp; new_symlink, system::error_code&amp; ec);</pre>

View File

@ -45,6 +45,7 @@
<li>Fixed that <code>read_symlink</code> on Windows could potentially fail or cause failures elsewhere with a sharing violation error, if the same symlink was opened concurrently. (<a href="https://github.com/boostorg/filesystem/issues/138">#138</a>)</li>
<li><code>copy_file</code> implementation has been updated to perform checks on the source and target files, as required by C++20 ([fs.op.copy.file]/4.1). In particular, the operation will fail if the source or target file is not a regular file or the source and target paths identify the same file.</li>
<li><code>copy_file</code> on POSIX systems will now also copy the source file permissions to the target file, if the target file is overwritten.</li>
<li><b>Deprecated:</b> The <code>copy_option</code> enumeration that is used with the <code>copy_file</code> operation is deprecated. As a replacement, the new enum <code>copy_options</code> (note the trailing 's') has been added. The new enum contains values similar to the <code>copy_options</code> enum from C++20. The old enum values are mapped onto the new enum. The old enum will be removed in a future release.</li>
<li><code>equivalent</code> on POSIX systems now returns the actual error code from the OS if one of the paths does not resolve to a file. Previously the function would return an error code of 1. (<a href="https://github.com/boostorg/filesystem/issues/141">#141</a>)</li>
<li><code>equivalent</code> no longer considers file size and last modification time in order to test whether the two paths refer to the same file. These checks could result in a false negative if the file was modified during the <code>equivalent</code> call.</li>
<li><code>space</code> now initializes the <code>space_info</code> structure members to -1 values on error, as required by C++20 ([fs.op.space]/1).</li>

View File

@ -31,6 +31,7 @@
#include <boost/filesystem/directory.hpp>
#endif
#include <boost/detail/bitmask.hpp>
#include <boost/core/scoped_enum.hpp>
#include <boost/system/error_code.hpp>
#include <boost/cstdint.hpp>
@ -52,9 +53,24 @@ struct space_info
boost::uintmax_t available; // <= free
};
BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(copy_options, unsigned int)
{
none = 0u, // Default, error if the target file exists
overwrite_existing = 1u, // Overwrite existing file
}
BOOST_SCOPED_ENUM_DECLARE_END(copy_options)
BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(copy_options))
#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
BOOST_SCOPED_ENUM_DECLARE_BEGIN(copy_option)
{none=0, fail_if_exists = none, overwrite_if_exists}
{
none = static_cast< unsigned int >(copy_options::none),
fail_if_exists = none,
overwrite_if_exists = static_cast< unsigned int >(copy_options::overwrite_existing)
}
BOOST_SCOPED_ENUM_DECLARE_END(copy_option)
#endif
//--------------------------------------------------------------------------------------//
// implementation details //
@ -62,11 +78,6 @@ BOOST_SCOPED_ENUM_DECLARE_END(copy_option)
namespace detail {
// We cannot pass a BOOST_SCOPED_ENUM to a compled function because it will result
// in an undefined reference if the library is compled with -std=c++0x but the use
// is compiled in C++03 mode, or vice versa. See tickets 6124, 6779, 10038.
enum copy_option {none=0, fail_if_exists = none, overwrite_if_exists};
BOOST_FILESYSTEM_DECL
file_status status(const path&p, system::error_code* ec=0);
BOOST_FILESYSTEM_DECL
@ -83,7 +94,7 @@ BOOST_FILESYSTEM_DECL
void copy_directory(const path& from, const path& to, system::error_code* ec=0);
BOOST_FILESYSTEM_DECL
void copy_file(const path& from, const path& to, // See ticket #2925
detail::copy_option option, system::error_code* ec=0);
unsigned int options, system::error_code* ec=0); // see copy_options for options
BOOST_FILESYSTEM_DECL
void copy_symlink(const path& existing_symlink, const path& new_symlink, system::error_code* ec=0);
BOOST_FILESYSTEM_DECL
@ -246,28 +257,42 @@ inline
void copy_directory(const path& from, const path& to, system::error_code& ec) BOOST_NOEXCEPT
{detail::copy_directory(from, to, &ec);}
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_option) option)
{
detail::copy_file(from, to, static_cast<detail::copy_option>(option));
}
inline
void copy_file(const path& from, const path& to)
{
detail::copy_file(from, to, detail::fail_if_exists);
}
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_option) option, system::error_code& ec) BOOST_NOEXCEPT
{
detail::copy_file(from, to, static_cast<detail::copy_option>(option), &ec);
detail::copy_file(from, to, static_cast< unsigned int >(copy_options::none));
}
inline
void copy_file(const path& from, const path& to, system::error_code& ec) BOOST_NOEXCEPT
{
detail::copy_file(from, to, detail::fail_if_exists, &ec);
detail::copy_file(from, to, static_cast< unsigned int >(copy_options::none), &ec);
}
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_options) options)
{
detail::copy_file(from, to, static_cast< unsigned int >(options));
}
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_options) options, system::error_code& ec) BOOST_NOEXCEPT
{
detail::copy_file(from, to, static_cast< unsigned int >(options), &ec);
}
#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_option) options)
{
detail::copy_file(from, to, static_cast< unsigned int >(options));
}
inline
void copy_file(const path& from, const path& to, // See ticket #2925
BOOST_SCOPED_ENUM_NATIVE(copy_option) options, system::error_code& ec) BOOST_NOEXCEPT
{
detail::copy_file(from, to, static_cast< unsigned int >(options), &ec);
}
#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
inline
void copy_symlink(const path& existing_symlink,
const path& new_symlink) {detail::copy_symlink(existing_symlink, new_symlink);}

View File

@ -254,7 +254,6 @@ union reparse_data_buffer
# define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
# define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
|| ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
# define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
# define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
@ -267,7 +266,6 @@ union reparse_data_buffer
# define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
# define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
# define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
# define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
# define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0)
# define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
# define BOOST_READ_SYMLINK(P,T)
@ -397,6 +395,21 @@ boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
BOOST_CONSTEXPR_OR_CONST char dot = '.';
struct fd_wrapper
{
int fd;
fd_wrapper() BOOST_NOEXCEPT : fd(-1) {}
explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {}
~fd_wrapper() BOOST_NOEXCEPT
{
if (fd >= 0)
::close(fd);
}
BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&))
BOOST_DELETED_FUNCTION(fd_wrapper& operator= (fd_wrapper const&))
};
inline bool not_found_error(int errval) BOOST_NOEXCEPT
{
return errval == ENOENT || errval == ENOTDIR;
@ -410,78 +423,15 @@ inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BO
return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino;
}
bool // true if ok
copy_file_api(const std::string& from_p,
const std::string& to_p, bool fail_if_exists)
typedef int (copy_file_data_t)(int infile, struct ::stat const& from_stat, int outfile, struct ::stat const& to_stat);
//! copy_file implementation that uses read/write loop
int copy_file_data_read_write(int infile, struct ::stat const& from_stat, int outfile, struct ::stat const& to_stat)
{
int err = 0;
int infile = ::open(from_p.c_str(), O_RDONLY | O_CLOEXEC);
if (BOOST_UNLIKELY(infile < 0))
return false;
struct ::stat from_stat = {};
if (BOOST_UNLIKELY(::fstat(infile, &from_stat) != 0))
{
err = errno;
fail1:
::close(infile);
errno = err;
return false;
}
if (BOOST_UNLIKELY(!S_ISREG(from_stat.st_mode)))
{
err = ENOSYS;
goto fail1;
}
// Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
// which checks the file permission on the server, even if the client's file descriptor supports writing.
mode_t to_mode = from_stat.st_mode | S_IWUSR;
int oflag = O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC;
if (fail_if_exists)
oflag |= O_EXCL;
int outfile = ::open(to_p.c_str(), oflag, to_mode);
if (BOOST_UNLIKELY(outfile < 0))
{
err = errno;
goto fail1;
}
struct ::stat to_stat = {};
if (BOOST_UNLIKELY(::fstat(outfile, &to_stat) != 0))
{
err = errno;
fail2:
::close(outfile);
::close(infile);
errno = err;
return false;
}
if (BOOST_UNLIKELY(!S_ISREG(to_stat.st_mode)))
{
err = ENOSYS;
goto fail2;
}
if (BOOST_UNLIKELY(equivalent_stat(from_stat, to_stat)))
{
err = EEXIST;
goto fail2;
}
BOOST_CONSTEXPR_OR_CONST std::size_t buf_sz = 65536u;
boost::scoped_array<char> buf(new (std::nothrow) char [buf_sz]);
boost::scoped_array<char> buf(new (std::nothrow) char[buf_sz]);
if (BOOST_UNLIKELY(!buf.get()))
{
err = ENOMEM;
goto fail2;
}
return ENOMEM;
while (true)
{
@ -490,10 +440,10 @@ copy_file_api(const std::string& from_p,
break;
if (BOOST_UNLIKELY(sz_read < 0))
{
err = errno;
int err = errno;
if (err == EINTR)
continue;
goto fail2;
return err;
}
// Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
@ -503,50 +453,22 @@ copy_file_api(const std::string& from_p,
ssize_t sz = ::write(outfile, buf.get() + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote));
if (BOOST_UNLIKELY(sz < 0))
{
err = errno;
int err = errno;
if (err == EINTR)
continue;
goto fail2;
return err;
}
sz_wrote += sz;
}
}
// If we created a new file with an explicitly added S_IWUSR permission,
// we may need to update its mode bits to match the source file.
if (to_stat.st_mode != from_stat.st_mode)
{
if (BOOST_UNLIKELY(::fchmod(outfile, from_stat.st_mode) != 0))
{
err = errno;
goto fail2;
}
}
// Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
// Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
// file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
// underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
// ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
// care at that point.
#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC)
err = ::fdatasync(outfile);
#else
err = ::fsync(outfile);
#endif
if (BOOST_UNLIKELY(err != 0))
{
err = errno;
goto fail2;
}
::close(outfile);
::close(infile);
return true;
return 0;
}
//! Pointer to the actual implementation of the copy_file_data implementation
copy_file_data_t* copy_file_data = &copy_file_data_read_write;
inline fs::file_type query_file_type(const path& p, error_code* ec)
{
return fs::detail::symlink_status(p, ec).type();
@ -560,8 +482,6 @@ inline fs::file_type query_file_type(const path& p, error_code* ec)
// //
//--------------------------------------------------------------------------------------//
BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128;
BOOST_CONSTEXPR_OR_CONST wchar_t dot = L'.';
// Windows CE has no environment variables
@ -627,13 +547,16 @@ void to_FILETIME(std::time_t t, FILETIME & ft)
struct handle_wrapper
{
HANDLE handle;
handle_wrapper(HANDLE h)
: handle(h){}
~handle_wrapper()
handle_wrapper() BOOST_NOEXCEPT : handle(INVALID_HANDLE_VALUE) {}
explicit handle_wrapper(HANDLE h) BOOST_NOEXCEPT : handle(h) {}
~handle_wrapper() BOOST_NOEXCEPT
{
if (handle != INVALID_HANDLE_VALUE)
::CloseHandle(handle);
}
BOOST_DELETED_FUNCTION(handle_wrapper(handle_wrapper const&))
BOOST_DELETED_FUNCTION(handle_wrapper& operator= (handle_wrapper const&))
};
HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
@ -950,7 +873,7 @@ void copy(const path& from, const path& to, system::error_code* ec)
}
else if (is_regular_file(s))
{
detail::copy_file(from, to, detail::fail_if_exists, ec);
detail::copy_file(from, to, static_cast< unsigned int >(copy_options::none), ec);
}
else
{
@ -972,11 +895,96 @@ void copy_directory(const path& from, const path& to, system::error_code* ec)
}
BOOST_FILESYSTEM_DECL
void copy_file(const path& from, const path& to, copy_option option, error_code* ec)
void copy_file(const path& from, const path& to, unsigned int options, error_code* ec)
{
error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
option == fail_if_exists) ? BOOST_ERRNO : 0,
from, to, ec, "boost::filesystem::copy_file");
if (ec)
ec->clear();
#if defined(BOOST_POSIX_API)
int err = 0;
fd_wrapper infile(::open(from.c_str(), O_RDONLY | O_CLOEXEC));
if (BOOST_UNLIKELY(infile.fd < 0))
{
fail_errno:
err = errno;
fail:
error(err, from, to, ec, "boost::filesystem::copy_file");
return;
}
struct ::stat from_stat = {};
if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0))
goto fail_errno;
if (BOOST_UNLIKELY(!S_ISREG(from_stat.st_mode)))
{
err = ENOSYS;
goto fail;
}
// Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
// which checks the file permission on the server, even if the client's file descriptor supports writing.
mode_t to_mode = from_stat.st_mode | S_IWUSR;
int oflag = O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC;
if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u)
oflag |= O_EXCL;
fd_wrapper outfile(::open(to.c_str(), oflag, to_mode));
if (BOOST_UNLIKELY(outfile.fd < 0))
goto fail_errno;
struct ::stat to_stat = {};
if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0))
goto fail_errno;
if (BOOST_UNLIKELY(!S_ISREG(to_stat.st_mode)))
{
err = ENOSYS;
goto fail;
}
if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat)))
{
err = EEXIST;
goto fail;
}
err = detail::copy_file_data(infile.fd, from_stat, outfile.fd, to_stat);
if (BOOST_UNLIKELY(err != 0))
goto fail; // err already contains the error code
// If we created a new file with an explicitly added S_IWUSR permission,
// we may need to update its mode bits to match the source file.
if (to_stat.st_mode != from_stat.st_mode)
{
if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_stat.st_mode) != 0))
goto fail_errno;
}
// Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
// Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
// file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
// underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
// ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
// care at that point.
#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC)
err = ::fdatasync(outfile.fd);
#else
err = ::fsync(outfile.fd);
#endif
if (BOOST_UNLIKELY(err != 0))
goto fail_errno;
#else // defined(BOOST_POSIX_API)
const bool fail_if_exists = (options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u;
BOOL res = ::CopyFileW(from.c_str(), to.c_str(), fail_if_exists);
if (BOOST_UNLIKELY(!res))
error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_file");
#endif // defined(BOOST_POSIX_API)
}
BOOST_FILESYSTEM_DECL
@ -2100,6 +2108,8 @@ path system_complete(const path& p, system::error_code* ec)
if (ec != 0) ec->clear();
return p;
}
BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128;
wchar_t buf[buf_size];
wchar_t* pfn;
std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);

View File

@ -7,8 +7,8 @@ void myFunc()
{
using namespace boost::filesystem;
copy_option opt(copy_option::overwrite_if_exists);
copy_options opt(copy_options::overwrite_existing);
copy_file(path("p1"),path("p2"),copy_option::overwrite_if_exists);
copy_file(path("p1"),path("p2"),copy_options::overwrite_existing);
// copy_file(path("p1"),path("p2"),opt);
}

View File

@ -1604,14 +1604,14 @@ namespace
BOOST_TEST(copy_ex_ok);
copy_ex_ok = false;
try { fs::copy_file(f1x, d1x / "f2", fs::copy_option::fail_if_exists); }
try { fs::copy_file(f1x, d1x / "f2", fs::copy_options::none); }
catch (const fs::filesystem_error &) { copy_ex_ok = true; }
BOOST_TEST(copy_ex_ok);
create_file(d1x / "f2", "1234567890");
BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U);
copy_ex_ok = true;
try { fs::copy_file(f1x, d1x / "f2", fs::copy_option::overwrite_if_exists); }
try { fs::copy_file(f1x, d1x / "f2", fs::copy_options::overwrite_existing); }
catch (const fs::filesystem_error &) { copy_ex_ok = false; }
BOOST_TEST(copy_ex_ok);
BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 7U);