1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

Merge pull request #4216 from jfinkels/cp-preserve-hardlinks-readability

cp: improve readability of preserve_hardlinks()
This commit is contained in:
Sylvestre Ledru 2022-12-06 08:44:44 +01:00 committed by GitHub
commit 24340665ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 49 deletions

View file

@ -213,9 +213,8 @@ fn copy_direntry(
// If the source is not a directory, then we need to copy the file.
if !source_absolute.is_dir() {
if preserve_hard_links {
let mut found_hard_link = false;
let dest = local_to_target.as_path().to_path_buf();
preserve_hardlinks(hard_links, &source_absolute, &dest, &mut found_hard_link)?;
let found_hard_link = preserve_hardlinks(hard_links, &source_absolute, &dest)?;
if !found_hard_link {
match copy_file(
progress_bar,

View file

@ -891,6 +891,16 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
Ok((paths, target))
}
/// Get the inode information for a file.
fn get_inode(file_info: &FileInformation) -> u64 {
#[cfg(unix)]
let result = file_info.inode();
#[cfg(windows)]
let result = file_info.file_index();
result
}
#[cfg(target_os = "redox")]
fn preserve_hardlinks(
hard_links: &mut Vec<(String, u64)>,
source: &std::path::Path,
@ -898,26 +908,23 @@ fn preserve_hardlinks(
found_hard_link: &mut bool,
) -> CopyResult<()> {
// Redox does not currently support hard links
#[cfg(not(target_os = "redox"))]
{
if !source.is_dir() {
let info = match FileInformation::from_path(source, false) {
Ok(info) => info,
Err(e) => {
return Err(format!("cannot stat {}: {}", source.quote(), e,).into());
Ok(())
}
};
#[cfg(unix)]
let inode = info.inode();
#[cfg(windows)]
let inode = info.file_index();
/// Hard link a pair of files if needed _and_ record if this pair is a new hard link.
#[cfg(not(target_os = "redox"))]
fn preserve_hardlinks(
hard_links: &mut Vec<(String, u64)>,
source: &std::path::Path,
dest: &std::path::Path,
) -> CopyResult<bool> {
let info = FileInformation::from_path(source, false)
.context(format!("cannot stat {}", source.quote()))?;
let inode = get_inode(&info);
let nlinks = info.number_of_links();
for hard_link in hard_links.iter() {
if hard_link.1 == inode {
let mut found_hard_link = false;
for (link, link_inode) in hard_links.iter() {
if *link_inode == inode {
// Consider the following files:
//
// * `src/f` - a regular file
@ -931,20 +938,17 @@ fn preserve_hardlinks(
// `dest/src/f` and `dest/src/f` has the contents of
// `src/f`, we delete the existing file to allow the hard
// linking.
if file_or_link_exists(dest) && file_or_link_exists(Path::new(&hard_link.0)) {
if file_or_link_exists(dest) && file_or_link_exists(Path::new(link)) {
std::fs::remove_file(dest)?;
}
std::fs::hard_link(hard_link.0.clone(), dest).unwrap();
*found_hard_link = true;
std::fs::hard_link(link, dest).unwrap();
found_hard_link = true;
}
}
if !(*found_hard_link) && nlinks > 1 {
if !found_hard_link && nlinks > 1 {
hard_links.push((dest.to_str().unwrap().to_string(), inode));
}
}
}
Ok(())
Ok(found_hard_link)
}
/// Copy all `sources` to `target`. Returns an
@ -986,11 +990,12 @@ fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResu
// FIXME: compare sources by the actual file they point to, not their path. (e.g. dir/file == dir/../dir/file in most cases)
show_warning!("source {} specified more than once", source.quote());
} else {
let mut found_hard_link = false;
if preserve_hard_links {
let found_hard_link = if preserve_hard_links && !source.is_dir() {
let dest = construct_dest_path(source, target, &target_type, options)?;
preserve_hardlinks(&mut hard_links, source, &dest, &mut found_hard_link)?;
}
preserve_hardlinks(&mut hard_links, source, &dest)?
} else {
false
};
if !found_hard_link {
if let Err(error) = copy_source(
&progress_bar,