mirror of
https://github.com/neovim/neovim.git
synced 2025-10-17 07:16:09 +00:00
fix(path): avoid chdir() when resolving path (#28799)
Use uv_fs_realpath() instead.
It seems that uv_fs_realpath() has some problems on non-Linux platforms:
- macOS and other BSDs: this function will fail with UV_ELOOP if more
than 32 symlinks are found while resolving the given path. This limit
is hardcoded and cannot be sidestepped.
- Windows: while this function works in the common case, there are a
number of corner cases where it doesn't:
- Paths in ramdisk volumes created by tools which sidestep the Volume
Manager (such as ImDisk) cannot be resolved.
- Inconsistent casing when using drive letters.
- Resolved path bypasses subst'd drives.
Ref: https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_realpath
I don't know if the old implementation that uses uv_chdir() and uv_cwd()
also suffers from the same problems.
- For the ELOOP case, chdir() seems to have the same limitations.
- On Windows, Vim doesn't use anything like chdir() either. It uses
_wfullpath(), while libuv uses GetFinalPathNameByHandleW().
(cherry picked from commit 42aa69b076
)
This commit is contained in:

committed by
github-actions[bot]
![github-actions[bot]](/assets/img/avatar_default.png)
parent
902980edb9
commit
0cf7e2570c
@@ -22,11 +22,16 @@ local buffer = nil
|
||||
|
||||
describe('path.c', function()
|
||||
describe('path_full_dir_name', function()
|
||||
local old_dir
|
||||
|
||||
setup(function()
|
||||
old_dir = uv.cwd()
|
||||
mkdir('unit-test-directory')
|
||||
uv.fs_symlink(old_dir .. '/unit-test-directory', 'unit-test-symlink')
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
uv.fs_unlink('unit-test-symlink')
|
||||
uv.fs_rmdir('unit-test-directory')
|
||||
end)
|
||||
|
||||
@@ -37,35 +42,64 @@ describe('path.c', function()
|
||||
|
||||
before_each(function()
|
||||
-- Create empty string buffer which will contain the resulting path.
|
||||
length = string.len(uv.cwd()) + 22
|
||||
length = string.len(old_dir) + 22
|
||||
buffer = cstr(length, '')
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
uv.chdir(old_dir)
|
||||
end)
|
||||
|
||||
itp('returns the absolute directory name of a given relative one', function()
|
||||
local result = path_full_dir_name('..', buffer, length)
|
||||
eq(OK, result)
|
||||
local old_dir = uv.cwd()
|
||||
eq(OK, path_full_dir_name('..', buffer, length))
|
||||
uv.chdir('..')
|
||||
local expected = uv.cwd()
|
||||
uv.chdir(old_dir)
|
||||
eq(expected, (ffi.string(buffer)))
|
||||
eq(expected, ffi.string(buffer))
|
||||
end)
|
||||
|
||||
itp('returns the current directory name if the given string is empty', function()
|
||||
eq(OK, (path_full_dir_name('', buffer, length)))
|
||||
eq(uv.cwd(), (ffi.string(buffer)))
|
||||
eq(OK, path_full_dir_name('', buffer, length))
|
||||
eq(old_dir, ffi.string(buffer))
|
||||
end)
|
||||
|
||||
local function test_full_dir_absolute()
|
||||
itp('works with a normal absolute dir', function()
|
||||
eq(OK, path_full_dir_name(old_dir .. '/unit-test-directory', buffer, length))
|
||||
eq(old_dir .. '/unit-test-directory', ffi.string(buffer))
|
||||
end)
|
||||
|
||||
itp('works with a symlinked absolute dir', function()
|
||||
eq(OK, path_full_dir_name(old_dir .. '/unit-test-symlink', buffer, length))
|
||||
eq(old_dir .. '/unit-test-directory', ffi.string(buffer))
|
||||
end)
|
||||
end
|
||||
|
||||
test_full_dir_absolute()
|
||||
|
||||
describe('when cwd does not exist #28786', function()
|
||||
before_each(function()
|
||||
mkdir('dir-to-remove')
|
||||
uv.chdir('dir-to-remove')
|
||||
uv.fs_rmdir(old_dir .. '/dir-to-remove')
|
||||
end)
|
||||
|
||||
test_full_dir_absolute()
|
||||
end)
|
||||
|
||||
itp('works with a normal relative dir', function()
|
||||
local result = path_full_dir_name('unit-test-directory', buffer, length)
|
||||
eq(uv.cwd() .. '/unit-test-directory', (ffi.string(buffer)))
|
||||
eq(OK, result)
|
||||
eq(OK, path_full_dir_name('unit-test-directory', buffer, length))
|
||||
eq(old_dir .. '/unit-test-directory', ffi.string(buffer))
|
||||
end)
|
||||
|
||||
itp('works with a symlinked relative dir', function()
|
||||
eq(OK, path_full_dir_name('unit-test-symlink', buffer, length))
|
||||
eq(old_dir .. '/unit-test-directory', ffi.string(buffer))
|
||||
end)
|
||||
|
||||
itp('works with a non-existing relative dir', function()
|
||||
local result = path_full_dir_name('does-not-exist', buffer, length)
|
||||
eq(uv.cwd() .. '/does-not-exist', (ffi.string(buffer)))
|
||||
eq(OK, result)
|
||||
eq(OK, path_full_dir_name('does-not-exist', buffer, length))
|
||||
eq(old_dir .. '/does-not-exist', ffi.string(buffer))
|
||||
end)
|
||||
|
||||
itp('fails with a non-existing absolute dir', function()
|
||||
|
Reference in New Issue
Block a user