|
1683 | 1683 | <span id="1683">1683</span>
|
1684 | 1684 | <span id="1684">1684</span>
|
1685 | 1685 | <span id="1685">1685</span>
|
| 1686 | +<span id="1686">1686</span> |
| 1687 | +<span id="1687">1687</span> |
| 1688 | +<span id="1688">1688</span> |
| 1689 | +<span id="1689">1689</span> |
| 1690 | +<span id="1690">1690</span> |
1686 | 1691 | </pre><pre class="rust"><code><span class="attribute">#![allow(clippy::missing_safety_doc)]
|
1687 | 1692 | #![allow(clippy::extra_unused_lifetimes)]
|
1688 | 1693 |
|
|
2576 | 2581 | <span class="prelude-val">Ok</span>((paths, target))
|
2577 | 2582 | }
|
2578 | 2583 |
|
2579 |
| -<span class="kw">fn </span>preserve_hardlinks( |
| 2584 | +<span class="doccomment">/// Get the inode information for a file. |
| 2585 | +</span><span class="kw">fn </span>get_inode(file_info: <span class="kw-2">&</span>FileInformation) -> u64 { |
| 2586 | + <span class="attribute">#[cfg(unix)] |
| 2587 | + </span><span class="kw">let </span>result = file_info.inode(); |
| 2588 | + <span class="attribute">#[cfg(windows)] |
| 2589 | + </span><span class="kw">let </span>result = file_info.file_index(); |
| 2590 | + result |
| 2591 | +} |
| 2592 | + |
| 2593 | +<span class="attribute">#[cfg(target_os = <span class="string">"redox"</span>)] |
| 2594 | +</span><span class="kw">fn </span>preserve_hardlinks( |
2580 | 2595 | hard_links: <span class="kw-2">&mut </span>Vec<(String, u64)>,
|
2581 | 2596 | source: <span class="kw-2">&</span>std::path::Path,
|
2582 | 2597 | dest: <span class="kw-2">&</span>std::path::Path,
|
2583 | 2598 | found_hard_link: <span class="kw-2">&mut </span>bool,
|
2584 | 2599 | ) -> CopyResult<()> {
|
2585 | 2600 | <span class="comment">// Redox does not currently support hard links
|
2586 |
| - </span><span class="attribute">#[cfg(not(target_os = <span class="string">"redox"</span>))] |
2587 |
| - </span>{ |
2588 |
| - <span class="kw">if </span>!source.is_dir() { |
2589 |
| - <span class="kw">let </span>info = <span class="kw">match </span>FileInformation::from_path(source, <span class="bool-val">false</span>) { |
2590 |
| - <span class="prelude-val">Ok</span>(info) => info, |
2591 |
| - <span class="prelude-val">Err</span>(e) => { |
2592 |
| - <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">format!</span>(<span class="string">"cannot stat {}: {}"</span>, source.quote(), e,).into()); |
2593 |
| - } |
2594 |
| - }; |
2595 |
| - |
2596 |
| - <span class="attribute">#[cfg(unix)] |
2597 |
| - </span><span class="kw">let </span>inode = info.inode(); |
2598 |
| - |
2599 |
| - <span class="attribute">#[cfg(windows)] |
2600 |
| - </span><span class="kw">let </span>inode = info.file_index(); |
2601 |
| - |
2602 |
| - <span class="kw">let </span>nlinks = info.number_of_links(); |
2603 |
| - |
2604 |
| - <span class="kw">for </span>hard_link <span class="kw">in </span>hard_links.iter() { |
2605 |
| - <span class="kw">if </span>hard_link.<span class="number">1 </span>== inode { |
2606 |
| - <span class="comment">// Consider the following files: |
2607 |
| - // |
2608 |
| - // * `src/f` - a regular file |
2609 |
| - // * `src/link` - a hard link to `src/f` |
2610 |
| - // * `dest/src/f` - a different regular file |
2611 |
| - // |
2612 |
| - // In this scenario, if we do `cp -a src/ dest/`, it is |
2613 |
| - // possible that the order of traversal causes `src/link` |
2614 |
| - // to get copied first (to `dest/src/link`). In that case, |
2615 |
| - // in order to make sure `dest/src/link` is a hard link to |
2616 |
| - // `dest/src/f` and `dest/src/f` has the contents of |
2617 |
| - // `src/f`, we delete the existing file to allow the hard |
2618 |
| - // linking. |
2619 |
| - </span><span class="kw">if </span>file_or_link_exists(dest) && file_or_link_exists(Path::new(<span class="kw-2">&</span>hard_link.<span class="number">0</span>)) { |
2620 |
| - std::fs::remove_file(dest)<span class="question-mark">?</span>; |
2621 |
| - } |
| 2601 | + </span><span class="prelude-val">Ok</span>(()) |
| 2602 | +} |
2622 | 2603 |
|
2623 |
| - std::fs::hard_link(hard_link.<span class="number">0</span>.clone(), dest).unwrap(); |
2624 |
| - <span class="kw-2">*</span>found_hard_link = <span class="bool-val">true</span>; |
2625 |
| - } |
2626 |
| - } |
2627 |
| - <span class="kw">if </span>!(<span class="kw-2">*</span>found_hard_link) && nlinks > <span class="number">1 </span>{ |
2628 |
| - hard_links.push((dest.to_str().unwrap().to_string(), inode)); |
| 2604 | +<span class="doccomment">/// Hard link a pair of files if needed _and_ record if this pair is a new hard link. |
| 2605 | +</span><span class="attribute">#[cfg(not(target_os = <span class="string">"redox"</span>))] |
| 2606 | +</span><span class="kw">fn </span>preserve_hardlinks( |
| 2607 | + hard_links: <span class="kw-2">&mut </span>Vec<(String, u64)>, |
| 2608 | + source: <span class="kw-2">&</span>std::path::Path, |
| 2609 | + dest: <span class="kw-2">&</span>std::path::Path, |
| 2610 | +) -> CopyResult<bool> { |
| 2611 | + <span class="kw">let </span>info = FileInformation::from_path(source, <span class="bool-val">false</span>) |
| 2612 | + .context(<span class="macro">format!</span>(<span class="string">"cannot stat {}"</span>, source.quote()))<span class="question-mark">?</span>; |
| 2613 | + <span class="kw">let </span>inode = get_inode(<span class="kw-2">&</span>info); |
| 2614 | + <span class="kw">let </span>nlinks = info.number_of_links(); |
| 2615 | + <span class="kw">let </span><span class="kw-2">mut </span>found_hard_link = <span class="bool-val">false</span>; |
| 2616 | + <span class="kw">for </span>(link, link_inode) <span class="kw">in </span>hard_links.iter() { |
| 2617 | + <span class="kw">if </span><span class="kw-2">*</span>link_inode == inode { |
| 2618 | + <span class="comment">// Consider the following files: |
| 2619 | + // |
| 2620 | + // * `src/f` - a regular file |
| 2621 | + // * `src/link` - a hard link to `src/f` |
| 2622 | + // * `dest/src/f` - a different regular file |
| 2623 | + // |
| 2624 | + // In this scenario, if we do `cp -a src/ dest/`, it is |
| 2625 | + // possible that the order of traversal causes `src/link` |
| 2626 | + // to get copied first (to `dest/src/link`). In that case, |
| 2627 | + // in order to make sure `dest/src/link` is a hard link to |
| 2628 | + // `dest/src/f` and `dest/src/f` has the contents of |
| 2629 | + // `src/f`, we delete the existing file to allow the hard |
| 2630 | + // linking. |
| 2631 | + </span><span class="kw">if </span>file_or_link_exists(dest) && file_or_link_exists(Path::new(link)) { |
| 2632 | + std::fs::remove_file(dest)<span class="question-mark">?</span>; |
2629 | 2633 | }
|
| 2634 | + std::fs::hard_link(link, dest).unwrap(); |
| 2635 | + found_hard_link = <span class="bool-val">true</span>; |
2630 | 2636 | }
|
2631 | 2637 | }
|
2632 |
| - <span class="prelude-val">Ok</span>(()) |
| 2638 | + <span class="kw">if </span>!found_hard_link && nlinks > <span class="number">1 </span>{ |
| 2639 | + hard_links.push((dest.to_str().unwrap().to_string(), inode)); |
| 2640 | + } |
| 2641 | + <span class="prelude-val">Ok</span>(found_hard_link) |
2633 | 2642 | }
|
2634 | 2643 |
|
2635 | 2644 | <span class="doccomment">/// Copy all `sources` to `target`. Returns an
|
|
2671 | 2680 | <span class="comment">// FIXME: compare sources by the actual file they point to, not their path. (e.g. dir/file == dir/../dir/file in most cases)
|
2672 | 2681 | </span><span class="macro">show_warning!</span>(<span class="string">"source {} specified more than once"</span>, source.quote());
|
2673 | 2682 | } <span class="kw">else </span>{
|
2674 |
| - <span class="kw">let </span><span class="kw-2">mut </span>found_hard_link = <span class="bool-val">false</span>; |
2675 |
| - <span class="kw">if </span>preserve_hard_links { |
| 2683 | + <span class="kw">let </span>found_hard_link = <span class="kw">if </span>preserve_hard_links && !source.is_dir() { |
2676 | 2684 | <span class="kw">let </span>dest = construct_dest_path(source, target, <span class="kw-2">&</span>target_type, options)<span class="question-mark">?</span>;
|
2677 |
| - preserve_hardlinks(<span class="kw-2">&mut </span>hard_links, source, <span class="kw-2">&</span>dest, <span class="kw-2">&mut </span>found_hard_link)<span class="question-mark">?</span>; |
2678 |
| - } |
| 2685 | + preserve_hardlinks(<span class="kw-2">&mut </span>hard_links, source, <span class="kw-2">&</span>dest)<span class="question-mark">? |
| 2686 | + </span>} <span class="kw">else </span>{ |
| 2687 | + <span class="bool-val">false |
| 2688 | + </span>}; |
2679 | 2689 | <span class="kw">if </span>!found_hard_link {
|
2680 | 2690 | <span class="kw">if let </span><span class="prelude-val">Err</span>(error) = copy_source(
|
2681 | 2691 | <span class="kw-2">&</span>progress_bar,
|
|
0 commit comments