@@ -35,7 +35,6 @@ use std::ffi::OsString;
3535use std:: fs:: Metadata ;
3636use std:: fs:: { File , OpenOptions } ;
3737use std:: io:: { self , Read , Seek , SeekFrom , Write } ;
38- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
3938use std:: os:: fd:: AsFd ;
4039#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
4140use std:: os:: unix:: fs:: OpenOptionsExt ;
@@ -183,11 +182,37 @@ impl Num {
183182/// This is more efficient than `io::copy` with `BufReader` because it reads
184183/// directly in `buf_size`-sized chunks, matching GNU dd's behavior.
185184/// Returns the total number of bytes actually read.
186- fn read_and_discard < R : Read > ( reader : & mut R , n : u64 , buf_size : usize ) -> io:: Result < u64 > {
187- // todo: consider splice()ing to /dev/null on Linux
188- let mut buf = Vec :: with_capacity ( buf_size) ;
185+ fn read_and_discard < R : Read + AsFd > ( reader : & mut R , n : u64 , buf_size : usize ) -> io:: Result < u64 > {
189186 let mut total = 0u64 ;
190187 let mut remaining = n;
188+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
189+ {
190+ //fast-path
191+ use std:: sync:: OnceLock ;
192+ use uucore:: pipes:: { MAX_ROOTLESS_PIPE_SIZE , dev_null, splice} ;
193+ static INIT : OnceLock < Option < File > > = OnceLock :: new ( ) ;
194+ let null = INIT . get_or_init ( || {
195+ if let Some ( f) = dev_null ( ) {
196+ let _ = rustix:: pipe:: fcntl_setpipe_size ( & reader, MAX_ROOTLESS_PIPE_SIZE ) ;
197+ Some ( f)
198+ } else {
199+ None
200+ }
201+ } ) ;
202+ if let Some ( null) = null {
203+ while remaining > 0 {
204+ match splice ( & reader, & null, remaining as usize ) {
205+ Ok ( 0 ) => return Ok ( total) , // no need to allocate buf
206+ Ok ( bytes_read) => {
207+ total += bytes_read as u64 ;
208+ remaining -= bytes_read as u64 ;
209+ }
210+ Err ( _) => break ,
211+ }
212+ }
213+ }
214+ }
215+ let mut buf = Vec :: with_capacity ( buf_size) ;
191216 while remaining > 0 {
192217 let to_read = cmp:: min ( remaining, buf_size as u64 ) ;
193218 buf. clear ( ) ;
0 commit comments