@@ -12,14 +12,12 @@ use file_diff::diff;
1212use filetime:: { set_file_times, FileTime } ;
1313use std:: error:: Error ;
1414use std:: fmt:: { Debug , Display } ;
15- use std:: fs;
1615use 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} ;
2017use std:: path:: { Path , PathBuf , MAIN_SEPARATOR } ;
2118use std:: process;
2219use uucore:: backup_control:: { self , BackupMode } ;
20+ use uucore:: buf_copy:: copy_stream;
2321use uucore:: display:: Quotable ;
2422use uucore:: entries:: { grp2gid, usr2uid} ;
2523use uucore:: error:: { FromIo , UError , UIoError , UResult , UUsageError } ;
@@ -29,6 +27,11 @@ use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
2927use uucore:: process:: { getegid, geteuid} ;
3028use 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+
3235const DEFAULT_MODE : u32 = 0o755 ;
3336const 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