Skip to content

Conversation

asomers
Copy link
Member

@asomers asomers commented Sep 13, 2025

readdir_r does not work well on systems where {NAME_MAX} can vary. The main reason to use it is for thread-safety. However, POSIX 1003.1-2024 Issue 8 makes readdir_r obsolete and clarifies that readdir must be thread-safe except when concurrent calls are made to the same directory stream. So all applications should prefer it now. The original rationale for Nix using readdir_r1, in addition to thread safety, was that the Rust standard library used it. But that is no longer the case. So Nix should switch to plain readdir.

The second problem is that on some operating systems, libc::dirent is an
open-ended structure where the last field (d_name) has a size of 1 byte,
but additional data follow the end of the structure. Nix currently
relies on copying the libc::dirent structure, which can't possibly work
on those platforms. Fix that bug by copying the d_name field to an
owned CString.

What does this PR do

Checklist:

  • I have read CONTRIBUTING.md
  • I have written necessary tests and rustdoc comments
  • A change log has been added if this PR modifies nix's API

Footnotes

  1. f9ebcb7 , from 2018

@asomers asomers force-pushed the readdir_r branch 3 times, most recently from ff8e8bc to 9386cb9 Compare September 13, 2025 22:07
@asomers asomers changed the title dir: use readdir_r instead of readdir fix two problems in the Dir module: Sep 13, 2025
@asomers asomers force-pushed the readdir_r branch 2 times, most recently from 7e5602c to 4644f30 Compare September 13, 2025 22:14
readdir_r does not work well on systems where {NAME_MAX} can vary.  The main
reason to use it is for thread-safety.  However, POSIX 1003.1-2024 Issue 8
makes readdir_r obsolete and clarifies that readdir must be thread-safe except
when concurrent calls are made to the same directory stream.  So all
applications should prefer it now.  The original rationale for Nix using
readdir_r[^1], in addition to thread safety, was that the Rust standard library
used it.  But that is no longer the case.  So Nix should switch to plain
readdir.

The second problem is that on some operating systems, libc::dirent is an
open-ended structure where the last field (d_name) has a size of 1 byte,
but additional data follow the end of the structure.  Nix currently
relies on copying the libc::dirent structure, which can't possibly work
on those platforms.  Fix that bug by copying the d_name field to an
owned CString.

[^1]: f9ebcb7 , from 2018

Fixes nix-rust#2673
Fixes nix-rust#1783
@asomers asomers added this pull request to the merge queue Sep 17, 2025
Merged via the queue into nix-rust:master with commit a214d8f Sep 17, 2025
39 checks passed
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.

1 participant