Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement -ignore_readdir_race and -noignore_readdir_race. #411

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/find/matchers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,20 @@ fn build_matcher_tree(

return Ok((i, top_level_matcher.build()));
}
// In our implementation, including the `-exec` parameter,
// it is always run in a single thread.
// Therefore, there is no race condition for now.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "race condition" that this flag is talking about is another command simultaneously modifying the directory while find is reading it, something like

tavianator@graphene $ touch {1..10000}
tavianator@graphene $ find -size 1 & rm ./*
[1] 65991
find: ‘./10000’: No such file or directory
[1]  + 65991 exit 1     find -size 1
tavianator@graphene $ touch {1..10000}
tavianator@graphene $ find -ignore_readdir_race -size 1 & rm ./*
[1] 66034
[1]  + 66034 done       find -ignore_readdir_race -size 1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hanbings ping ? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I forgot about this. The race condition does happen when deleting a large number of files, and I'm rewriting a piece of code that implements this feature.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terribly sorry, I did misunderstand the meaning of readdir_race.

I rechecked the code and read the GNU documentation. The -ignore_readdir_race parameter requires a way to suppress file not found errors globally in the software, so I need to complete #15 to centralize the error handling logic before I can return here.

I will finish them as soon as possible. :)

// and we currently only add the corresponding fields in Config.
//
// Related: https://github.com/uutils/findutils/pull/411#issuecomment-2210638686
"-ignore_readdir_race" => {
config.ignore_readdir_race = true;
None
}
"-noignore_readdir_race" => {
config.ignore_readdir_race = false;
None
}
"-daystart" => {
config.today_start = true;
None
Expand Down
45 changes: 34 additions & 11 deletions src/find/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct Config {
sorted_output: bool,
help_requested: bool,
version_requested: bool,
ignore_readdir_race: bool,
hanbings marked this conversation as resolved.
Show resolved Hide resolved
today_start: bool,
no_leaf_dirs: bool,
}
Expand All @@ -35,6 +36,8 @@ impl Default for Config {
sorted_output: false,
help_requested: false,
version_requested: false,
// For compat: doesn't change anything
ignore_readdir_race: false,
today_start: false,
// Directory information and traversal are done by walkdir,
// and this configuration field will exist as
Expand Down Expand Up @@ -1232,17 +1235,6 @@ mod tests {
assert_eq!(rc, 0);
}

#[test]
#[cfg(unix)]
fn test_noleaf() {
use crate::find::tests::FakeDependencies;

let deps = FakeDependencies::new();
let rc = find_main(&["find", "./test_data/simple/subdir", "-noleaf"], &deps);

assert_eq!(rc, 0);
}

#[test]
fn find_maxdepth_and() {
let deps = FakeDependencies::new();
Expand Down Expand Up @@ -1300,4 +1292,35 @@ mod tests {

assert_eq!(rc, 0);
}

#[test]
#[cfg(unix)]
fn test_ignore_readdir_race() {
use crate::find::tests::FakeDependencies;

let deps = FakeDependencies::new();
let rc = find_main(
&["find", "./test_data/simple/subdir", "-ignore_readdir_race"],
&deps,
);

assert_eq!(rc, 0);
}

#[test]
fn test_noignore_readdir_race() {
use crate::find::tests::FakeDependencies;

let deps = FakeDependencies::new();
let rc = find_main(
&[
"find",
"./test_data/simple/subdir",
"-noignore_readdir_race",
],
&deps,
);

assert_eq!(rc, 0);
}
}
36 changes: 24 additions & 12 deletions tests/find_cmd_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,18 +910,6 @@ fn find_samefile() {
.stderr(predicate::str::contains("not-exist-file"));
}

#[test]
#[serial(working_dir)]
fn find_noleaf() {
Command::cargo_bin("find")
.expect("found binary")
.args(["test_data/simple/subdir", "-noleaf"])
.assert()
.success()
.stdout(predicate::str::contains("test_data/simple/subdir"))
.stderr(predicate::str::is_empty());
}

#[test]
#[serial(working_dir)]
fn find_daystart() {
Expand All @@ -946,3 +934,27 @@ fn find_daystart() {
.success()
.stderr(predicate::str::is_empty());
}

#[test]
#[serial(working_dir)]
fn find_ignore_readdir_race() {
Command::cargo_bin("find")
.expect("found binary")
.args(["./test_data/simple/subdir", "-ignore_readdir_race"])
.assert()
.success()
.stdout(predicate::str::contains("./test_data/simple/subdir"))
.stderr(predicate::str::is_empty());
}

#[test]
#[serial(working_dir)]
fn find_noignore_readdir_race() {
Command::cargo_bin("find")
.expect("found binary")
.args(["./test_data/simple/subdir", "-noignore_readdir_race"])
.assert()
.success()
.stdout(predicate::str::contains("./test_data/simple/subdir"))
.stderr(predicate::str::is_empty());
}
Loading