mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cp: add support for preserving links on windows.
This commit is contained in:
parent
f7072b7dfe
commit
6476f6e616
2 changed files with 74 additions and 1 deletions
|
@ -22,6 +22,10 @@ filetime = "0.1"
|
|||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
ioctl-sys = "0.5.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
kernel32-sys = "*"
|
||||
winapi = "*"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
xattr="0.2.1"
|
||||
|
||||
|
|
71
src/cp/cp.rs
71
src/cp/cp.rs
|
@ -22,6 +22,18 @@ use filetime::FileTime;
|
|||
#[cfg(unix)]
|
||||
extern crate xattr;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
#[cfg(windows)]
|
||||
extern crate kernel32;
|
||||
#[cfg(windows)]
|
||||
use kernel32::GetFileInformationByHandle;
|
||||
#[cfg(windows)]
|
||||
use kernel32::CreateFile2;
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
use std::mem;
|
||||
use std::ffi::CString;
|
||||
use clap::{Arg, App, ArgMatches};
|
||||
|
@ -673,6 +685,9 @@ fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()
|
|||
}
|
||||
#[cfg(unix)]
|
||||
let mut hard_links: Vec<(String, u64)> = vec![];
|
||||
|
||||
#[cfg(windows)]
|
||||
let mut hard_links: Vec<(String, (u32, u32))> = vec![];
|
||||
|
||||
let mut non_fatal_errors = false;
|
||||
let mut seen_sources = HashSet::with_capacity(sources.len());
|
||||
|
@ -706,7 +721,32 @@ fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()
|
|||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
unsafe {
|
||||
if !source.is_dir() {
|
||||
let dest = construct_dest_path(source, target, &target_type, options)?;
|
||||
let handle = CreateFile2(CString::new(Path::new(&source.clone()).as_os_str().to_str().unwrap()).unwrap().as_ptr() as *const u16,
|
||||
winapi::winnt::GENERIC_READ,
|
||||
winapi::winnt::FILE_SHARE_READ,
|
||||
0,
|
||||
std::ptr::null_mut());
|
||||
let file_info = std::mem::uninitialized();
|
||||
if GetFileInformationByHandle(handle, file_info) != 0 {
|
||||
return Err(format!("cannot get file information {:?}: {}", source, std::io::Error::last_os_error()).into());
|
||||
}
|
||||
|
||||
let file_index = ((*file_info).nFileIndexHigh, (*file_info).nFileIndexLow);
|
||||
for hard_link in &hard_links {
|
||||
if (hard_link.1).0 == file_index.0 && (hard_link.1).1 == file_index.1 {
|
||||
std::fs::hard_link(hard_link.0.clone(), dest.clone()).unwrap();
|
||||
found_hard_link = true;
|
||||
}
|
||||
}
|
||||
if (((*file_info).nNumberOfLinks) > 1u32) && !found_hard_link {
|
||||
println!("{}", (*file_info).nNumberOfLinks);
|
||||
hard_links.push((dest.clone().to_str().unwrap().to_string(), file_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found_hard_link {
|
||||
|
@ -786,6 +826,10 @@ fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult
|
|||
preserve_hard_links = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
let mut hard_links: Vec<(String, (u32, u32))> = vec![];
|
||||
|
||||
for path in WalkDir::new(root) {
|
||||
let path = or_continue!(or_continue!(path).path().canonicalize());
|
||||
let local_to_root_parent = match root_parent {
|
||||
|
@ -819,14 +863,39 @@ fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult
|
|||
if stat.st_nlink > 1 && !found_hard_link {
|
||||
hard_links.push((local_to_target.as_path().to_str().unwrap().to_string(), inode));
|
||||
copy_file(path.as_path(), local_to_target.as_path(), options)?;
|
||||
} else {
|
||||
copy_file(path.as_path(), local_to_target.as_path(), options)?;
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
unsafe {
|
||||
let mut found_hard_link = false;
|
||||
let src_path = CString::new(path.as_os_str().to_str().unwrap()).unwrap();
|
||||
let handle = File::open(path.clone()).unwrap().as_raw_handle();
|
||||
let file_info = std::mem::uninitialized();
|
||||
|
||||
let handle = File::open(path.clone()).unwrap().as_raw_handle();
|
||||
if GetFileInformationByHandle(handle, file_info) != 0 {
|
||||
return Err(format!("cannot get file information {:?}: {}", src_path, std::io::Error::last_os_error()).into());
|
||||
}
|
||||
|
||||
let file_index = ((*file_info).nFileIndexHigh, (*file_info).nFileIndexLow);
|
||||
for hard_link in &hard_links {
|
||||
if (hard_link.1).0 == file_index.0 && (hard_link.1).1 == file_index.1 {
|
||||
std::fs::hard_link(hard_link.0.clone(), local_to_target.as_path()).unwrap();
|
||||
found_hard_link = true;
|
||||
}
|
||||
}
|
||||
if (*file_info).nNumberOfLinks > 1u32 && !found_hard_link {
|
||||
hard_links.push((local_to_target.as_path().to_str().unwrap().to_string(), file_index));
|
||||
copy_file(path.as_path(), local_to_target.as_path(), options)?;
|
||||
} else {
|
||||
copy_file(path.as_path(), local_to_target.as_path(), options)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("copy");
|
||||
copy_file(path.as_path(), local_to_target.as_path(), options)?;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue