From c24a51403a8e48af7fc3417a46bd6795f28bcedc Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 28 Oct 2023 22:29:24 +0200 Subject: [PATCH] cat: return the same error message as GNU with loop symlink (#5466) * cat: return the same error message as GNU with loop symlink Should fix tests/du/long-sloop.sh because it is using cat as a ref for error messages Co-authored-by: Daniel Hofstetter --- src/uu/cat/src/cat.rs | 22 ++++++++++++++++++++-- tests/by-util/test_cat.rs | 12 ++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index 10e5d9ce1..da47485cc 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (ToDO) nonprint nonblank nonprinting +// spell-checker:ignore (ToDO) nonprint nonblank nonprinting ELOOP use clap::{crate_version, Arg, ArgAction, Command}; use std::fs::{metadata, File}; use std::io::{self, IsTerminal, Read, Write}; @@ -50,6 +50,8 @@ enum CatError { IsDirectory, #[error("input file is output file")] OutputIsInput, + #[error("Too many levels of symbolic links")] + TooManySymlinks, } type CatResult = Result; @@ -401,7 +403,23 @@ fn get_input_type(path: &str) -> CatResult { return Ok(InputType::StdIn); } - let ft = metadata(path)?.file_type(); + let ft = match metadata(path) { + Ok(md) => md.file_type(), + Err(e) => { + if let Some(raw_error) = e.raw_os_error() { + // On Unix-like systems, the error code for "Too many levels of symbolic links" is 40 (ELOOP). + // we want to provide a proper error message in this case. + #[cfg(not(target_os = "macos"))] + let too_many_symlink_code = 40; + #[cfg(target_os = "macos")] + let too_many_symlink_code = 62; + if raw_error == too_many_symlink_code { + return Err(CatError::TooManySymlinks); + } + } + return Err(CatError::Io(e)); + } + }; match ft { #[cfg(unix)] ft if ft.is_block_device() => Ok(InputType::BlockDevice), diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index 27f40356d..aa86ab066 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -540,3 +540,15 @@ fn test_write_to_self() { "first_file_content.second_file_content." ); } + +#[test] +#[cfg(unix)] +fn test_error_loop() { + let (at, mut ucmd) = at_and_ucmd!(); + at.symlink_file("2", "1"); + at.symlink_file("3", "2"); + at.symlink_file("1", "3"); + ucmd.arg("1") + .fails() + .stderr_is("cat: 1: Too many levels of symbolic links\n"); +}