mirror of
https://github.com/neovim/neovim.git
synced 2026-11-06 05:16:52 +00:00
fix(fs): prevent endless EPERM when deleting a parent directory #42635
Problem: On Windows, libuv emits endless EPERM errors when another process deletes the parent directory of an open file, causing nvim to hang. Solution: Ideally, bump libuv version once the issue is fixed upstream. For now, we have to stop handle immediately to prevent endless EPERM errors from starving the debounced cleanup callback in autoread.lua.
This commit is contained in:
2 files changed
+61
No files matched your search
@@ -1,5 +1,6 @@
|
||||
local uv = vim.uv
|
||||
local log = vim.log.new({ name = 'nvim-watch' })
|
||||
local is_win = package.config:sub(1, 1) == '\\'
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -451,6 +452,10 @@ local function watch(path, opts, callback)
|
||||
if events.rename then
|
||||
local _, staterr, staterrname = uv.fs_stat(fullpath)
|
||||
if staterrname == 'ENOENT' then
|
||||
-- stop handle to prevent endless EPERM errors (neovim#41851, libuv#5399)
|
||||
if is_win and not watching_dir then
|
||||
handle:stop()
|
||||
end
|
||||
change_type = M.FileChangeType.Deleted
|
||||
else
|
||||
if staterr then
|
||||
|
||||
@@ -389,6 +389,62 @@ describe('vim._watch', function()
|
||||
}, result)
|
||||
end)
|
||||
|
||||
it('watch() stops when the parent directory of watched file is deleted #41851', function()
|
||||
local root_dir = t.tmpname(false)
|
||||
t.finally(function()
|
||||
n.rmdir(root_dir)
|
||||
end)
|
||||
n.mkdir_p(root_dir)
|
||||
local file = ('%s/file'):format(root_dir)
|
||||
vim.fn.writefile({ 'x' }, file)
|
||||
|
||||
exec_lua(
|
||||
[[
|
||||
local f = ...
|
||||
_G.events = {}
|
||||
_G.errors = {}
|
||||
_G.cancel = vim._watch.watch(f, {
|
||||
on_error = function(err)
|
||||
_G.errors[#_G.errors + 1] = err
|
||||
end,
|
||||
}, function(p, change_type)
|
||||
_G.events[#_G.events + 1] = { path = p, change_type = change_type }
|
||||
end)
|
||||
vim.wait(0)
|
||||
]],
|
||||
file
|
||||
)
|
||||
|
||||
assert(vim.uv.fs_unlink(file))
|
||||
assert(vim.uv.fs_rmdir(root_dir))
|
||||
|
||||
exec_lua([[
|
||||
assert(
|
||||
vim.wait(3000, function()
|
||||
return #_G.events >= 1
|
||||
end), 'Timed out waiting for event')
|
||||
]])
|
||||
eq({
|
||||
path = file,
|
||||
change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]),
|
||||
}, exec_lua [=[return _G.events[#_G.events]]=])
|
||||
|
||||
eq(
|
||||
not is_os('win'),
|
||||
exec_lua(function()
|
||||
local active
|
||||
vim.uv.walk(function(handle)
|
||||
if handle:get_type() == 'fs_event' then
|
||||
active = handle:is_active()
|
||||
end
|
||||
end)
|
||||
return active
|
||||
end)
|
||||
)
|
||||
exec_lua [[_G.cancel()]]
|
||||
eq(0, exec_lua [[return vim._watch.active().watch]])
|
||||
end)
|
||||
|
||||
it('watchdirs() tracks directories for matching files until cancelled', function()
|
||||
local root_dir = t.tmpname(false)
|
||||
n.mkdir_p(root_dir .. '/src')
|
||||
|
||||
Reference in new issue
Block a user