44// file that was distributed with this source code.
55
66// spell-checker:ignore (ToDO) nonprint nonblank nonprinting ELOOP
7- use clap:: { crate_version, Arg , ArgAction , Command } ;
87use std:: fs:: { metadata, File } ;
98use std:: io:: { self , IsTerminal , Read , Write } ;
10- use thiserror:: Error ;
11- use uucore:: display:: Quotable ;
12- use uucore:: error:: UResult ;
13- use uucore:: fs:: FileInformation ;
14-
15- #[ cfg( unix) ]
16- use std:: os:: fd:: { AsFd , AsRawFd } ;
17-
18- /// Linux splice support
19- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
20- mod splice;
21-
229/// Unix domain socket support
2310#[ cfg( unix) ]
2411use std:: net:: Shutdown ;
2512#[ cfg( unix) ]
13+ use std:: os:: fd:: { AsFd , AsRawFd } ;
14+ #[ cfg( unix) ]
2615use std:: os:: unix:: fs:: FileTypeExt ;
2716#[ cfg( unix) ]
2817use std:: os:: unix:: net:: UnixStream ;
18+
19+ use clap:: { crate_version, Arg , ArgAction , Command } ;
20+ #[ cfg( unix) ]
21+ use nix:: fcntl:: { fcntl, FcntlArg } ;
22+ use thiserror:: Error ;
23+ use uucore:: display:: Quotable ;
24+ use uucore:: error:: UResult ;
25+ use uucore:: fs:: FileInformation ;
2926use uucore:: { format_usage, help_about, help_usage} ;
3027
28+ /// Linux splice support
29+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
30+ mod splice;
31+
3132const USAGE : & str = help_usage ! ( "cat.md" ) ;
3233const ABOUT : & str = help_about ! ( "cat.md" ) ;
3334
@@ -322,6 +323,24 @@ fn cat_handle<R: FdReadable>(
322323 }
323324}
324325
326+ /// Whether this process is appending to stdout.
327+ #[ cfg( unix) ]
328+ fn is_appending ( ) -> bool {
329+ let stdout = std:: io:: stdout ( ) ;
330+ let flags = match fcntl ( stdout. as_raw_fd ( ) , FcntlArg :: F_GETFL ) {
331+ Ok ( flags) => flags,
332+ Err ( _) => return false ,
333+ } ;
334+ // TODO Replace `1 << 10` with `nix::fcntl::Oflag::O_APPEND`.
335+ let o_append = 1 << 10 ;
336+ ( flags & o_append) > 0
337+ }
338+
339+ #[ cfg( not( unix) ) ]
340+ fn is_appending ( ) -> bool {
341+ false
342+ }
343+
325344fn cat_path (
326345 path : & str ,
327346 options : & OutputOptions ,
@@ -331,10 +350,16 @@ fn cat_path(
331350 match get_input_type ( path) ? {
332351 InputType :: StdIn => {
333352 let stdin = io:: stdin ( ) ;
353+ let in_info = FileInformation :: from_file ( & stdin) ?;
334354 let mut handle = InputHandle {
335355 reader : stdin,
336356 is_interactive : std:: io:: stdin ( ) . is_terminal ( ) ,
337357 } ;
358+ if let Some ( out_info) = out_info {
359+ if in_info == * out_info && is_appending ( ) {
360+ return Err ( CatError :: OutputIsInput ) ;
361+ }
362+ }
338363 cat_handle ( & mut handle, options, state)
339364 }
340365 InputType :: Directory => Err ( CatError :: IsDirectory ) ,
0 commit comments