Skip to content

find: share one file handle per output path (fixes #439) - #828

Open
MsfPablo wants to merge 1 commit into
uutils:mainfrom
MsfPablo:fix-439-dedup-output-files
Open

find: share one file handle per output path (fixes #439)#828
MsfPablo wants to merge 1 commit into
uutils:mainfrom
MsfPablo:fix-439-dedup-output-files

Conversation

@MsfPablo

Copy link
Copy Markdown
Contributor

Fixes #439.

Problem

GNU find de-duplicates the files opened by its output predicates, so
find . -fprint foo -fprint foo writes each path to foo twice. uutils
opened a separate File for every occurrence of -fprint/-fprintf/
-fprint0/-fls, so each handle had its own file offset and the writes
overwrote one another — only one line per entry survived.

Fix

get_or_create_file now caches opened output files on Config, keyed by the
path as written on the command line (matching GNU's literal-filename
de-duplication), and hands out a shared Rc<File>. Repeated references to the
same path therefore share a single file descriptor and a single file offset.
Printer, Printf and Ls take Option<Rc<File>> instead of Option<File>.
The first reference still truncates, as before.

Tests

Two unit tests in src/find/matchers/mod.rs:

  • get_or_create_file_reuses_handle_for_same_path — the same path yields the
    same Rc, and writes through both handles append rather than overwrite.
  • two_fprints_to_the_same_file_do_not_overwrite_each_other — end-to-end
    through build_top_level_matcher with -fprint out -fprint out, asserting
    the entry appears twice.

Verified the regression test fails without the fix (reverting just the cache
lookup gives left: "…abbbc\n…abbbc\n" / right: "…abbbc\n").

$ cargo test
test result: ok. 228 passed; 0 failed  (lib)
... all other suites ok, 0 failed
$ cargo clippy --all-targets --all-features -- -D warnings
    Finished `dev` profile
$ cargo fmt --all --check
(clean)

AI disclosure

This change was written with the assistance of Claude (Anthropic). I have
reviewed the diff, and ran the build, the full test suite, clippy and rustfmt
locally as shown above.

GNU find de-duplicates the files opened by -fprint, -fprintf, -fprint0
and -fls, so `find -fprint foo -fprint foo` writes each line twice.
We opened a separate File per predicate, so the two handles had
independent file offsets and their writes overwrote each other.

Cache opened output files by the path given on the command line and
hand out a shared Rc<File>, so repeated references to the same path
reuse a single file offset.

Fixes uutils#439
@github-actions

Copy link
Copy Markdown

Commit 2081a60 has test result changes:

bfs testsuite:

Test results comparison:
  Current:   TOTAL: 313 / PASSED: 266 / FAILED: 41 / SKIPPED: 6
  Reference: TOTAL: 313 / PASSED: 267 / FAILED: 40 / SKIPPED: 6

Changes from main branch:
  TOTAL: +0
  PASSED: -1
  FAILED: +1

New test failures (1):
  - gnu/okdir_path_relative

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Specifying the same file for output multiple times in find will overwrite the file by default.

1 participant