Skip to content

Commit

Permalink
Added a copy_options::ignore_attribute_errors option for copy_file/copy.
Browse files Browse the repository at this point in the history
The new option allows to ignore errors while copying file attributes
(but not file contents).

Closes #179.
  • Loading branch information
Lastique committed Jan 13, 2024
1 parent 7ff596a commit fc24312
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 18 deletions.
10 changes: 7 additions & 3 deletions doc/reference.html
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ <h2><a name="Header-filesystem-synopsis">Header <code>&lt;boost/filesystem.hpp&g
update_existing,
synchronize_data,
synchronize,
ignore_attribute_errors,
// <a href="#copy">copy</a> options
recursive,
copy_symlinks,
Expand Down Expand Up @@ -3198,6 +3199,7 @@ <h2><a name="Operational-functions">Operational functions</a> [fs.op.funcs]</h2>
<ul>
<li><code>copy_options::skip_existing</code>, <code>copy_options::overwrite_existing</code> or <code>copy_options::update_existing</code>;</li>
<li><code>copy_options::synchronize_data</code> or <code>copy_options::synchronize</code>;</li>
<li><code>copy_options::ignore_attribute_errors</code>;</li>
<li><code>copy_options::recursive</code>;</li>
<li><code>copy_options::copy_symlinks</code> or <code>copy_options::skip_symlinks</code>;</li>
<li><code>copy_options::directories_only</code>, <code>copy_options::create_symlinks</code> or <code>copy_options::create_hard_links</code>.</li>
Expand Down Expand Up @@ -3290,7 +3292,8 @@ <h2><a name="Operational-functions">Operational functions</a> [fs.op.funcs]</h2>
<p><i>Precondition:</i> <code>options</code> must contain at most one option from each of the following groups:
<ul>
<li><code>copy_options::skip_existing</code>, <code>copy_options::overwrite_existing</code> or <code>copy_options::update_existing</code>;</li>
<li><code>copy_options::synchronize_data</code> or <code>copy_options::synchronize</code>.</li>
<li><code>copy_options::synchronize_data</code> or <code>copy_options::synchronize</code>;</li>
<li><code>copy_options::ignore_attribute_errors</code>.</li>
</ul>
</p>
<p><i>Effects:</i> Report an error if:
Expand All @@ -3303,11 +3306,11 @@ <h2><a name="Operational-functions">Operational functions</a> [fs.op.funcs]</h2>
Otherwise, return successfully with no effect if:
<ul>
<li><code>exists(to) &amp;&amp; (options &amp; copy_options::skip_existing) != copy_options::none</code>, or</li>
<li><code>exists(to) &amp;&amp; (options &amp; copy_options::update_existing) != copy_options::none</code> and last write time of <code>from</code> is more recent than that of <code>to</code>.</li>
<li><code>exists(to) &amp;&amp; (options &amp; copy_options::update_existing) != copy_options::none</code> and last write time of <code>to</code> is more recent than that of <code>from</code>.</li>
</ul>
Otherwise:
<ul>
<li>The contents and attributes of the file <code>from</code> resolves to are copied to the file <code>to</code> resolves to; then</li>
<li>The contents and attributes of the file <code>from</code> resolves to are copied to the file <code>to</code> resolves to. If copying file attributes (but not contents) fails with an error and <code>(options &amp; copy_options::ignore_attribute_errors) != copy_options::none</code> then that error is ignored. After that,</li>
<li>If <code>(options &amp; copy_options::synchronize) != copy_options::none</code>, the written data and attributes are synchronized with the permanent storage; otherwise</li>
<li>If <code>(options &amp; copy_options::synchronize_data) != copy_options::none</code>, the written data is synchronized with the permanent storage.</li>
</ul>
Expand All @@ -3317,6 +3320,7 @@ <h2><a name="Operational-functions">Operational functions</a> [fs.op.funcs]</h2>
<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>
<p>[<i>Note:</i> When <code>copy_options::update_existing</code> is specified, checking the write times of <code>from</code> and <code>to</code> may not be atomic with the copy operation. Another process may create or modify the file identified by <code>to</code> after the file modification times have been checked but before copying starts. In this case the target file will be overwritten.]</p>
<p>[<i>Note:</i> The <code>copy_options::synchronize_data</code> and <code>copy_options::synchronize</code> options may have a significant performance impact. The <code>copy_options::synchronize_data</code> option may be less expensive than <code>copy_options::synchronize</code>. However, without these options, upon returning from <code>copy_file</code> it is not guaranteed that the copied file is completely written and preserved in case of a system failure. Any delayed write operations may fail after the function returns, at the point of physically writing the data to the underlying media, and this error will not be reported to the caller.]</p>
<p>[<i>Note:</i> The <code>copy_options::ignore_attribute_errors</code> option can be used when the caller does not require file attributes to be copied. The implementation is permitted to make an attempt to copy the file attributes, but still succeed the file copying operation if that attempt fails. This option may be useful with file systems that do not fully support operations of file attributes.]</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>
Expand Down
1 change: 1 addition & 0 deletions doc/release_history.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ <h2>1.85.0</h2>
<li><b>v4:</b> <code>absolute</code> now returns a path with a trailing directory separator when the input path has an empty <code>relative_path()</code>. (<a href="https://github.com/boostorg/filesystem/issues/301">#301</a>)</li>
<li>Added a <code>unique_path</code> overload taking a single <code>error_code&amp; ec</code> argument. The overload generates a unique path using the default path model.</li>
<li><code>weakly_canonical</code> now produces an absolute path if the input path is relative and contains no elements that exist in the filesystem. (<a href="https://github.com/boostorg/filesystem/issues/300">#300</a>)</li>
<li>Added a new <code>copy_options::ignore_attribute_errors</code> option for <code>copy_file</code> and <code>copy</code> operations. The new option allows to ignore possible errors while copying file attributes. (<a href="https://github.com/boostorg/filesystem/issues/179">#179</a>)</li>
<li>On Linux, <code>copy_file</code> backends based on <code>sendfile</code> and <code>copy_file_range</code> system calls will attempt to preallocate storage for the target file. This may reduce filesystem fragmentation and provide early error indication if there is not enough free space. Not all filesystems support this feature; file copying proceeds if storage preallocation is not supported.</li>
</ul>

Expand Down
25 changes: 13 additions & 12 deletions include/boost/filesystem/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,21 @@ BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(copy_options, unsigned int)
none = 0u, // Default. For copy_file: error if the target file exists. For copy: do not recurse, follow symlinks, copy file contents.

// copy_file options:
skip_existing = 1u, // Don't overwrite the existing target file, don't report an error
overwrite_existing = 1u << 1, // Overwrite existing file
update_existing = 1u << 2, // Overwrite existing file if its last write time is older than the replacement file
synchronize_data = 1u << 3, // Flush all buffered data written to the target file to permanent storage
synchronize = 1u << 4, // Flush all buffered data and attributes written to the target file to permanent storage
skip_existing = 1u, // Don't overwrite the existing target file, don't report an error
overwrite_existing = 1u << 1u, // Overwrite existing file
update_existing = 1u << 2u, // Overwrite existing file if its last write time is older than the replacement file
synchronize_data = 1u << 3u, // Flush all buffered data written to the target file to permanent storage
synchronize = 1u << 4u, // Flush all buffered data and attributes written to the target file to permanent storage
ignore_attribute_errors = 1u << 5u, // Ignore errors of copying file attributes

// copy options:
recursive = 1u << 8, // Recurse into sub-directories
copy_symlinks = 1u << 9, // Copy symlinks as symlinks instead of copying the referenced file
skip_symlinks = 1u << 10, // Don't copy symlinks
directories_only = 1u << 11, // Only copy directory structure, do not copy non-directory files
create_symlinks = 1u << 12, // Create symlinks instead of copying files
create_hard_links = 1u << 13, // Create hard links instead of copying files
_detail_recursing = 1u << 14 // Internal use only, do not use
recursive = 1u << 8u, // Recurse into sub-directories
copy_symlinks = 1u << 9u, // Copy symlinks as symlinks instead of copying the referenced file
skip_symlinks = 1u << 10u, // Don't copy symlinks
directories_only = 1u << 11u, // Only copy directory structure, do not copy non-directory files
create_symlinks = 1u << 12u, // Create symlinks instead of copying files
create_hard_links = 1u << 13u, // Create hard links instead of copying files
_detail_recursing = 1u << 14u // Internal use only, do not use
}
BOOST_SCOPED_ENUM_DECLARE_END(copy_options)

Expand Down
9 changes: 6 additions & 3 deletions src/operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3061,7 +3061,7 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod
goto fail;
}

mode_t to_mode = from_mode;
mode_t to_mode = from_mode & fs::perms_mask;
#if !defined(BOOST_FILESYSTEM_USE_WASI)
// 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.
Expand Down Expand Up @@ -3184,10 +3184,13 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod
#if !defined(BOOST_FILESYSTEM_USE_WASI)
// 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_mode != from_mode)
if ((to_mode & fs::perms_mask) != (from_mode & fs::perms_mask))
{
if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0))
if (BOOST_UNLIKELY(::fchmod(outfile.fd, (from_mode & fs::perms_mask)) != 0 &&
(options & static_cast< unsigned int >(copy_options::ignore_attribute_errors)) == 0u))
{
goto fail_errno;
}
}
#endif

Expand Down

0 comments on commit fc24312

Please sign in to comment.