Skip to content

Commit 200e4b1

Browse files
install: implement copying from streams
1 parent edf8be5 commit 200e4b1

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

src/uu/install/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ file_diff = { workspace = true }
2323
libc = { workspace = true }
2424
uucore = { workspace = true, features = [
2525
"backup-control",
26+
"buf-copy",
2627
"fs",
2728
"mode",
2829
"perms",

src/uu/install/src/install.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ use file_diff::diff;
1212
use filetime::{set_file_times, FileTime};
1313
use std::error::Error;
1414
use std::fmt::{Debug, Display};
15-
use std::fs;
1615
use std::fs::File;
17-
use std::os::unix::fs::MetadataExt;
18-
#[cfg(unix)]
19-
use std::os::unix::prelude::OsStrExt;
16+
use std::fs::{self, metadata};
2017
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
2118
use std::process;
2219
use uucore::backup_control::{self, BackupMode};
20+
use uucore::buf_copy::copy_stream;
2321
use uucore::display::Quotable;
2422
use uucore::entries::{grp2gid, usr2uid};
2523
use uucore::error::{FromIo, UError, UIoError, UResult, UUsageError};
@@ -29,6 +27,11 @@ use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
2927
use uucore::process::{getegid, geteuid};
3028
use uucore::{format_usage, help_about, help_usage, show, show_error, show_if_err, uio_error};
3129

30+
#[cfg(unix)]
31+
use std::os::unix::fs::{FileTypeExt, MetadataExt};
32+
#[cfg(unix)]
33+
use std::os::unix::prelude::OsStrExt;
34+
3235
const DEFAULT_MODE: u32 = 0o755;
3336
const DEFAULT_STRIP_PROGRAM: &str = "strip";
3437

@@ -736,7 +739,24 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
736739
}
737740
}
738741

739-
/// Copy a file from one path to another.
742+
/// Copy a non-special file using std::fs::copy.
743+
///
744+
/// # Parameters
745+
/// * `from` - The source file path.
746+
/// * `to` - The destination file path.
747+
///
748+
/// # Returns
749+
///
750+
/// Returns an empty Result or an error in case of failure.
751+
fn copy_normal_file(from: &Path, to: &Path) -> UResult<()> {
752+
if let Err(err) = fs::copy(from, to) {
753+
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
754+
}
755+
Ok(())
756+
}
757+
758+
/// Copy a file from one path to another. Handles the certain cases of special
759+
/// files (e.g character specials).
740760
///
741761
/// # Parameters
742762
///
@@ -760,18 +780,26 @@ fn copy_file(from: &Path, to: &Path) -> UResult<()> {
760780
}
761781
}
762782

763-
if from.as_os_str() == "/dev/null" {
764-
/* workaround a limitation of fs::copy
765-
* https://github.com/rust-lang/rust/issues/79390
766-
*/
767-
if let Err(err) = File::create(to) {
783+
let ft = match metadata(from) {
784+
Ok(ft) => ft.file_type(),
785+
Err(err) => {
768786
return Err(
769787
InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
770788
);
771789
}
772-
} else if let Err(err) = fs::copy(from, to) {
773-
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
790+
};
791+
792+
// Stream-based copying to get around the limitations of std::fs::copy
793+
#[cfg(unix)]
794+
if ft.is_char_device() || ft.is_block_device() || ft.is_fifo() {
795+
let mut handle = File::open(from)?;
796+
let mut dest = File::create(to)?;
797+
copy_stream(&mut handle, &mut dest)?;
798+
return Ok(());
774799
}
800+
801+
copy_normal_file(from, to)?;
802+
775803
Ok(())
776804
}
777805

0 commit comments

Comments
 (0)