win: fix watch loop logic (#5013)
Refs: https://github.com/nodejs/node/issues/61398
This commit is contained in:
parent
84816e064a
commit
44125af62a
@ -433,6 +433,7 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
WCHAR* filenamew = NULL;
|
||||
WCHAR* long_filenamew = NULL;
|
||||
DWORD offset = 0;
|
||||
int dir_event_detected = 0;
|
||||
|
||||
assert(req->type == UV_FS_EVENT_REQ);
|
||||
assert(handle->req_pending);
|
||||
@ -459,6 +460,10 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
assert(!filenamew);
|
||||
assert(!long_filenamew);
|
||||
|
||||
if (file_info->FileNameLength == 0) {
|
||||
dir_event_detected = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fire the event only if we were asked to watch a directory,
|
||||
* or if the filename filter matches.
|
||||
@ -587,6 +592,7 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
sizeof(info)) &&
|
||||
info.Directory &&
|
||||
info.DeletePending) {
|
||||
dir_event_detected = 1;
|
||||
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
||||
handle->cb(handle, filename, UV_RENAME, 0);
|
||||
uv__free(filename);
|
||||
@ -599,6 +605,26 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (uv__is_active(handle)) {
|
||||
/*
|
||||
* Check if the handle has become a zombie pointing to \$Extend\$Deleted\.
|
||||
* Only perform the check if we detected an event on the directory, which
|
||||
* may indicate deletion.
|
||||
*/
|
||||
if (dir_event_detected) {
|
||||
WCHAR path_buf[MAX_PATH];
|
||||
DWORD path_len = GetFinalPathNameByHandleW(handle->dir_handle,
|
||||
path_buf,
|
||||
ARRAY_SIZE(path_buf),
|
||||
FILE_NAME_NORMALIZED | VOLUME_NAME_NONE);
|
||||
|
||||
if (path_len > 0 && path_len < ARRAY_SIZE(path_buf)) {
|
||||
if (wcsstr(path_buf, L"\\$Extend\\$Deleted\\") != NULL) {
|
||||
handle->cb(handle, NULL, 0, UV_ENOENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uv__fs_event_queue_readdirchanges(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,6 +519,51 @@ TEST_IMPL(fs_event_watch_delete_dir) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static int fs_event_cb_del_dir_perm_got_enoent;
|
||||
|
||||
static void fs_event_cb_del_dir_perm(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
if (status == UV_ENOENT) {
|
||||
fs_event_cb_del_dir_perm_got_enoent = 1;
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_delete_dir_win) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
fs_event_cb_del_dir_perm_got_enoent = 0;
|
||||
fs_event_unlink_files(NULL);
|
||||
delete_dir("watch_del_dir/");
|
||||
create_dir("watch_del_dir");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT_OK(r);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_del_dir_perm, "watch_del_dir", 0);
|
||||
ASSERT_OK(r);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT_OK(r);
|
||||
r = uv_timer_start(&timer, fs_event_del_dir, 100, 0);
|
||||
ASSERT_OK(r);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT_EQ(1, fs_event_cb_del_dir_perm_got_enoent);
|
||||
ASSERT_EQ(2, close_cb_called);
|
||||
|
||||
/* Cleanup */
|
||||
fs_event_unlink_files(NULL);
|
||||
|
||||
MAKE_VALGRIND_HAPPY(loop);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_watch_dir_recursive) {
|
||||
#if defined(__APPLE__) && defined(__TSAN__)
|
||||
|
||||
@ -410,6 +410,9 @@ TEST_FS_DECLARE (fs_read_bufs)
|
||||
TEST_FS_DECLARE (fs_read_file_eof)
|
||||
TEST_DECLARE (fs_event_watch_dir)
|
||||
TEST_DECLARE (fs_event_watch_delete_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (fs_event_watch_delete_dir_win)
|
||||
#endif
|
||||
TEST_DECLARE (fs_event_watch_dir_recursive)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (fs_event_watch_dir_short_path)
|
||||
@ -1143,6 +1146,9 @@ TASK_LIST_START
|
||||
TEST_FS_ENTRY (fs_file_open_append)
|
||||
TEST_ENTRY (fs_event_watch_dir)
|
||||
TEST_ENTRY (fs_event_watch_delete_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (fs_event_watch_delete_dir_win)
|
||||
#endif
|
||||
TEST_ENTRY (fs_event_watch_dir_recursive)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (fs_event_watch_dir_short_path)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user