Skip to content

Commit 2433e4a

Browse files
authored
Merge branch 'main' into cargo_target_dir
2 parents 07bed67 + 4fda78a commit 2433e4a

File tree

9 files changed

+494
-86
lines changed

9 files changed

+494
-86
lines changed

.github/workflows/CICD.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,14 +435,14 @@ jobs:
435435
--arg multisize "$SIZE_MULTI" \
436436
'{($date): { sha: $sha, size: $size, multisize: $multisize, }}' > size-result.json
437437
- name: Download the previous individual size result
438-
uses: dawidd6/action-download-artifact@v8
438+
uses: dawidd6/action-download-artifact@v9
439439
with:
440440
workflow: CICD.yml
441441
name: individual-size-result
442442
repo: uutils/coreutils
443443
path: dl
444444
- name: Download the previous size result
445-
uses: dawidd6/action-download-artifact@v8
445+
uses: dawidd6/action-download-artifact@v9
446446
with:
447447
workflow: CICD.yml
448448
name: size-result

.github/workflows/GnuTests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
working-directory: ${{ steps.vars.outputs.path_GNU }}
9292

9393
- name: Retrieve reference artifacts
94-
uses: dawidd6/action-download-artifact@v8
94+
uses: dawidd6/action-download-artifact@v9
9595
# ref: <https://github.com/dawidd6/action-download-artifact>
9696
continue-on-error: true ## don't break the build for missing reference artifacts (may be expired or just not generated yet)
9797
with:

Cargo.lock

Lines changed: 16 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/head/src/head.rs

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
99
use std::ffi::OsString;
10+
#[cfg(unix)]
11+
use std::fs::File;
1012
use std::io::{self, BufWriter, Read, Seek, SeekFrom, Write};
1113
use std::num::TryFromIntError;
14+
#[cfg(unix)]
15+
use std::os::fd::{AsRawFd, FromRawFd};
1216
use thiserror::Error;
1317
use uucore::display::Quotable;
1418
use uucore::error::{FromIo, UError, UResult};
@@ -239,39 +243,39 @@ impl HeadOptions {
239243
}
240244
}
241245

242-
fn read_n_bytes(input: impl Read, n: u64) -> std::io::Result<()> {
246+
fn read_n_bytes(input: impl Read, n: u64) -> std::io::Result<u64> {
243247
// Read the first `n` bytes from the `input` reader.
244248
let mut reader = input.take(n);
245249

246250
// Write those bytes to `stdout`.
247251
let stdout = std::io::stdout();
248252
let mut stdout = stdout.lock();
249253

250-
io::copy(&mut reader, &mut stdout)?;
254+
let bytes_written = io::copy(&mut reader, &mut stdout)?;
251255

252256
// Make sure we finish writing everything to the target before
253257
// exiting. Otherwise, when Rust is implicitly flushing, any
254258
// error will be silently ignored.
255259
stdout.flush()?;
256260

257-
Ok(())
261+
Ok(bytes_written)
258262
}
259263

260-
fn read_n_lines(input: &mut impl std::io::BufRead, n: u64, separator: u8) -> std::io::Result<()> {
264+
fn read_n_lines(input: &mut impl std::io::BufRead, n: u64, separator: u8) -> std::io::Result<u64> {
261265
// Read the first `n` lines from the `input` reader.
262266
let mut reader = take_lines(input, n, separator);
263267

264268
// Write those bytes to `stdout`.
265269
let mut stdout = std::io::stdout();
266270

267-
io::copy(&mut reader, &mut stdout)?;
271+
let bytes_written = io::copy(&mut reader, &mut stdout)?;
268272

269273
// Make sure we finish writing everything to the target before
270274
// exiting. Otherwise, when Rust is implicitly flushing, any
271275
// error will be silently ignored.
272276
stdout.flush()?;
273277

274-
Ok(())
278+
Ok(bytes_written)
275279
}
276280

277281
fn catch_too_large_numbers_in_backwards_bytes_or_lines(n: u64) -> Option<usize> {
@@ -284,7 +288,8 @@ fn catch_too_large_numbers_in_backwards_bytes_or_lines(n: u64) -> Option<usize>
284288
}
285289
}
286290

287-
fn read_but_last_n_bytes(input: impl std::io::BufRead, n: u64) -> std::io::Result<()> {
291+
fn read_but_last_n_bytes(input: impl std::io::BufRead, n: u64) -> std::io::Result<u64> {
292+
let mut bytes_written = 0;
288293
if let Some(n) = catch_too_large_numbers_in_backwards_bytes_or_lines(n) {
289294
let stdout = std::io::stdout();
290295
let stdout = stdout.lock();
@@ -294,32 +299,36 @@ fn read_but_last_n_bytes(input: impl std::io::BufRead, n: u64) -> std::io::Resul
294299
let mut writer = BufWriter::with_capacity(BUF_SIZE, stdout);
295300
for byte in take_all_but(input.bytes(), n) {
296301
writer.write_all(&[byte?])?;
302+
bytes_written += 1;
297303
}
298304
// Make sure we finish writing everything to the target before
299305
// exiting. Otherwise, when Rust is implicitly flushing, any
300306
// error will be silently ignored.
301307
writer.flush()?;
302308
}
303-
Ok(())
309+
Ok(bytes_written)
304310
}
305311

306312
fn read_but_last_n_lines(
307313
input: impl std::io::BufRead,
308314
n: u64,
309315
separator: u8,
310-
) -> std::io::Result<()> {
316+
) -> std::io::Result<u64> {
317+
let mut bytes_written: u64 = 0;
311318
if let Some(n) = catch_too_large_numbers_in_backwards_bytes_or_lines(n) {
312319
let stdout = std::io::stdout();
313320
let mut stdout = stdout.lock();
314321
for bytes in take_all_but(lines(input, separator), n) {
315-
stdout.write_all(&bytes?)?;
322+
let bytes = bytes?;
323+
bytes_written += u64::try_from(bytes.len()).unwrap();
324+
stdout.write_all(&bytes)?;
316325
}
317326
// Make sure we finish writing everything to the target before
318327
// exiting. Otherwise, when Rust is implicitly flushing, any
319328
// error will be silently ignored.
320329
stdout.flush()?;
321330
}
322-
Ok(())
331+
Ok(bytes_written)
323332
}
324333

325334
/// Return the index in `input` just after the `n`th line from the end.
@@ -400,60 +409,57 @@ fn is_seekable(input: &mut std::fs::File) -> bool {
400409
&& input.seek(SeekFrom::Start(current_pos.unwrap())).is_ok()
401410
}
402411

403-
fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
412+
fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<u64> {
404413
let st = input.metadata()?;
405414
let seekable = is_seekable(input);
406415
let blksize_limit = uucore::fs::sane_blksize::sane_blksize_from_metadata(&st);
407416
if !seekable || st.len() <= blksize_limit {
408-
return head_backwards_without_seek_file(input, options);
417+
head_backwards_without_seek_file(input, options)
418+
} else {
419+
head_backwards_on_seekable_file(input, options)
409420
}
410-
411-
head_backwards_on_seekable_file(input, options)
412421
}
413422

414423
fn head_backwards_without_seek_file(
415424
input: &mut std::fs::File,
416425
options: &HeadOptions,
417-
) -> std::io::Result<()> {
426+
) -> std::io::Result<u64> {
418427
let reader = std::io::BufReader::with_capacity(BUF_SIZE, &*input);
419428
match options.mode {
420-
Mode::AllButLastBytes(n) => read_but_last_n_bytes(reader, n)?,
421-
Mode::AllButLastLines(n) => read_but_last_n_lines(reader, n, options.line_ending.into())?,
429+
Mode::AllButLastBytes(n) => read_but_last_n_bytes(reader, n),
430+
Mode::AllButLastLines(n) => read_but_last_n_lines(reader, n, options.line_ending.into()),
422431
_ => unreachable!(),
423432
}
424-
425-
Ok(())
426433
}
427434

428435
fn head_backwards_on_seekable_file(
429436
input: &mut std::fs::File,
430437
options: &HeadOptions,
431-
) -> std::io::Result<()> {
438+
) -> std::io::Result<u64> {
432439
match options.mode {
433440
Mode::AllButLastBytes(n) => {
434441
let size = input.metadata()?.len();
435442
if n >= size {
436-
return Ok(());
443+
Ok(0)
437444
} else {
438445
read_n_bytes(
439446
&mut std::io::BufReader::with_capacity(BUF_SIZE, input),
440447
size - n,
441-
)?;
448+
)
442449
}
443450
}
444451
Mode::AllButLastLines(n) => {
445452
let found = find_nth_line_from_end(input, n, options.line_ending.into())?;
446453
read_n_bytes(
447454
&mut std::io::BufReader::with_capacity(BUF_SIZE, input),
448455
found,
449-
)?;
456+
)
450457
}
451458
_ => unreachable!(),
452459
}
453-
Ok(())
454460
}
455461

456-
fn head_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
462+
fn head_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<u64> {
457463
match options.mode {
458464
Mode::FirstBytes(n) => {
459465
read_n_bytes(&mut std::io::BufReader::with_capacity(BUF_SIZE, input), n)
@@ -480,16 +486,41 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
480486
println!("==> standard input <==");
481487
}
482488
let stdin = std::io::stdin();
483-
let mut stdin = stdin.lock();
484-
485-
match options.mode {
486-
Mode::FirstBytes(n) => read_n_bytes(&mut stdin, n),
487-
Mode::AllButLastBytes(n) => read_but_last_n_bytes(&mut stdin, n),
488-
Mode::FirstLines(n) => read_n_lines(&mut stdin, n, options.line_ending.into()),
489-
Mode::AllButLastLines(n) => {
490-
read_but_last_n_lines(&mut stdin, n, options.line_ending.into())
489+
490+
#[cfg(unix)]
491+
{
492+
let stdin_raw_fd = stdin.as_raw_fd();
493+
let mut stdin_file = unsafe { File::from_raw_fd(stdin_raw_fd) };
494+
let current_pos = stdin_file.stream_position();
495+
if let Ok(current_pos) = current_pos {
496+
// We have a seekable file. Ensure we set the input stream to the
497+
// last byte read so that any tools that parse the remainder of
498+
// the stdin stream read from the correct place.
499+
500+
let bytes_read = head_file(&mut stdin_file, options)?;
501+
stdin_file.seek(SeekFrom::Start(current_pos + bytes_read))?;
502+
} else {
503+
let _bytes_read = head_file(&mut stdin_file, options)?;
491504
}
492505
}
506+
507+
#[cfg(not(unix))]
508+
{
509+
let mut stdin = stdin.lock();
510+
511+
match options.mode {
512+
Mode::FirstBytes(n) => read_n_bytes(&mut stdin, n),
513+
Mode::AllButLastBytes(n) => read_but_last_n_bytes(&mut stdin, n),
514+
Mode::FirstLines(n) => {
515+
read_n_lines(&mut stdin, n, options.line_ending.into())
516+
}
517+
Mode::AllButLastLines(n) => {
518+
read_but_last_n_lines(&mut stdin, n, options.line_ending.into())
519+
}
520+
}?;
521+
}
522+
523+
Ok(())
493524
}
494525
(name, false) => {
495526
let mut file = match std::fs::File::open(name) {
@@ -508,7 +539,8 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
508539
}
509540
println!("==> {name} <==");
510541
}
511-
head_file(&mut file, options)
542+
head_file(&mut file, options)?;
543+
Ok(())
512544
}
513545
};
514546
if let Err(e) = res {

0 commit comments

Comments
 (0)