aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/path.c
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-05-17 18:39:01 +0800
committerGitHub <noreply@github.com>2024-05-17 18:39:01 +0800
commit42aa69b076cb338e20b5b4656771f1873e8930d8 (patch)
treecc1b82eb2e91c93c78af88a9feb62889833848b8 /src/nvim/path.c
parent10f917351906ca2d3c61a6b9bd8b8ae88a26ed8f (diff)
downloadrneovim-42aa69b076cb338e20b5b4656771f1873e8930d8.tar.gz
rneovim-42aa69b076cb338e20b5b4656771f1873e8930d8.tar.bz2
rneovim-42aa69b076cb338e20b5b4656771f1873e8930d8.zip
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().
Diffstat (limited to 'src/nvim/path.c')
-rw-r--r--src/nvim/path.c43
1 files changed, 13 insertions, 30 deletions
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.