Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit b991120

Browse files
Bump notify from 5.1.0 to 6.0.1 in /src/agent (#3195)
* Bump notify from 5.1.0 to 6.0.1 in /src/agent Bumps [notify](https://github.com/notify-rs/notify) from 5.1.0 to 6.0.1. - [Release notes](https://github.com/notify-rs/notify/releases) - [Changelog](https://github.com/notify-rs/notify/blob/main/CHANGELOG.md) - [Commits](notify-rs/notify@notify-5.1.0...notify-6.0.1) --- updated-dependencies: - dependency-name: notify dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Update for new notify API which has renames * Add tests for expected behaviour * Disable crossbeam support as recommended for use with Tokio * Fix Windows behaviour * Pre-filter events * Log when ignoring unknown rename event --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: George Pollard <gpollard@microsoft.com>
1 parent 06fb0d3 commit b991120

File tree

5 files changed

+174
-55
lines changed

5 files changed

+174
-55
lines changed

src/agent/Cargo.lock

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

src/agent/debugger/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ features = [
2727
"processthreadsapi",
2828
"securitybaseapi",
2929
"shellapi",
30+
"synchapi",
3031
"werapi",
3132
"winbase",
3233
"winerror"

src/agent/onefuzz/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ futures-util = "0.3"
1818
hex = "0.4"
1919
lazy_static = "1.4"
2020
log = "0.4"
21-
notify = "5.1.0"
21+
notify = { version = "6.0.1", default-features = false }
2222
regex = "1.9.1"
2323
reqwest = { version = "0.11", features = [
2424
"json",

src/agent/onefuzz/src/monitor.rs

Lines changed: 97 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use std::{
5-
io::ErrorKind,
6-
path::{Path, PathBuf},
7-
};
4+
use std::path::{Path, PathBuf};
85

9-
use anyhow::{format_err, Result};
10-
use notify::{Event, EventKind, Watcher};
6+
use anyhow::{format_err, Context, Result};
7+
use notify::{
8+
event::{CreateKind, ModifyKind, RenameMode},
9+
Event, EventKind, Watcher,
10+
};
1111
use tokio::{
1212
fs,
1313
sync::mpsc::{unbounded_channel, UnboundedReceiver},
@@ -41,12 +41,37 @@ impl DirectoryMonitor {
4141
}
4242

4343
let (sender, notify_events) = unbounded_channel();
44-
let event_handler = move |event_or_err| {
45-
// A send error only occurs when the channel is closed. No remedial
46-
// action is needed (or possible), so ignore it.
47-
let _ = sender.send(event_or_err);
48-
};
49-
let mut watcher = notify::recommended_watcher(event_handler)?;
44+
let mut watcher =
45+
notify::recommended_watcher(move |event_or_err: notify::Result<Event>| {
46+
// pre-filter the events here
47+
let result = match event_or_err {
48+
Ok(ev) => match ev.kind {
49+
// we are interested in:
50+
// - create
51+
// - remove
52+
// - modify name
53+
EventKind::Create(_)
54+
| EventKind::Remove(_)
55+
| EventKind::Modify(ModifyKind::Name(_)) => Some(Ok(ev)),
56+
// we are not interested in:
57+
// - access
58+
// - modify something else (data, metadata)
59+
// - any other events
60+
EventKind::Access(_)
61+
| EventKind::Modify(_)
62+
| EventKind::Any
63+
| EventKind::Other => None,
64+
},
65+
Err(err) => Some(Err(err)),
66+
};
67+
68+
if let Some(to_send) = result {
69+
// A send error only occurs when the channel is closed. No remedial
70+
// action is needed (or possible), so ignore it.
71+
let _ = sender.send(to_send);
72+
}
73+
})?;
74+
5075
watcher.watch(&dir, RecursiveMode::NonRecursive)?;
5176

5277
Ok(Self {
@@ -89,56 +114,87 @@ impl DirectoryMonitor {
89114
}
90115
};
91116

117+
let mut paths = event.paths.into_iter();
118+
92119
match event.kind {
93-
EventKind::Create(..) => {
94-
let path = event
95-
.paths
96-
.get(0)
97-
.ok_or_else(|| format_err!("missing path for file create event"))?
98-
.clone();
99-
100-
if self.report_directories {
101-
return Ok(Some(path));
120+
EventKind::Create(create_kind) => {
121+
let path = paths
122+
.next()
123+
.ok_or_else(|| format_err!("missing path for file create event"))?;
124+
125+
match create_kind {
126+
CreateKind::File => {
127+
return Ok(Some(path));
128+
}
129+
CreateKind::Folder => {
130+
if self.report_directories {
131+
return Ok(Some(path));
132+
}
133+
}
134+
CreateKind::Any | CreateKind::Other => {
135+
if self.report_directories {
136+
return Ok(Some(path));
137+
}
138+
139+
// check if it is a file
140+
let metadata = fs::metadata(&path)
141+
.await
142+
.context("checking metadata for file")?;
143+
144+
if metadata.is_file() {
145+
return Ok(Some(path));
146+
}
147+
}
102148
}
149+
}
150+
EventKind::Modify(ModifyKind::Name(rename_mode)) => {
151+
match rename_mode {
152+
RenameMode::To => {
153+
let path = paths.next().ok_or_else(|| {
154+
format_err!("missing 'to' path for file rename-to event")
155+
})?;
103156

104-
match fs::metadata(&path).await {
105-
Ok(metadata) if metadata.is_file() => {
106157
return Ok(Some(path));
107158
}
108-
Ok(_) => {
109-
// Ignore directories.
110-
continue;
159+
RenameMode::Both => {
160+
let _from = paths.next().ok_or_else(|| {
161+
format_err!("missing 'from' path for file rename event")
162+
})?;
163+
164+
let to = paths.next().ok_or_else(|| {
165+
format_err!("missing 'to' path for file rename event")
166+
})?;
167+
168+
return Ok(Some(to));
111169
}
112-
Err(err) if err.kind() == ErrorKind::NotFound => {
113-
// Ignore if deleted.
114-
continue;
170+
RenameMode::From => {
171+
// ignore rename-from
115172
}
116-
Err(err) => {
117-
warn!(
118-
"error checking metadata for file. path = {}, error = {}",
119-
path.display(),
120-
err
173+
RenameMode::Any | RenameMode::Other => {
174+
// something unusual, ignore
175+
info!(
176+
"unknown rename event: ignoring {:?} for path {:?}",
177+
rename_mode,
178+
paths.next()
121179
);
122-
continue;
123180
}
124181
}
125182
}
126183
EventKind::Remove(..) => {
127-
let path = event
128-
.paths
129-
.get(0)
184+
let path = paths
185+
.next()
130186
.ok_or_else(|| format_err!("missing path for file remove event"))?;
131187

132-
if path == &self.dir {
188+
if path == self.dir {
133189
// The directory we were watching was removed; we're done.
134190
let _ = self.stop();
135191
return Ok(None);
136192
} else {
137193
// Some file _inside_ the watched directory was removed. Ignore.
138194
}
139195
}
140-
_event_kind => {
141-
// Other filesystem event. Ignore.
196+
EventKind::Access(_) | EventKind::Modify(_) | EventKind::Other | EventKind::Any => {
197+
unreachable!() // these events have already been filtered out
142198
}
143199
}
144200
}

src/agent/onefuzz/src/monitor/tests.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,76 @@ timed_test!(test_monitor_set_report_directories, async move {
155155

156156
Ok(())
157157
});
158+
159+
timed_test!(test_rename_into_dir, async move {
160+
use std::fs::canonicalize;
161+
162+
let dir1 = tempdir().unwrap();
163+
let dir2 = tempdir().unwrap();
164+
165+
// create file
166+
let file1 = dir1.path().join("testfile");
167+
fs::write(&file1, &"xxx").await?;
168+
169+
// start watching
170+
let mut monitor = DirectoryMonitor::new(dir2.path()).await?;
171+
172+
// move into watched dir
173+
let file2 = dir2.path().join("testfile");
174+
fs::rename(&file1, &file2).await?;
175+
176+
// should get notification
177+
assert_eq!(monitor.next_file().await?, Some(canonicalize(file2)?));
178+
179+
Ok(())
180+
});
181+
182+
timed_test!(test_rename_inside_dir, async move {
183+
use std::fs::canonicalize;
184+
185+
// create file
186+
let dir = tempdir().unwrap();
187+
let file1 = dir.path().join("testfile");
188+
fs::write(&file1, &"xxx").await?;
189+
190+
// start watching
191+
let mut monitor = DirectoryMonitor::new(dir.path()).await?;
192+
193+
// rename inside watched dir
194+
let file2 = dir.path().join("testfile_2");
195+
fs::rename(&file1, &file2).await?;
196+
197+
// should get notification
198+
assert_eq!(monitor.next_file().await?, Some(canonicalize(&file2)?));
199+
200+
Ok(())
201+
});
202+
203+
timed_test!(test_rename_out_of_dir, async move {
204+
let dir1 = tempdir().unwrap();
205+
let dir2 = tempdir().unwrap();
206+
207+
// create file
208+
let file1 = dir1.path().join("testfile");
209+
fs::write(&file1, &"xxx").await?;
210+
211+
// start watching
212+
let mut monitor = DirectoryMonitor::new(dir1.path()).await?;
213+
214+
// move _out_ of watched dir
215+
let file2 = dir2.path().join("testfile");
216+
fs::rename(&file1, &file2).await?;
217+
218+
// TODO: on Windows, `notify` doesn't provide an event for the removal of a
219+
// watched directory, so we can't proactively close our channel.
220+
#[cfg(not(target_os = "windows"))]
221+
{
222+
dir1.close()?;
223+
// shouldn't get any notification
224+
assert_eq!(monitor.next_file().await?, None);
225+
}
226+
227+
let _ = monitor.stop();
228+
229+
Ok(())
230+
});

0 commit comments

Comments
 (0)