3
3
// For the full copyright and license information, please view the LICENSE
4
4
// file that was distributed with this source code.
5
5
6
- // spell-checker:ignore fname, ftype, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, wlen, wstat seekable oconv canonicalized fadvise Fadvise FADV DONTNEED ESPIPE bufferedoutput
6
+ // spell-checker:ignore fname, ftype, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, wlen, wstat seekable oconv canonicalized fadvise Fadvise FADV DONTNEED ESPIPE bufferedoutput, SETFL
7
7
8
8
mod blocks;
9
9
mod bufferedoutput;
@@ -16,6 +16,10 @@ mod progress;
16
16
use crate :: bufferedoutput:: BufferedOutput ;
17
17
use blocks:: conv_block_unblock_helper;
18
18
use datastructures:: * ;
19
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
20
+ use nix:: fcntl:: FcntlArg :: F_SETFL ;
21
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
22
+ use nix:: fcntl:: OFlag ;
19
23
use parseargs:: Parser ;
20
24
use progress:: { gen_prog_updater, ProgUpdate , ReadStat , StatusLevel , WriteStat } ;
21
25
@@ -24,6 +28,8 @@ use std::env;
24
28
use std:: ffi:: OsString ;
25
29
use std:: fs:: { File , OpenOptions } ;
26
30
use std:: io:: { self , Read , Seek , SeekFrom , Stdout , Write } ;
31
+ use std:: os:: fd:: AsFd ;
32
+ use std:: os:: fd:: OwnedFd ;
27
33
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
28
34
use std:: os:: unix:: fs:: OpenOptionsExt ;
29
35
#[ cfg( unix) ]
@@ -557,7 +563,7 @@ impl Dest {
557
563
return Ok ( len) ;
558
564
}
559
565
}
560
- f. seek ( io:: SeekFrom :: Start ( n ) )
566
+ f. seek ( io:: SeekFrom :: Current ( n . try_into ( ) . unwrap ( ) ) )
561
567
}
562
568
#[ cfg( unix) ]
563
569
Self :: Fifo ( f) => {
@@ -699,6 +705,11 @@ impl<'a> Output<'a> {
699
705
if !settings. oconv . notrunc {
700
706
dst. set_len ( settings. seek ) . ok ( ) ;
701
707
}
708
+
709
+ Self :: prepare_file ( dst, settings)
710
+ }
711
+
712
+ fn prepare_file ( dst : File , settings : & ' a Settings ) -> UResult < Self > {
702
713
let density = if settings. oconv . sparse {
703
714
Density :: Sparse
704
715
} else {
@@ -710,6 +721,28 @@ impl<'a> Output<'a> {
710
721
Ok ( Self { dst, settings } )
711
722
}
712
723
724
+ /// Instantiate this struct with file descriptor as a destination.
725
+ ///
726
+ /// This is useful e.g. for the case when the file descriptor was
727
+ /// already opened by the system (stdout) and has a state
728
+ /// (current position) that shall be used.
729
+ fn new_file_from_fd ( fd : OwnedFd , settings : & ' a Settings ) -> UResult < Self > {
730
+ fn open_dst ( fd : OwnedFd , _oflags : & OFlags ) -> Result < File , io:: Error > {
731
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
732
+ if let Some ( libc_flags) = make_linux_oflags ( _oflags) {
733
+ nix:: fcntl:: fcntl ( fd. as_raw_fd ( ) , F_SETFL ( OFlag :: from_bits_retain ( libc_flags) ) ) ?;
734
+ }
735
+
736
+ Ok ( File :: from ( fd) )
737
+ }
738
+
739
+ let raw_fd = fd. as_raw_fd ( ) ;
740
+ let dst = open_dst ( fd, & settings. oflags )
741
+ . map_err_context ( || format ! ( "failed to open fd {}" , raw_fd) ) ?;
742
+
743
+ Self :: prepare_file ( dst, settings)
744
+ }
745
+
713
746
/// Instantiate this struct with the given named pipe as a destination.
714
747
#[ cfg( unix) ]
715
748
fn new_fifo ( filename : & Path , settings : & ' a Settings ) -> UResult < Self > {
@@ -1288,7 +1321,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
1288
1321
Some ( ref outfile) if is_fifo ( outfile) => Output :: new_fifo ( Path :: new ( & outfile) , & settings) ?,
1289
1322
Some ( ref outfile) => Output :: new_file ( Path :: new ( & outfile) , & settings) ?,
1290
1323
None if is_stdout_redirected_to_seekable_file ( ) => {
1291
- Output :: new_file ( Path :: new ( & stdout_canonicalized ( ) ) , & settings) ?
1324
+ let fd = io:: stdout ( ) . as_fd ( ) . try_clone_to_owned ( ) ?;
1325
+ Output :: new_file_from_fd ( fd, & settings) ?
1292
1326
}
1293
1327
None => Output :: new_stdout ( & settings) ?,
1294
1328
} ;
0 commit comments