@@ -10,7 +10,7 @@ use std::ffi::OsString;
10
10
use std:: fmt:: Display ;
11
11
use std:: fs:: { self , Metadata , OpenOptions , Permissions } ;
12
12
#[ cfg( unix) ]
13
- use std:: os:: unix:: fs:: { FileTypeExt , PermissionsExt } ;
13
+ use std:: os:: unix:: fs:: { FileTypeExt , MetadataExt , PermissionsExt } ;
14
14
#[ cfg( unix) ]
15
15
use std:: os:: unix:: net:: UnixListener ;
16
16
use std:: path:: { Path , PathBuf , StripPrefixError } ;
@@ -27,13 +27,13 @@ use thiserror::Error;
27
27
use platform:: copy_on_write;
28
28
use uucore:: display:: Quotable ;
29
29
use uucore:: error:: { UError , UResult , UUsageError , set_exit_code} ;
30
- #[ cfg( unix) ]
31
- use uucore:: fs:: make_fifo;
32
30
use uucore:: fs:: {
33
31
FileInformation , MissingHandling , ResolveMode , are_hardlinks_to_same_file, canonicalize,
34
32
get_filename, is_symlink_loop, normalize_path, path_ends_with_terminator,
35
33
paths_refer_to_same_file,
36
34
} ;
35
+ #[ cfg( unix) ]
36
+ use uucore:: fs:: { make_block_device, make_char_device, make_fifo} ;
37
37
use uucore:: { backup_control, update_control} ;
38
38
// These are exposed for projects (e.g. nushell) that want to create an `Options` value, which
39
39
// requires these enum.
@@ -2082,6 +2082,8 @@ fn handle_copy_mode(
2082
2082
source_in_command_line : bool ,
2083
2083
source_is_fifo : bool ,
2084
2084
source_is_socket : bool ,
2085
+ source_is_char_device : bool ,
2086
+ source_is_block_device : bool ,
2085
2087
#[ cfg( unix) ] source_is_stream : bool ,
2086
2088
) -> CopyResult < PerformedAction > {
2087
2089
let source_is_symlink = source_metadata. is_symlink ( ) ;
@@ -2122,6 +2124,8 @@ fn handle_copy_mode(
2122
2124
source_is_symlink,
2123
2125
source_is_fifo,
2124
2126
source_is_socket,
2127
+ source_is_char_device,
2128
+ source_is_block_device,
2125
2129
symlinked_files,
2126
2130
#[ cfg( unix) ]
2127
2131
source_is_stream,
@@ -2145,6 +2149,8 @@ fn handle_copy_mode(
2145
2149
source_is_symlink,
2146
2150
source_is_fifo,
2147
2151
source_is_socket,
2152
+ source_is_char_device,
2153
+ source_is_block_device,
2148
2154
symlinked_files,
2149
2155
#[ cfg( unix) ]
2150
2156
source_is_stream,
@@ -2181,6 +2187,8 @@ fn handle_copy_mode(
2181
2187
source_is_symlink,
2182
2188
source_is_fifo,
2183
2189
source_is_socket,
2190
+ source_is_char_device,
2191
+ source_is_block_device,
2184
2192
symlinked_files,
2185
2193
#[ cfg( unix) ]
2186
2194
source_is_stream,
@@ -2196,6 +2204,8 @@ fn handle_copy_mode(
2196
2204
source_is_symlink,
2197
2205
source_is_fifo,
2198
2206
source_is_socket,
2207
+ source_is_char_device,
2208
+ source_is_block_device,
2199
2209
symlinked_files,
2200
2210
#[ cfg( unix) ]
2201
2211
source_is_stream,
@@ -2424,10 +2434,18 @@ fn copy_file(
2424
2434
let source_is_fifo = source_metadata. file_type ( ) . is_fifo ( ) ;
2425
2435
#[ cfg( unix) ]
2426
2436
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 ( ) ;
2427
2441
#[ cfg( not( unix) ) ]
2428
2442
let source_is_fifo = false ;
2429
2443
#[ cfg( not( unix) ) ]
2430
2444
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 ;
2431
2449
2432
2450
let source_is_stream = is_stream ( & source_metadata) ;
2433
2451
@@ -2441,6 +2459,8 @@ fn copy_file(
2441
2459
source_in_command_line,
2442
2460
source_is_fifo,
2443
2461
source_is_socket,
2462
+ source_is_char_device,
2463
+ source_is_block_device,
2444
2464
#[ cfg( unix) ]
2445
2465
source_is_stream,
2446
2466
) ?;
@@ -2568,6 +2588,8 @@ fn copy_helper(
2568
2588
source_is_symlink : bool ,
2569
2589
source_is_fifo : bool ,
2570
2590
source_is_socket : bool ,
2591
+ source_is_char_device : bool ,
2592
+ source_is_block_device : bool ,
2571
2593
symlinked_files : & mut HashSet < FileInformation > ,
2572
2594
#[ cfg( unix) ] source_is_stream : bool ,
2573
2595
) -> CopyResult < ( ) > {
@@ -2586,6 +2608,12 @@ fn copy_helper(
2586
2608
} else if source_is_fifo && options. recursive && !options. copy_contents {
2587
2609
#[ cfg( unix) ]
2588
2610
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 ) ?;
2589
2617
} else if source_is_symlink {
2590
2618
copy_link ( source, dest, symlinked_files, options) ?;
2591
2619
} else {
@@ -2620,6 +2648,52 @@ fn copy_fifo(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<(
2620
2648
. map_err ( |_| translate ! ( "cp-error-cannot-create-fifo" , "path" => dest. quote( ) ) . into ( ) )
2621
2649
}
2622
2650
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
+
2623
2697
#[ cfg( unix) ]
2624
2698
fn copy_socket ( dest : & Path , overwrite : OverwriteMode , debug : bool ) -> CopyResult < ( ) > {
2625
2699
if dest. exists ( ) {
0 commit comments