mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-10-11 00:00:13 +08:00
[Fix] Handle filesystem identity when checking path containment
Fixes #1049. Assisted-by: OpenAI GPT-6 <noreply@openai.com>
This commit is contained in:
@@ -552,9 +552,8 @@ else
|
|||||||
fi
|
fi
|
||||||
unset NVM_SCRIPT_SOURCE 2>/dev/null
|
unset NVM_SCRIPT_SOURCE 2>/dev/null
|
||||||
|
|
||||||
# Performs pure in-memory POSIX path containment checking without subshell process forks.
|
# Walks parent paths without subshells, comparing names literally before checking
|
||||||
# Uses case-guarded ${pathdir%/*} for parent-walk and exact string equality (=) to ensure literal matching
|
# filesystem identity to account for case-insensitive paths and directory symlinks.
|
||||||
# for directory names containing glob metacharacters (*, ?, []) across all shells including zsh.
|
|
||||||
nvm_tree_contains_path() {
|
nvm_tree_contains_path() {
|
||||||
local tree
|
local tree
|
||||||
tree="${1-}"
|
tree="${1-}"
|
||||||
@@ -577,12 +576,11 @@ nvm_tree_contains_path() {
|
|||||||
clean_tree='/'
|
clean_tree='/'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pure in-memory POSIX parent-walk using parameter expansion instead of subshell dirname forks.
|
# Keep literal matching for paths that do not exist, including glob characters.
|
||||||
# Uses literal string equality [ "${pathdir}" = "${clean_tree}" ] to prevent glob expansion bugs.
|
|
||||||
local pathdir
|
local pathdir
|
||||||
pathdir="${node_path}"
|
pathdir="${node_path}"
|
||||||
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
|
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
|
||||||
[ "${pathdir}" != "${clean_tree}" ]; do
|
[ "${pathdir}" != "${clean_tree}" ] && ! [ "${pathdir}" -ef "${clean_tree}" ]; do
|
||||||
case "${pathdir}" in
|
case "${pathdir}" in
|
||||||
*/*)
|
*/*)
|
||||||
pathdir="${pathdir%/*}"
|
pathdir="${pathdir%/*}"
|
||||||
@@ -595,7 +593,7 @@ nvm_tree_contains_path() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
[ "${pathdir}" = "${clean_tree}" ]
|
[ "${pathdir}" = "${clean_tree}" ] || [ "${pathdir}" -ef "${clean_tree}" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_find_project_dir() {
|
nvm_find_project_dir() {
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
cleanup () {
|
cleanup () {
|
||||||
|
rm tmp-alias
|
||||||
|
if [ "${CASE_SENSITIVE-}" = '1' ]; then
|
||||||
|
rm tmp/TREE/node
|
||||||
|
rmdir tmp/TREE
|
||||||
|
fi
|
||||||
|
rm tmp/tree/node
|
||||||
|
rmdir tmp/tree
|
||||||
rm tmp/node
|
rm tmp/node
|
||||||
rmdir tmp
|
rmdir tmp
|
||||||
rm tmp2/node
|
rm tmp2/node
|
||||||
@@ -15,6 +22,15 @@ mkdir -p tmp
|
|||||||
touch tmp/node
|
touch tmp/node
|
||||||
mkdir -p tmp2
|
mkdir -p tmp2
|
||||||
touch tmp2/node
|
touch tmp2/node
|
||||||
|
mkdir -p tmp/tree
|
||||||
|
touch tmp/tree/node
|
||||||
|
ln -s tmp tmp-alias
|
||||||
|
CASE_SENSITIVE=0
|
||||||
|
if [ ! -d tmp/TREE ]; then
|
||||||
|
CASE_SENSITIVE=1
|
||||||
|
mkdir tmp/TREE
|
||||||
|
touch tmp/TREE/node
|
||||||
|
fi
|
||||||
|
|
||||||
[ "$(nvm_tree_contains_path 2>&1)" = "both the tree and the node path are required" ] || die 'incorrect error message with no args'
|
[ "$(nvm_tree_contains_path 2>&1)" = "both the tree and the node path are required" ] || die 'incorrect error message with no args'
|
||||||
[ "$(nvm_tree_contains_path > /dev/null 2>&1 ; echo $?)" = "2" ] || die 'incorrect error code with no args'
|
[ "$(nvm_tree_contains_path > /dev/null 2>&1 ; echo $?)" = "2" ] || die 'incorrect error code with no args'
|
||||||
@@ -36,4 +52,18 @@ nvm_tree_contains_path / /tmp/node || die '"/" should contain "/tmp/node"'
|
|||||||
nvm_tree_contains_path "tmp[glob]" "tmp[glob]/node" || die '"tmp[glob]" should contain "tmp[glob]/node"'
|
nvm_tree_contains_path "tmp[glob]" "tmp[glob]/node" || die '"tmp[glob]" should contain "tmp[glob]/node"'
|
||||||
nvm_tree_contains_path "tmp" "tmp[glob]/node" && die '"tmp" should not contain "tmp[glob]/node"'
|
nvm_tree_contains_path "tmp" "tmp[glob]/node" && die '"tmp" should not contain "tmp[glob]/node"'
|
||||||
|
|
||||||
|
if [ "${CASE_SENSITIVE}" = '1' ]; then
|
||||||
|
nvm_tree_contains_path tmp/tree tmp/TREE/node && die 'case-sensitive directories should stay distinct'
|
||||||
|
nvm_tree_contains_path tmp/TREE tmp/tree/node && die 'case-sensitive directories should stay distinct'
|
||||||
|
else
|
||||||
|
nvm_tree_contains_path tmp/tree tmp/TREE/node || die 'case-insensitive directories should match'
|
||||||
|
nvm_tree_contains_path tmp/TREE tmp/tree/node || die 'case-insensitive directories should match'
|
||||||
|
fi
|
||||||
|
|
||||||
|
nvm_tree_contains_path tmp-alias tmp/node || die 'a symlink to the tree should contain its node'
|
||||||
|
nvm_tree_contains_path tmp tmp-alias/node || die 'the tree should contain a node reached through a symlink'
|
||||||
|
nvm_tree_contains_path tmp-alias tmp2/node && die 'a symlink should not contain a sibling tree'
|
||||||
|
|
||||||
|
nvm_tree_contains_path nonexistent NONEXISTENT/node && die 'missing directories should not be case folded'
|
||||||
|
|
||||||
cleanup
|
cleanup
|
||||||
|
|||||||
Reference in New Issue
Block a user