Repository: uutils/coreutils (Rust)

Issue:
`uu-tail` error with message `Invalid argument` if -c BYTES and BYTES is greater than bytes of file
Here's the error when running uu-tail with `-c 8194` and the size of the file is 8193 bytes.

```
❯ wc --bytes tests/fixtures/tail/random_ascii_8193_bytes_103_lines.txt
8193 tests/fixtures/tail/random_ascii_8193_bytes_103_lines.txt
❯ RUST_BACKTRACE=1 target/debug/tail -c -8194 tests/fixtures/tail/random_ascii_8193_bytes_103_lines.txt
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }', src/uu/tail/src/tail.rs:1414:56
stack backtrace:
   0: rust_begin_unwind
             at /rustc/878aef79dcdf59d19bb8482202dc55e58ceb62ff/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/878aef79dcdf59d19bb8482202dc55e58ceb62ff/library/core/src/panicking.rs:142:14
   2: core::result::unwrap_failed
             at /rustc/878aef79dcdf59d19bb8482202dc55e58ceb62ff/library/core/src/result.rs:1814:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/878aef79dcdf59d19bb8482202dc55e58ceb62ff/library/core/src/result.rs:1107:23
   4: uu_tail::bounded_tail
             at ./src/uu/tail/src/tail.rs:1414:13
   5: uu_tail::uu_tail
             at ./src/uu/tail/src/tail.rs:485:25
   6: uu_tail::uumain::uumain
             at ./src/uu/tail/src/tail.rs:305:5
   7: uu_tail::uumain
             at ./src/uu/tail/src/tail.rs:295:1
   8: tail::main
             at ./src/uucore/src/lib/lib.rs:91:24
   9: core::ops::function::FnOnce::call_once
             at /rustc/878aef79dcdf59d19bb8482202dc55e58ceb62ff/library/core/src/ops/function.rs:248:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```

I think I found the error in https://github.com/uutils/coreutils/blob/5a726e1ab3484d50c87ce93739e08b620261584f/src/uu/tail/src/tail.rs#L1414
when passing `count = 8194` to `file.seek(SeekFrom::End(-(*count as i64))).unwrap();` and `seek` can't seek to a position within the file lower than 0.

Expected behaviour (like gnu's tail) is to print the whole file.


Discussion:
It seems to work fine adding len by seeking file end like so:
```rust
(FilterMode::Bytes(count), false) => {
    let len = file.seek(SeekFrom::End(0)).unwrap();
    file.seek(SeekFrom::End(-((*count).min(len) as i64))).unwrap();
}
(FilterMode::Bytes(count), true) => {
    let len = file.seek(SeekFrom::End(0)).unwrap();
    // GNU `tail` seems to index bytes and lines starting at 1, not
    // at 0. It seems to treat `+0` and `+1` as the same thing.
    file.seek(SeekFrom::Start((((*count).max(1) - 1) as u64).min(len)))
        .unwrap();
}
```
Is it fine if I add tests and formulate it to a PR or do you want to work on it yourself @Joining7943 ?
@kilpkonn No it's fine go ahead. But as far as I can see only the -c -BYTES (not the -c +BYTES) option was affected.
> @kilpkonn No it's fine go ahead. But as far as I can see only the -c -BYTES (not the -c +BYTES) option was affected.

Yep, you are correct! Will revert that part. Thanks for that!



Patch:
diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs
index 32ebb21b06f..a26fe65209e 100644
--- a/src/uu/tail/src/tail.rs
+++ b/src/uu/tail/src/tail.rs
@@ -1411,7 +1411,9 @@ fn bounded_tail(file: &mut File, settings: &Settings) {
             file.seek(SeekFrom::Start(i as u64)).unwrap();
         }
         (FilterMode::Bytes(count), false) => {
-            file.seek(SeekFrom::End(-(*count as i64))).unwrap();
+            let len = file.seek(SeekFrom::End(0)).unwrap();
+            file.seek(SeekFrom::End(-((*count).min(len) as i64)))
+                .unwrap();
         }
         (FilterMode::Bytes(count), true) => {
             // GNU `tail` seems to index bytes and lines starting at 1, not


Test patch:
diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs
index d4755a48832..6afd55f51d7 100644
--- a/tests/by-util/test_tail.rs
+++ b/tests/by-util/test_tail.rs
@@ -2435,3 +2435,23 @@ fn test_illegal_seek() {
     );
     assert_eq!(p.wait().unwrap().code().unwrap(), 1);
 }
+
+#[test]
+fn test_seek_bytes_backward_outside_file() {
+    new_ucmd!()
+        .arg("-c")
+        .arg("100")
+        .arg(FOOBAR_TXT)
+        .run()
+        .stdout_is_fixture(FOOBAR_TXT);
+}
+
+#[test]
+fn test_seek_bytes_forward_outside_file() {
+    new_ucmd!()
+        .arg("-c")
+        .arg("+100")
+        .arg(FOOBAR_TXT)
+        .run()
+        .stdout_is("");
+}