os: do not resolve symlinks in os.find_abs_path_of_executable/1 (fix #24759) (#24761)

This commit is contained in:
Davide Beatrici 2025-06-24 01:53:13 +02:00 committed by GitHub
parent 2da65219e2
commit 1c5a9e1be2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 71 additions and 31 deletions

View file

@ -1,47 +1,87 @@
import os import os
const tfolder = os.join_path(os.real_path(os.vtmp_dir()), 'filepath_tests')
const original_path = os.getenv('PATH')
fn testsuite_begin() {
eprintln('testsuite_begin, tfolder = ${tfolder}')
os.rmdir_all(tfolder) or {}
os.mkdir_all(tfolder) or { panic(err) }
os.chdir(tfolder) or { panic(err) }
}
fn testsuite_end() {
os.chdir(os.wd_at_startup) or {}
os.rmdir_all(tfolder) or {}
}
fn test_find_abs_path_of_executable() { fn test_find_abs_path_of_executable() {
tfolder := os.join_path(os.vtmp_dir(), 'filepath_tests') exefolder := os.join_path(tfolder, 'exe')
os.rmdir_all(tfolder) or {} os.mkdir(exefolder) or { panic(err) }
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder)!
defer {
os.rmdir_all(tfolder) or {}
}
original_path := os.getenv('PATH') mut myclang_file := os.join_path(exefolder, 'myclang')
original_wdir := os.getwd()
defer {
os.chdir(original_wdir) or {}
}
new_path := tfolder + os.path_delimiter + original_path
os.setenv('PATH', new_path, true)
mut myclang_file := 'myclang'
$if windows { $if windows {
myclang_file += '.bat' myclang_file += '.bat'
} }
os.chdir(tfolder)! mut mylink_file := os.join_path(tfolder, 'mylink')
$if windows {
mylink_file += '.bat'
}
os.write_file(myclang_file, 'echo hello')! os.write_file(myclang_file, 'echo hello')!
os.chmod(myclang_file, 0o0777)! os.chmod(myclang_file, 0o0777)!
dump(os.abs_path(myclang_file))
dump(os.real_path(myclang_file)) dump(os.real_path(myclang_file))
dump(os.is_executable(myclang_file)) dump(os.is_executable(myclang_file))
defer {
os.rm(myclang_file) or {} $if windows {
eprintln('Windows requires admin privileges in order to create symlinks, related tests will be faked.')
os.cp(myclang_file, mylink_file) or { panic(err) }
} $else {
os.symlink(myclang_file, mylink_file) or { panic(err) }
} }
fpath := os.find_abs_path_of_executable('myclang') or { dump(os.abs_path(mylink_file))
assert false dump(os.real_path(mylink_file))
return dump(os.is_executable(mylink_file))
prepend_to_original_path(exefolder)
assert find_and_check('myclang')? == myclang_file
assert find_and_check('mylink') == none
prepend_to_original_path('.')
assert find_and_check('mylink')? == mylink_file
assert find_and_check('myclang') == none
os.chdir(exefolder) or { panic(err) }
assert find_and_check('myclang')? == myclang_file
assert find_and_check('mylink') == none
prepend_to_original_path(tfolder)
assert find_and_check('mylink')? == mylink_file
assert find_and_check('myclang') == none
restore_original_path()
os.chdir(os.home_dir())! // Change to a *completely* different folder, just in case the original PATH contains `.`
assert find_and_check('myclang') == none
assert find_and_check('mylink') == none
} }
fn find_and_check(executable string) ?string {
fpath := os.find_abs_path_of_executable(executable) or { return none }
dump(fpath) dump(fpath)
assert os.is_abs_path(fpath)
return fpath
}
fn restore_original_path() {
os.setenv('PATH', original_path, true) os.setenv('PATH', original_path, true)
os.chdir(os.home_dir())! // change to a *completely* different folder, to avoid the original PATH containing `.`
if x := os.find_abs_path_of_executable('myclang') {
eprintln('> find_abs_path_of_executable should have failed, but instead it found: ${x}')
assert false
} }
fn prepend_to_original_path(to_prepend string) {
new_path := to_prepend + os.path_delimiter + original_path
os.setenv('PATH', new_path, true)
} }

View file

@ -598,7 +598,7 @@ pub fn find_abs_path_of_executable(exe_name string) !string {
for suffix in executable_suffixes { for suffix in executable_suffixes {
fexepath := exe_name + suffix fexepath := exe_name + suffix
if is_abs_path(fexepath) { if is_abs_path(fexepath) {
return real_path(fexepath) return fexepath
} }
mut res := '' mut res := ''
path := getenv('PATH') path := getenv('PATH')
@ -614,7 +614,7 @@ pub fn find_abs_path_of_executable(exe_name string) !string {
} }
} }
if res.len > 0 { if res.len > 0 {
return real_path(res) return abs_path(res)
} }
} }
return error_failed_to_find_executable() return error_failed_to_find_executable()