@@ -10,7 +10,7 @@ use std::ffi::OsString;
1010use std:: fmt:: Display ;
1111use std:: fs:: { self , Metadata , OpenOptions , Permissions } ;
1212#[ cfg( unix) ]
13- use std:: os:: unix:: fs:: { FileTypeExt , PermissionsExt } ;
13+ use std:: os:: unix:: fs:: { FileTypeExt , MetadataExt , PermissionsExt } ;
1414#[ cfg( unix) ]
1515use std:: os:: unix:: net:: UnixListener ;
1616use std:: path:: { Path , PathBuf , StripPrefixError } ;
@@ -27,13 +27,13 @@ use thiserror::Error;
2727use platform:: copy_on_write;
2828use uucore:: display:: Quotable ;
2929use uucore:: error:: { UError , UResult , UUsageError , set_exit_code} ;
30- #[ cfg( unix) ]
31- use uucore:: fs:: make_fifo;
3230use uucore:: fs:: {
3331 FileInformation , MissingHandling , ResolveMode , are_hardlinks_to_same_file, canonicalize,
3432 get_filename, is_symlink_loop, normalize_path, path_ends_with_terminator,
3533 paths_refer_to_same_file,
3634} ;
35+ #[ cfg( unix) ]
36+ use uucore:: fs:: { make_block_device, make_char_device, make_fifo} ;
3737use uucore:: { backup_control, update_control} ;
3838// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
3939// requires these enum.
@@ -2082,6 +2082,8 @@ fn handle_copy_mode(
20822082 source_in_command_line : bool ,
20832083 source_is_fifo : bool ,
20842084 source_is_socket : bool ,
2085+ source_is_char_device : bool ,
2086+ source_is_block_device : bool ,
20852087 #[ cfg( unix) ] source_is_stream : bool ,
20862088) -> CopyResult < PerformedAction > {
20872089 let source_is_symlink = source_metadata. is_symlink ( ) ;
@@ -2122,6 +2124,8 @@ fn handle_copy_mode(
21222124 source_is_symlink,
21232125 source_is_fifo,
21242126 source_is_socket,
2127+ source_is_char_device,
2128+ source_is_block_device,
21252129 symlinked_files,
21262130 #[ cfg( unix) ]
21272131 source_is_stream,
@@ -2145,6 +2149,8 @@ fn handle_copy_mode(
21452149 source_is_symlink,
21462150 source_is_fifo,
21472151 source_is_socket,
2152+ source_is_char_device,
2153+ source_is_block_device,
21482154 symlinked_files,
21492155 #[ cfg( unix) ]
21502156 source_is_stream,
@@ -2181,6 +2187,8 @@ fn handle_copy_mode(
21812187 source_is_symlink,
21822188 source_is_fifo,
21832189 source_is_socket,
2190+ source_is_char_device,
2191+ source_is_block_device,
21842192 symlinked_files,
21852193 #[ cfg( unix) ]
21862194 source_is_stream,
@@ -2196,6 +2204,8 @@ fn handle_copy_mode(
21962204 source_is_symlink,
21972205 source_is_fifo,
21982206 source_is_socket,
2207+ source_is_char_device,
2208+ source_is_block_device,
21992209 symlinked_files,
22002210 #[ cfg( unix) ]
22012211 source_is_stream,
@@ -2424,10 +2434,18 @@ fn copy_file(
24242434 let source_is_fifo = source_metadata. file_type ( ) . is_fifo ( ) ;
24252435 #[ cfg( unix) ]
24262436 let source_is_socket = source_metadata. file_type ( ) . is_socket ( ) ;
2437+ #[ cfg( unix) ]
2438+ let source_is_char_device = source_metadata. file_type ( ) . is_char_device ( ) ;
2439+ #[ cfg( unix) ]
2440+ let source_is_block_device = source_metadata. file_type ( ) . is_block_device ( ) ;
24272441 #[ cfg( not( unix) ) ]
24282442 let source_is_fifo = false ;
24292443 #[ cfg( not( unix) ) ]
24302444 let source_is_socket = false ;
2445+ #[ cfg( not( unix) ) ]
2446+ let source_is_char_device = false ;
2447+ #[ cfg( not( unix) ) ]
2448+ let source_is_block_device = false ;
24312449
24322450 let source_is_stream = is_stream ( & source_metadata) ;
24332451
@@ -2441,6 +2459,8 @@ fn copy_file(
24412459 source_in_command_line,
24422460 source_is_fifo,
24432461 source_is_socket,
2462+ source_is_char_device,
2463+ source_is_block_device,
24442464 #[ cfg( unix) ]
24452465 source_is_stream,
24462466 ) ?;
@@ -2568,6 +2588,8 @@ fn copy_helper(
25682588 source_is_symlink : bool ,
25692589 source_is_fifo : bool ,
25702590 source_is_socket : bool ,
2591+ source_is_char_device : bool ,
2592+ source_is_block_device : bool ,
25712593 symlinked_files : & mut HashSet < FileInformation > ,
25722594 #[ cfg( unix) ] source_is_stream : bool ,
25732595) -> CopyResult < ( ) > {
@@ -2586,6 +2608,12 @@ fn copy_helper(
25862608 } else if source_is_fifo && options. recursive && !options. copy_contents {
25872609 #[ cfg( unix) ]
25882610 copy_fifo ( dest, options. overwrite , options. debug ) ?;
2611+ } else if source_is_char_device && options. recursive && !options. copy_contents {
2612+ #[ cfg( unix) ]
2613+ copy_char_device ( source, dest, options. overwrite , options. debug ) ?;
2614+ } else if source_is_block_device && options. recursive && !options. copy_contents {
2615+ #[ cfg( unix) ]
2616+ copy_block_device ( source, dest, options. overwrite , options. debug ) ?;
25892617 } else if source_is_symlink {
25902618 copy_link ( source, dest, symlinked_files, options) ?;
25912619 } else {
@@ -2620,6 +2648,52 @@ fn copy_fifo(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<(
26202648 . map_err ( |_| translate ! ( "cp-error-cannot-create-fifo" , "path" => dest. quote( ) ) . into ( ) )
26212649}
26222650
2651+ // "Copies" a character device by creating a new one with the same major/minor numbers.
2652+ #[ cfg( unix) ]
2653+ fn copy_char_device (
2654+ source : & Path ,
2655+ dest : & Path ,
2656+ overwrite : OverwriteMode ,
2657+ debug : bool ,
2658+ ) -> CopyResult < ( ) > {
2659+ if dest. exists ( ) {
2660+ overwrite. verify ( dest, debug) ?;
2661+ fs:: remove_file ( dest) ?;
2662+ }
2663+
2664+ let source_metadata = fs:: metadata ( source) ?;
2665+ let device_id = source_metadata. rdev ( ) ;
2666+ let major = ( ( device_id >> 8 ) & 0xff ) as u32 ;
2667+ let minor = ( device_id & 0xff ) as u32 ;
2668+
2669+ make_char_device ( dest, major, minor) . map_err ( |_| {
2670+ translate ! ( "cp-error-cannot-create-char-device" , "path" => dest. quote( ) ) . into ( )
2671+ } )
2672+ }
2673+
2674+ // "Copies" a block device by creating a new one with the same major/minor numbers.
2675+ #[ cfg( unix) ]
2676+ fn copy_block_device (
2677+ source : & Path ,
2678+ dest : & Path ,
2679+ overwrite : OverwriteMode ,
2680+ debug : bool ,
2681+ ) -> CopyResult < ( ) > {
2682+ if dest. exists ( ) {
2683+ overwrite. verify ( dest, debug) ?;
2684+ fs:: remove_file ( dest) ?;
2685+ }
2686+
2687+ let source_metadata = fs:: metadata ( source) ?;
2688+ let device_id = source_metadata. rdev ( ) ;
2689+ let major = ( ( device_id >> 8 ) & 0xff ) as u32 ;
2690+ let minor = ( device_id & 0xff ) as u32 ;
2691+
2692+ make_block_device ( dest, major, minor) . map_err ( |_| {
2693+ translate ! ( "cp-error-cannot-create-block-device" , "path" => dest. quote( ) ) . into ( )
2694+ } )
2695+ }
2696+
26232697#[ cfg( unix) ]
26242698fn copy_socket ( dest : & Path , overwrite : OverwriteMode , debug : bool ) -> CopyResult < ( ) > {
26252699 if dest. exists ( ) {
0 commit comments