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

install: implement copying from streams

This commit is contained in:
Daringcuteseal 2024-12-17 20:03:44 +07:00
parent edf8be5e08
commit 200e4b1032
No known key found for this signature in database
GPG key ID: 173F4A541C0E39D7
2 changed files with 41 additions and 12 deletions

View file

@ -23,6 +23,7 @@ file_diff = { workspace = true }
libc = { workspace = true }
uucore = { workspace = true, features = [
"backup-control",
"buf-copy",
"fs",
"mode",
"perms",

View file

@ -12,14 +12,12 @@ use file_diff::diff;
use filetime::{set_file_times, FileTime};
use std::error::Error;
use std::fmt::{Debug, Display};
use std::fs;
use std::fs::File;
use std::os::unix::fs::MetadataExt;
#[cfg(unix)]
use std::os::unix::prelude::OsStrExt;
use std::fs::{self, metadata};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process;
use uucore::backup_control::{self, BackupMode};
use uucore::buf_copy::copy_stream;
use uucore::display::Quotable;
use uucore::entries::{grp2gid, usr2uid};
use uucore::error::{FromIo, UError, UIoError, UResult, UUsageError};
@ -29,6 +27,11 @@ use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
use uucore::process::{getegid, geteuid};
use uucore::{format_usage, help_about, help_usage, show, show_error, show_if_err, uio_error};
#[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, MetadataExt};
#[cfg(unix)]
use std::os::unix::prelude::OsStrExt;
const DEFAULT_MODE: u32 = 0o755;
const DEFAULT_STRIP_PROGRAM: &str = "strip";
@ -736,7 +739,24 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
}
}
/// Copy a file from one path to another.
/// Copy a non-special file using std::fs::copy.
///
/// # Parameters
/// * `from` - The source file path.
/// * `to` - The destination file path.
///
/// # Returns
///
/// Returns an empty Result or an error in case of failure.
fn copy_normal_file(from: &Path, to: &Path) -> UResult<()> {
if let Err(err) = fs::copy(from, to) {
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
}
Ok(())
}
/// Copy a file from one path to another. Handles the certain cases of special
/// files (e.g character specials).
///
/// # Parameters
///
@ -760,18 +780,26 @@ fn copy_file(from: &Path, to: &Path) -> UResult<()> {
}
}
if from.as_os_str() == "/dev/null" {
/* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390
*/
if let Err(err) = File::create(to) {
let ft = match metadata(from) {
Ok(ft) => ft.file_type(),
Err(err) => {
return Err(
InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
);
}
} else if let Err(err) = fs::copy(from, to) {
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
};
// Stream-based copying to get around the limitations of std::fs::copy
#[cfg(unix)]
if ft.is_char_device() || ft.is_block_device() || ft.is_fifo() {
let mut handle = File::open(from)?;
let mut dest = File::create(to)?;
copy_stream(&mut handle, &mut dest)?;
return Ok(());
}
copy_normal_file(from, to)?;
Ok(())
}