* tr: Fix regression causing read error with sockets
The test used for determining if a file descriptor
tested with fstat points to a directory is traditionally
done by using the S_IFMT mask[^1][^2], e.g.:
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
In Rust, this translates to 'm & libc::S_IFMT == libc::S_IFDIR'.
is_stdin_directory() uses 'has!(mode, S_IFDIR)', which is
**not** equivalent and causes non-directory sockets to be
incorrectly recognized as directories. This causes uu-tr
to break when used with all sockets created with socketpair,
including ksh93 pipes[^3]. Below is an example Rust program
demonstrating why the current check is bogus:
fn main() {
use nix::sys::socket::{socketpair, SockFlag, AddressFamily, SockType};
use nix::sys::stat::fstat;
use libc::{S_IFDIR, S_IFMT, mode_t};
let (_fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
let mode = fstat(&fd2).unwrap().st_mode as mode_t;
if mode & S_IFMT == S_IFDIR { // Equivalent to S_ISDIR()
println!("Not reached"); // Not a dir, so unreachable
}
if mode & S_IFDIR == S_IFDIR { // Bogus check for S_IFDIR
println!("BAD");
}
}
- is_stdin_directory(): Fix the regression introduced in 3e4221a4
by replacing the bogus check with one equivalent to S_ISDIR().
- test_tr.rs: Add a regression test for this bug.
[^1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=io/sys/stat.h;h=4bea9e9a#l123
[^2]: https://git.musl-libc.org/cgit/musl/tree/include/sys/stat.h?id=047a1639#n51
[^3]: https://github.com/ksh93/ksh/blob/cc5e0692/src/cmd/ksh93/sh/io.c#L98-L102
Fixes https://github.com/uutils/coreutils/issues/7658
* Add comment explaining rationale
Also fix cargo clippy lint.
(In case it isn't obvious, I'm fairly new to Rust)
* Fix more lint
Specifically:
- check_against_gnu_tr_tests_e: Yes, the test is about octal interpretation.
- check_against_gnu_tr_tests_ross_0a: Yes, the [Y*] generates multiple Y's, which causes conflicting replacements, which is why the operation is rejected.
- check_against_gnu_tr_tests_ross_0b: Same, plus a newline character was accidentally forgotten.
- check_against_gnu_tr_tests_fowler_1: Apparently the problem was fixed at some point.