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* filenamew = NULL;
|
||||||
WCHAR* long_filenamew = NULL;
|
WCHAR* long_filenamew = NULL;
|
||||||
DWORD offset = 0;
|
DWORD offset = 0;
|
||||||
|
int dir_event_detected = 0;
|
||||||
|
|
||||||
assert(req->type == UV_FS_EVENT_REQ);
|
assert(req->type == UV_FS_EVENT_REQ);
|
||||||
assert(handle->req_pending);
|
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(!filenamew);
|
||||||
assert(!long_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,
|
* Fire the event only if we were asked to watch a directory,
|
||||||
* or if the filename filter matches.
|
* 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)) &&
|
sizeof(info)) &&
|
||||||
info.Directory &&
|
info.Directory &&
|
||||||
info.DeletePending) {
|
info.DeletePending) {
|
||||||
|
dir_event_detected = 1;
|
||||||
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
uv__convert_utf16_to_utf8(handle->dirw, -1, &filename);
|
||||||
handle->cb(handle, filename, UV_RENAME, 0);
|
handle->cb(handle, filename, UV_RENAME, 0);
|
||||||
uv__free(filename);
|
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) {
|
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||||
} else if (uv__is_active(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);
|
uv__fs_event_queue_readdirchanges(loop, handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -519,6 +519,51 @@ TEST_IMPL(fs_event_watch_delete_dir) {
|
|||||||
return 0;
|
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) {
|
TEST_IMPL(fs_event_watch_dir_recursive) {
|
||||||
#if defined(__APPLE__) && defined(__TSAN__)
|
#if defined(__APPLE__) && defined(__TSAN__)
|
||||||
|
|||||||
@ -410,6 +410,9 @@ TEST_FS_DECLARE (fs_read_bufs)
|
|||||||
TEST_FS_DECLARE (fs_read_file_eof)
|
TEST_FS_DECLARE (fs_read_file_eof)
|
||||||
TEST_DECLARE (fs_event_watch_dir)
|
TEST_DECLARE (fs_event_watch_dir)
|
||||||
TEST_DECLARE (fs_event_watch_delete_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)
|
TEST_DECLARE (fs_event_watch_dir_recursive)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TEST_DECLARE (fs_event_watch_dir_short_path)
|
TEST_DECLARE (fs_event_watch_dir_short_path)
|
||||||
@ -1143,6 +1146,9 @@ TASK_LIST_START
|
|||||||
TEST_FS_ENTRY (fs_file_open_append)
|
TEST_FS_ENTRY (fs_file_open_append)
|
||||||
TEST_ENTRY (fs_event_watch_dir)
|
TEST_ENTRY (fs_event_watch_dir)
|
||||||
TEST_ENTRY (fs_event_watch_delete_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)
|
TEST_ENTRY (fs_event_watch_dir_recursive)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TEST_ENTRY (fs_event_watch_dir_short_path)
|
TEST_ENTRY (fs_event_watch_dir_short_path)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user