diff --git a/notify/Cargo.toml b/notify/Cargo.toml index 1772ec6b..f08e666a 100644 --- a/notify/Cargo.toml +++ b/notify/Cargo.toml @@ -35,7 +35,7 @@ kqueue = { version = "1.0", optional = true } mio = { version = "0.8", features = ["os-ext"], optional = true } [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.8", features = ["fileapi", "handleapi", "ioapiset", "minwinbase", "synchapi", "winbase", "winnt"] } +windows-sys = { version = "0.42.0", features = ["Win32_System_Threading", "Win32_Foundation", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_WindowsProgramming", "Win32_System_IO"] } [target.'cfg(any(target_os="freebsd", target_os="openbsd", target_os = "netbsd", target_os = "dragonflybsd"))'.dependencies] kqueue = "^1.0.4" # fix for #344 diff --git a/notify/src/windows.rs b/notify/src/windows.rs index 9a032241..181a555c 100644 --- a/notify/src/windows.rs +++ b/notify/src/windows.rs @@ -5,17 +5,7 @@ //! //! [ref]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363950(v=vs.85).aspx -use winapi::shared::minwindef::TRUE; -use winapi::shared::winerror::ERROR_OPERATION_ABORTED; -use winapi::um::fileapi; -use winapi::um::handleapi::{self, INVALID_HANDLE_VALUE}; -use winapi::um::ioapiset; -use winapi::um::minwinbase::{LPOVERLAPPED, OVERLAPPED}; -use winapi::um::synchapi; -use winapi::um::winbase::{self, INFINITE, WAIT_OBJECT_0}; -use winapi::um::winnt::{self, FILE_NOTIFY_INFORMATION, HANDLE}; - -use crate::{bounded, unbounded, BoundSender, Receiver, Sender, Config}; +use crate::{bounded, unbounded, BoundSender, Config, Receiver, Sender}; use crate::{event::*, WatcherKind}; use crate::{Error, EventHandler, RecursiveMode, Result, Watcher}; use std::collections::HashMap; @@ -29,6 +19,23 @@ use std::ptr; use std::slice; use std::sync::{Arc, Mutex}; use std::thread; +use windows_sys::Win32::Foundation::{ + CloseHandle, ERROR_OPERATION_ABORTED, HANDLE, INVALID_HANDLE_VALUE, WAIT_OBJECT_0, +}; +use windows_sys::Win32::Storage::FileSystem::{ + CreateFileW, ReadDirectoryChangesW, FILE_ACTION_ADDED, FILE_ACTION_MODIFIED, + FILE_ACTION_REMOVED, FILE_ACTION_RENAMED_NEW_NAME, FILE_ACTION_RENAMED_OLD_NAME, + FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OVERLAPPED, FILE_LIST_DIRECTORY, + FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_CREATION, FILE_NOTIFY_CHANGE_DIR_NAME, + FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_NOTIFY_CHANGE_SECURITY, + FILE_NOTIFY_CHANGE_SIZE, FILE_NOTIFY_INFORMATION, FILE_SHARE_DELETE, FILE_SHARE_READ, + FILE_SHARE_WRITE, OPEN_EXISTING, +}; +use windows_sys::Win32::System::Threading::{ + CreateSemaphoreW, ReleaseSemaphore, WaitForSingleObjectEx, +}; +use windows_sys::Win32::System::WindowsProgramming::INFINITE; +use windows_sys::Win32::System::IO::{CancelIo, OVERLAPPED}; const BUF_SIZE: u32 = 16384; @@ -132,7 +139,7 @@ impl ReadDirectoryChangesServer { unsafe { // wait with alertable flag so that the completion routine fires - let waitres = synchapi::WaitForSingleObjectEx(self.wakeup_sem, 100, TRUE); + let waitres = WaitForSingleObjectEx(self.wakeup_sem, 100, 1); if waitres == WAIT_OBJECT_0 { let _ = self.meta_tx.send(MetaEvent::WatcherAwakened); } @@ -141,7 +148,7 @@ impl ReadDirectoryChangesServer { // we have to clean this up, since the watcher may be long gone unsafe { - handleapi::CloseHandle(self.wakeup_sem); + CloseHandle(self.wakeup_sem); } } @@ -170,14 +177,14 @@ impl ReadDirectoryChangesServer { .collect(); let handle; unsafe { - handle = fileapi::CreateFileW( + handle = CreateFileW( encoded_path.as_ptr(), - winnt::FILE_LIST_DIRECTORY, - winnt::FILE_SHARE_READ | winnt::FILE_SHARE_DELETE | winnt::FILE_SHARE_WRITE, - ptr::null_mut(), - fileapi::OPEN_EXISTING, - winbase::FILE_FLAG_BACKUP_SEMANTICS | winbase::FILE_FLAG_OVERLAPPED, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, ptr::null_mut(), + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + 0, ); if handle == INVALID_HANDLE_VALUE { @@ -199,11 +206,10 @@ impl ReadDirectoryChangesServer { None }; // every watcher gets its own semaphore to signal completion - let semaphore = - unsafe { synchapi::CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut()) }; - if semaphore.is_null() || semaphore == INVALID_HANDLE_VALUE { + let semaphore = unsafe { CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut()) }; + if semaphore == 0 || semaphore == INVALID_HANDLE_VALUE { unsafe { - handleapi::CloseHandle(handle); + CloseHandle(handle); } return Err(Error::generic("Failed to create semaphore for watch.").add_path(path)); } @@ -236,16 +242,15 @@ impl ReadDirectoryChangesServer { fn stop_watch(ws: &WatchState, meta_tx: &Sender) { unsafe { - let cio = ioapiset::CancelIo(ws.dir_handle); - let ch = handleapi::CloseHandle(ws.dir_handle); + let cio = CancelIo(ws.dir_handle); + let ch = CloseHandle(ws.dir_handle); // have to wait for it, otherwise we leak the memory allocated for there read request if cio != 0 && ch != 0 { - while synchapi::WaitForSingleObjectEx(ws.complete_sem, INFINITE, TRUE) != WAIT_OBJECT_0 - { + while WaitForSingleObjectEx(ws.complete_sem, INFINITE, 1) != WAIT_OBJECT_0 { // drain the apc queue, fix for https://github.com/notify-rs/notify/issues/287#issuecomment-801465550 } } - handleapi::CloseHandle(ws.complete_sem); + CloseHandle(ws.complete_sem); } let _ = meta_tx.send(MetaEvent::SingleWatchComplete); } @@ -258,13 +263,13 @@ fn start_read(rd: &ReadData, event_handler: Arc>, handle data: rd.clone(), }); - let flags = winnt::FILE_NOTIFY_CHANGE_FILE_NAME - | winnt::FILE_NOTIFY_CHANGE_DIR_NAME - | winnt::FILE_NOTIFY_CHANGE_ATTRIBUTES - | winnt::FILE_NOTIFY_CHANGE_SIZE - | winnt::FILE_NOTIFY_CHANGE_LAST_WRITE - | winnt::FILE_NOTIFY_CHANGE_CREATION - | winnt::FILE_NOTIFY_CHANGE_SECURITY; + let flags = FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_CREATION + | FILE_NOTIFY_CHANGE_SECURITY; let monitor_subdir = if (&request.data.file).is_none() && request.data.is_recursive { 1 @@ -278,12 +283,12 @@ fn start_read(rd: &ReadData, event_handler: Arc>, handle // for our own purposes let req_buf = request.buffer.as_mut_ptr() as *mut c_void; - let request_p = Box::into_raw(request) as *mut c_void; + let request_p = Box::into_raw(request) as isize; overlapped.hEvent = request_p; // This is using an asynchronous call with a completion routine for receiving notifications // An I/O completion port would probably be more performant - let ret = winbase::ReadDirectoryChangesW( + let ret = ReadDirectoryChangesW( handle, req_buf, BUF_SIZE, @@ -299,7 +304,7 @@ fn start_read(rd: &ReadData, event_handler: Arc>, handle // allow overlapped to drop by omitting forget() let request: Box = mem::transmute(request_p); - synchapi::ReleaseSemaphore(request.data.complete_sem, 1, ptr::null_mut()); + ReleaseSemaphore(request.data.complete_sem, 1, ptr::null_mut()); } else { // read ok. forget overlapped to let the completion routine handle memory mem::forget(overlapped); @@ -310,7 +315,7 @@ fn start_read(rd: &ReadData, event_handler: Arc>, handle unsafe extern "system" fn handle_event( error_code: u32, _bytes_written: u32, - overlapped: LPOVERLAPPED, + overlapped: *mut OVERLAPPED, ) { let overlapped: Box = Box::from_raw(overlapped); let request: Box = Box::from_raw(overlapped.hEvent as *mut _); @@ -318,7 +323,7 @@ unsafe extern "system" fn handle_event( if error_code == ERROR_OPERATION_ABORTED { // received when dir is unwatched or watcher is shutdown; return and let overlapped/request // get drop-cleaned - synchapi::ReleaseSemaphore(request.data.complete_sem, 1, ptr::null_mut()); + ReleaseSemaphore(request.data.complete_sem, 1, ptr::null_mut()); return; } @@ -359,7 +364,7 @@ unsafe extern "system" fn handle_event( let event_handler = |res| emit_event(&request.event_handler, res); - if (*cur_entry).Action == winnt::FILE_ACTION_RENAMED_OLD_NAME { + if (*cur_entry).Action == FILE_ACTION_RENAMED_OLD_NAME { let mode = RenameMode::From; let kind = ModifyKind::Name(mode); let kind = EventKind::Modify(kind); @@ -367,22 +372,22 @@ unsafe extern "system" fn handle_event( event_handler(Ok(ev)) } else { match (*cur_entry).Action { - winnt::FILE_ACTION_RENAMED_NEW_NAME => { + FILE_ACTION_RENAMED_NEW_NAME => { let kind = EventKind::Modify(ModifyKind::Name(RenameMode::To)); let ev = newe.set_kind(kind); event_handler(Ok(ev)); } - winnt::FILE_ACTION_ADDED => { + FILE_ACTION_ADDED => { let kind = EventKind::Create(CreateKind::Any); let ev = newe.set_kind(kind); event_handler(Ok(ev)); } - winnt::FILE_ACTION_REMOVED => { + FILE_ACTION_REMOVED => { let kind = EventKind::Remove(RemoveKind::Any); let ev = newe.set_kind(kind); event_handler(Ok(ev)); } - winnt::FILE_ACTION_MODIFIED => { + FILE_ACTION_MODIFIED => { let kind = EventKind::Modify(ModifyKind::Any); let ev = newe.set_kind(kind); event_handler(Ok(ev)); @@ -415,9 +420,8 @@ impl ReadDirectoryChangesWatcher { ) -> Result { let (cmd_tx, cmd_rx) = unbounded(); - let wakeup_sem = - unsafe { synchapi::CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut()) }; - if wakeup_sem.is_null() || wakeup_sem == INVALID_HANDLE_VALUE { + let wakeup_sem = unsafe { CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut()) }; + if wakeup_sem == 0 || wakeup_sem == INVALID_HANDLE_VALUE { return Err(Error::generic("Failed to create wakeup semaphore.")); } @@ -436,7 +440,7 @@ impl ReadDirectoryChangesWatcher { // so that if you add a watch you don't block for 100ms in watch() while the // server sleeps. unsafe { - synchapi::ReleaseSemaphore(self.wakeup_sem, 1, ptr::null_mut()); + ReleaseSemaphore(self.wakeup_sem, 1, ptr::null_mut()); } }