@@ -98,7 +98,7 @@ fn uu_tail(settings: &Settings) -> UResult<()> {
9898 the input file is not a FIFO, pipe, or regular file, it is unspecified whether or
9999 not the -f option shall be ignored.
100100 */
101- if !settings. has_only_stdin ( ) || settings. pid != 0 {
101+ if !settings. has_only_stdin ( ) || settings. pid != 0 || observer . stdin_is_tailable ( ) {
102102 follow:: follow ( observer, settings) ?;
103103 }
104104 }
@@ -267,50 +267,85 @@ fn tail_stdin(
267267 }
268268 }
269269
270- match input. resolve ( ) {
271- // fifo
272- Some ( path) => {
273- let mut stdin_offset = 0 ;
274- if cfg ! ( unix ) {
275- // Save the current seek position/offset of a stdin redirected file.
276- // This is needed to pass "gnu/tests/tail-2/start-middle.sh"
277- if let Ok ( mut stdin_handle ) = Handle :: stdin ( ) {
278- if let Ok ( offset ) = stdin_handle . as_file_mut ( ) . stream_position ( ) {
279- stdin_offset = offset ;
280- }
281- }
270+ let resolved_stdin = input. resolve ( ) . or_else ( resolve_stdin_path ) ;
271+
272+ if let Some ( ref path) = resolved_stdin {
273+ let mut stdin_is_seekable_file = false ;
274+ let mut stdin_offset = 0 ;
275+
276+ if let Ok ( mut stdin_handle ) = Handle :: stdin ( ) {
277+ if let Ok ( offset ) = stdin_handle . as_file_mut ( ) . stream_position ( ) {
278+ stdin_offset = offset ;
279+ }
280+ if let Ok ( meta ) = stdin_handle . as_file_mut ( ) . metadata ( ) {
281+ stdin_is_seekable_file = meta . is_file ( ) ;
282282 }
283+ }
284+
285+ if !stdin_is_seekable_file {
286+ stdin_is_seekable_file = path. metadata ( ) . map ( |meta| meta. is_file ( ) ) . unwrap_or ( false ) ;
287+ }
288+
289+ if stdin_is_seekable_file {
283290 tail_file (
284291 settings,
285292 header_printer,
286293 input,
287- & path,
294+ path,
288295 observer,
289296 stdin_offset,
290297 ) ?;
298+
299+ observer. set_stdin_is_tailable ( true ) ;
300+ observer. set_stdin_key ( path. clone ( ) ) ;
301+ if settings. follow . is_some ( ) {
302+ observer. add_path ( path, input. display_name . as_str ( ) , None , true ) ?;
303+ }
304+ return Ok ( ( ) ) ;
291305 }
292- // pipe
293- None => {
306+
307+ if path . metadata ( ) . map ( |meta| meta . is_dir ( ) ) . unwrap_or ( false ) {
294308 header_printer. print_input ( input) ;
295- if paths:: stdin_is_bad_fd ( ) {
296- set_exit_code ( 1 ) ;
297- show_error ! (
298- "{}" ,
299- translate!( "tail-error-cannot-fstat" , "file" => translate!( "tail-stdin-header" ) , "error" => translate!( "tail-bad-fd" ) )
300- ) ;
301- if settings. follow . is_some ( ) {
302- show_error ! (
303- "{}" ,
304- translate!( "tail-error-reading-file" , "file" => translate!( "tail-stdin-header" ) , "error" => translate!( "tail-bad-fd" ) )
305- ) ;
306- }
307- } else {
308- let mut reader = BufReader :: new ( stdin ( ) ) ;
309- unbounded_tail ( & mut reader, settings) ?;
310- }
309+ set_exit_code ( 1 ) ;
310+ show_error ! (
311+ "{}" ,
312+ translate!(
313+ "tail-error-reading-file" ,
314+ "file" => input. display_name. clone( ) ,
315+ "error" => translate!( "tail-is-a-directory" )
316+ )
317+ ) ;
318+ return Ok ( ( ) ) ;
311319 }
312320 }
313321
322+ header_printer. print_input ( input) ;
323+ if paths:: stdin_is_bad_fd ( ) {
324+ set_exit_code ( 1 ) ;
325+ show_error ! (
326+ "{}" ,
327+ translate!(
328+ "tail-error-cannot-fstat" ,
329+ "file" => translate!( "tail-stdin-header" ) ,
330+ "error" => translate!( "tail-bad-fd" )
331+ )
332+ ) ;
333+ if settings. follow . is_some ( ) {
334+ show_error ! (
335+ "{}" ,
336+ translate!(
337+ "tail-error-reading-file" ,
338+ "file" => translate!( "tail-stdin-header" ) ,
339+ "error" => translate!( "tail-bad-fd" )
340+ )
341+ ) ;
342+ }
343+ } else {
344+ let mut reader = BufReader :: new ( stdin ( ) ) ;
345+ unbounded_tail ( & mut reader, settings) ?;
346+ observer. add_stdin ( input. display_name . as_str ( ) , Some ( Box :: new ( reader) ) , true ) ?;
347+ }
348+
314349 Ok ( ( ) )
315350}
316351
@@ -568,6 +603,39 @@ where
568603 }
569604}
570605
606+ #[ cfg( windows) ]
607+ fn resolve_stdin_path ( ) -> Option < PathBuf > {
608+ use std:: os:: windows:: io:: AsRawHandle ;
609+ use windows_sys:: Win32 :: Foundation :: MAX_PATH ;
610+ use windows_sys:: Win32 :: Storage :: FileSystem :: { FILE_NAME_OPENED , GetFinalPathNameByHandleW } ;
611+
612+ let handle = std:: io:: stdin ( ) . lock ( ) . as_raw_handle ( ) ;
613+ if handle. is_null ( ) {
614+ return None ;
615+ }
616+
617+ let mut buffer = [ 0u16 ; MAX_PATH as usize ] ;
618+ let len = unsafe {
619+ GetFinalPathNameByHandleW (
620+ handle,
621+ buffer. as_mut_ptr ( ) ,
622+ buffer. len ( ) as u32 ,
623+ FILE_NAME_OPENED ,
624+ )
625+ } as usize ;
626+
627+ if len == 0 || len >= buffer. len ( ) {
628+ return None ;
629+ }
630+
631+ String :: from_utf16 ( & buffer[ ..len] ) . ok ( ) . map ( PathBuf :: from)
632+ }
633+
634+ #[ cfg( not( windows) ) ]
635+ fn resolve_stdin_path ( ) -> Option < PathBuf > {
636+ None
637+ }
638+
571639#[ cfg( test) ]
572640mod tests {
573641
0 commit comments