diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index ad568db7628..5b0c6d75c36 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -117,14 +117,24 @@ fn tail_file( observer: &mut Observer, offset: u64, ) -> UResult<()> { - if !path.exists() { - set_exit_code(1); - show_error!( - "{}", - translate!("tail-error-cannot-open-no-such-file", "file" => input.display_name.clone(), "error" => translate!("tail-no-such-file-or-directory")) - ); - observer.add_bad_path(path, input.display_name.as_str(), false)?; - } else if path.is_dir() { + let md = path.metadata(); + if let Err(ref e) = md { + if e.kind() == ErrorKind::NotFound { + set_exit_code(1); + show_error!( + "{}", + translate!( + "tail-error-cannot-open-no-such-file", + "file" => input.display_name.clone(), + "error" => translate!("tail-no-such-file-or-directory") + ) + ); + observer.add_bad_path(path, input.display_name.as_str(), false)?; + return Ok(()); + } + } + + if path.is_dir() { set_exit_code(1); header_printer.print_input(input); @@ -146,7 +156,6 @@ fn tail_file( ); } if !observer.follow_name_retry() { - // skip directory if not retry return Ok(()); } observer.add_bad_path(path, input.display_name.as_str(), false)?; diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index f2875e7b1e3..6fefc8633c1 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -574,6 +574,31 @@ fn test_follow_non_utf8_bytes() { child.kill(); } +#[test] +#[cfg(unix)] +fn test_permission_denied_is_not_reported_as_not_found() { + use std::fs; + use std::os::unix::fs::PermissionsExt; + + if unsafe { libc::geteuid() } == 0 { + return; + } + + let (at, mut ucmd) = at_and_ucmd!(); + + at.mkdir("noexec"); + at.touch("noexec/file"); + + let dir = at.plus("noexec"); + fs::set_permissions(&dir, fs::Permissions::from_mode(0o000)).unwrap(); + + ucmd.arg("noexec/file") + .fails() + .stderr_contains("Permission denied"); + + fs::set_permissions(&dir, fs::Permissions::from_mode(0o700)).unwrap(); +} + #[test] #[cfg(not(target_os = "windows"))] // FIXME: test times out fn test_follow_multiple() {