aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval/funcs.c4
-rw-r--r--src/nvim/os/env.c14
-rw-r--r--src/nvim/os/fs.c14
-rw-r--r--src/nvim/path.c43
-rw-r--r--test/unit/path_spec.lua60
5 files changed, 72 insertions, 63 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index b1ee33929c..1fc80e88c4 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -6479,7 +6479,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *v = os_resolve_shortcut(fname);
if (v == NULL) {
if (os_is_reparse_point_include(fname)) {
- v = os_realpath(fname, v);
+ v = os_realpath(fname, NULL, MAXPATHL + 1);
}
}
rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v);
@@ -6631,7 +6631,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
xfree(buf);
}
# else
- char *v = os_realpath(fname, NULL);
+ char *v = os_realpath(fname, NULL, MAXPATHL + 1);
rettv->vval.v_string = v == NULL ? xstrdup(fname) : v;
# endif
#endif
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index fbc3a243a6..5a79004c41 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -474,17 +474,9 @@ void init_homedir(void)
var = os_homedir();
}
- if (var != NULL) {
- // Change to the directory and get the actual path. This resolves
- // links. Don't do it when we can't return.
- if (os_dirname(os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) {
- if (!os_chdir(var) && os_dirname(IObuff, IOSIZE) == OK) {
- var = IObuff;
- }
- if (os_chdir(os_buf) != 0) {
- emsg(_(e_prev_dir));
- }
- }
+ // Get the actual path. This resolves links.
+ if (var != NULL && os_realpath(var, IObuff, IOSIZE) != NULL) {
+ var = IObuff;
}
// Fall back to current working directory if home is not found
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 2eca906d4e..19bdf30311 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -1320,22 +1320,22 @@ bool os_fileid_equal_fileinfo(const FileID *file_id, const FileInfo *file_info)
/// Return the canonicalized absolute pathname.
///
/// @param[in] name Filename to be canonicalized.
-/// @param[out] buf Buffer to store the canonicalized values. A minimum length
-// of MAXPATHL+1 is required. If it is NULL, memory is
-// allocated. In that case, the caller should deallocate this
-// buffer.
+/// @param[out] buf Buffer to store the canonicalized values.
+/// If it is NULL, memory is allocated. In that case, the caller
+/// should deallocate this buffer.
+/// @param[in] len The length of the buffer.
///
/// @return pointer to the buf on success, or NULL.
-char *os_realpath(const char *name, char *buf)
+char *os_realpath(const char *name, char *buf, size_t len)
FUNC_ATTR_NONNULL_ARG(1)
{
uv_fs_t request;
int result = uv_fs_realpath(NULL, &request, name, NULL);
if (result == kLibuvSuccess) {
if (buf == NULL) {
- buf = xmallocz(MAXPATHL);
+ buf = xmalloc(len);
}
- xstrlcpy(buf, request.ptr, MAXPATHL + 1);
+ xstrlcpy(buf, request.ptr, len);
}
uv_fs_req_cleanup(&request);
return result == kLibuvSuccess ? buf : NULL;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index f7e8b2b65c..96330e000b 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -2273,13 +2273,20 @@ bool match_suffix(char *fname)
/// @return `FAIL` for failure, `OK` for success.
int path_full_dir_name(char *directory, char *buffer, size_t len)
{
- int SUCCESS = 0;
- int retval = OK;
-
if (strlen(directory) == 0) {
return os_dirname(buffer, len);
}
+ if (os_realpath(directory, buffer, len) != NULL) {
+ return OK;
+ }
+
+ // Path does not exist (yet). For a full path fail, will use the path as-is.
+ if (path_is_absolute(directory)) {
+ return FAIL;
+ }
+ // For a relative path use the current directory and append the file name.
+
char old_dir[MAXPATHL];
// Get current directory name.
@@ -2287,36 +2294,12 @@ int path_full_dir_name(char *directory, char *buffer, size_t len)
return FAIL;
}
- // We have to get back to the current dir at the end, check if that works.
- if (os_chdir(old_dir) != SUCCESS) {
+ xstrlcpy(buffer, old_dir, len);
+ if (append_path(buffer, directory, len) == FAIL) {
return FAIL;
}
- if (os_chdir(directory) != SUCCESS) {
- // Path does not exist (yet). For a full path fail,
- // will use the path as-is. For a relative path use
- // the current directory and append the file name.
- if (path_is_absolute(directory)) {
- // Do not return immediately since we may be in the wrong directory.
- retval = FAIL;
- } else {
- xstrlcpy(buffer, old_dir, len);
- if (append_path(buffer, directory, len) == FAIL) {
- retval = FAIL;
- }
- }
- } else if (os_dirname(buffer, len) == FAIL) {
- // Do not return immediately since we are in the wrong directory.
- retval = FAIL;
- }
-
- if (os_chdir(old_dir) != SUCCESS) {
- // That shouldn't happen, since we've tested if it works.
- retval = FAIL;
- emsg(_(e_prev_dir));
- }
-
- return retval;
+ return OK;
}
// Append to_append to path with a slash in between.
diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua
index 44919368bf..6f6a80f44e 100644
--- a/test/unit/path_spec.lua
+++ b/test/unit/path_spec.lua
@@ -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()