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

Deleting the watched repository in Linux creates an event but does not in Windows #403

Open
tevoinea opened this issue May 12, 2022 · 4 comments
Labels
A-bug os-windows Z-needs implementation Needs an implementation, will accept PRs

Comments

@tevoinea
Copy link

System details

Linux (WSL2):

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.4 LTS
Release:        20.04
Codename:       focal

$ uname -r
5.10.102.1-microsoft-standard-WSL2

Windows 11:

  • 21H2 (OS Build 22000.675)
  • Not running in a container
  • Not running as a privileged user
  • Not running in a VM

Rust (on both systems):
rustc 1.60.0 (7737e0b5c 2022-04-04)

Notify (on both systems):
notify = "5.0.0-pre.15"

What you did (as detailed as you can)

  1. Create some directory b (Linux: mkdir b, Windows: New-Item b -ItemType "directory")
  2. Watch the directory b (I posted the code below as a minimal repro)
  3. Delete directory b (Linux: rmdir b, Windows: Remove-Item b)
  4. See on Linux that an event was created Ok(Event { kind: Remove(File), paths: ["b"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }) but on Windows, no event is created
use notify::{Watcher, RecursiveMode};
use std::sync::mpsc::channel;
use std::path::Path;

fn main() {
    let (tx, rx) = channel();
    let mut watcher = notify::recommended_watcher(tx).unwrap();
    let path = Path::new("b");
    watcher.watch(&path, RecursiveMode::NonRecursive);

    loop {
        match rx.recv() {
            Ok(e) => println!("{:?}", e),
            Err(e) => println!("Error: {:?}", e),
        }
    }
}

What you expected

The behavior should be consistent across both Linux and Windows. Either both should receive the directory delete event or neither.

What happened

Only the Linux implementation receives the folder delete event.

@0xpr03
Copy link
Member

0xpr03 commented May 12, 2022

My guess is that the windows file API simply does not emit events for that case, while on linux it does. Would be interesting to test for this on the other Systems. I did a short search through the docs but I couldn't find anything obvious.

@0xpr03
Copy link
Member

0xpr03 commented May 12, 2022

Ok I found something and it's not fun:
https://stackoverflow.com/a/49902015/3332686

To summarize:
The handle stays open, the folder itself isn't deleted (only when the last handle is closed -> we stop watching it).
One could

  • call GetFinalPathNameByHandle in addition in a loop and compare if something changed here from the original result
  • watch the parent
  • watch from a single temporary folder with a symlink.

I'd propose we simply document this behavior and one should watch the parent directory.

Edit to clarify: We simply won't get top-level deletion events on windows.

@tevoinea
Copy link
Author

Thanks for looking into this! I definitely think that documenting the behavior and the parent directory workaround is a good idea.

It seems there are some solutions like the ones listed in that stackoverflow answer. In notify's case it could be some separate thread that occasionally polls the watched directory using GetFinalPathNameByHandle but I understand that's far from a 'clean' implementation.

@0xpr03 0xpr03 added the Z-needs implementation Needs an implementation, will accept PRs label Aug 10, 2022
@0xpr03
Copy link
Member

0xpr03 commented Aug 30, 2022

fyi: behaviour is documented and links to this issue for now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-bug os-windows Z-needs implementation Needs an implementation, will accept PRs
Projects
None yet
Development

No branches or pull requests

2 participants