@@ -100,7 +100,7 @@ fn uu_tail(settings: &Settings) -> UResult<()> {
100100 the input file is not a FIFO, pipe, or regular file, it is unspecified whether or
101101 not the -f option shall be ignored.
102102 */
103- if !settings. has_only_stdin ( ) || settings. pid != 0 {
103+ if !settings. has_only_stdin ( ) || settings. pid != 0 || observer . stdin_is_tailable ( ) {
104104 follow:: follow ( observer, settings) ?;
105105 }
106106 }
@@ -227,51 +227,85 @@ fn tail_stdin(
227227 }
228228 }
229229
230- match input. resolve ( ) {
231- // fifo
232- Some ( path) => {
233- let mut stdin_offset = 0 ;
234- if cfg ! ( unix ) {
235- // Save the current seek position/offset of a stdin redirected file.
236- // This is needed to pass "gnu/tests/tail-2/start-middle.sh"
237- if let Ok ( mut stdin_handle ) = Handle :: stdin ( ) {
238- if let Ok ( offset ) = stdin_handle . as_file_mut ( ) . stream_position ( ) {
239- stdin_offset = offset ;
240- }
241- }
230+ let resolved_stdin = input. resolve ( ) . or_else ( resolve_stdin_path ) ;
231+
232+ if let Some ( ref path) = resolved_stdin {
233+ let mut stdin_is_seekable_file = false ;
234+ let mut stdin_offset = 0 ;
235+
236+ if let Ok ( mut stdin_handle ) = Handle :: stdin ( ) {
237+ if let Ok ( offset ) = stdin_handle . as_file_mut ( ) . stream_position ( ) {
238+ stdin_offset = offset ;
239+ }
240+ if let Ok ( meta ) = stdin_handle . as_file_mut ( ) . metadata ( ) {
241+ stdin_is_seekable_file = meta . is_file ( ) ;
242242 }
243+ }
244+
245+ if !stdin_is_seekable_file {
246+ stdin_is_seekable_file = path. metadata ( ) . map ( |meta| meta. is_file ( ) ) . unwrap_or ( false ) ;
247+ }
248+
249+ if stdin_is_seekable_file {
243250 tail_file (
244251 settings,
245252 header_printer,
246253 input,
247- & path,
254+ path,
248255 observer,
249256 stdin_offset,
250257 ) ?;
258+
259+ observer. set_stdin_is_tailable ( true ) ;
260+ observer. set_stdin_key ( path. clone ( ) ) ;
261+ if settings. follow . is_some ( ) {
262+ observer. add_path ( path, input. display_name . as_str ( ) , None , true ) ?;
263+ }
264+ return Ok ( ( ) ) ;
251265 }
252- // pipe
253- None => {
266+
267+ if path . metadata ( ) . map ( |meta| meta . is_dir ( ) ) . unwrap_or ( false ) {
254268 header_printer. print_input ( input) ;
255- if paths:: stdin_is_bad_fd ( ) {
256- set_exit_code ( 1 ) ;
257- show_error ! (
258- "{}" ,
259- translate!( "tail-error-cannot-fstat" , "file" => translate!( "tail-stdin-header" ) , "error" => translate!( "tail-bad-fd" ) )
260- ) ;
261- if settings. follow . is_some ( ) {
262- show_error ! (
263- "{}" ,
264- translate!( "tail-error-reading-file" , "file" => translate!( "tail-stdin-header" ) , "error" => translate!( "tail-bad-fd" ) )
265- ) ;
266- }
267- } else {
268- let mut reader = BufReader :: new ( stdin ( ) ) ;
269- unbounded_tail ( & mut reader, settings) ?;
270- observer. add_stdin ( input. display_name . as_str ( ) , Some ( Box :: new ( reader) ) , true ) ?;
271- }
269+ set_exit_code ( 1 ) ;
270+ show_error ! (
271+ "{}" ,
272+ translate!(
273+ "tail-error-reading-file" ,
274+ "file" => input. display_name. clone( ) ,
275+ "error" => translate!( "tail-is-a-directory" )
276+ )
277+ ) ;
278+ return Ok ( ( ) ) ;
272279 }
273280 }
274281
282+ header_printer. print_input ( input) ;
283+ if paths:: stdin_is_bad_fd ( ) {
284+ set_exit_code ( 1 ) ;
285+ show_error ! (
286+ "{}" ,
287+ translate!(
288+ "tail-error-cannot-fstat" ,
289+ "file" => translate!( "tail-stdin-header" ) ,
290+ "error" => translate!( "tail-bad-fd" )
291+ )
292+ ) ;
293+ if settings. follow . is_some ( ) {
294+ show_error ! (
295+ "{}" ,
296+ translate!(
297+ "tail-error-reading-file" ,
298+ "file" => translate!( "tail-stdin-header" ) ,
299+ "error" => translate!( "tail-bad-fd" )
300+ )
301+ ) ;
302+ }
303+ } else {
304+ let mut reader = BufReader :: new ( stdin ( ) ) ;
305+ unbounded_tail ( & mut reader, settings) ?;
306+ observer. add_stdin ( input. display_name . as_str ( ) , Some ( Box :: new ( reader) ) , true ) ?;
307+ }
308+
275309 Ok ( ( ) )
276310}
277311
@@ -529,6 +563,39 @@ where
529563 }
530564}
531565
566+ #[ cfg( windows) ]
567+ fn resolve_stdin_path ( ) -> Option < PathBuf > {
568+ use std:: os:: windows:: io:: AsRawHandle ;
569+ use windows_sys:: Win32 :: Foundation :: MAX_PATH ;
570+ use windows_sys:: Win32 :: Storage :: FileSystem :: { FILE_NAME_OPENED , GetFinalPathNameByHandleW } ;
571+
572+ let handle = std:: io:: stdin ( ) . lock ( ) . as_raw_handle ( ) ;
573+ if handle. is_null ( ) {
574+ return None ;
575+ }
576+
577+ let mut buffer = [ 0u16 ; MAX_PATH as usize ] ;
578+ let len = unsafe {
579+ GetFinalPathNameByHandleW (
580+ handle,
581+ buffer. as_mut_ptr ( ) ,
582+ buffer. len ( ) as u32 ,
583+ FILE_NAME_OPENED ,
584+ )
585+ } as usize ;
586+
587+ if len == 0 || len >= buffer. len ( ) {
588+ return None ;
589+ }
590+
591+ String :: from_utf16 ( & buffer[ ..len] ) . ok ( ) . map ( PathBuf :: from)
592+ }
593+
594+ #[ cfg( not( windows) ) ]
595+ fn resolve_stdin_path ( ) -> Option < PathBuf > {
596+ None
597+ }
598+
532599#[ cfg( test) ]
533600mod tests {
534601
0 commit comments