mirror of
https://github.com/neovim/neovim.git
synced 2026-04-18 13:30:42 +00:00
vim-patch:9.2.0326: runtime(tar): but with dotted path
Problem: runtime(tar): but with dotted path
Solution: Do not strip everything after the first dot
(Aaron Burrow)
tar#Extract was getting the extensionless basename by
stripping away everything starting with the leftmost
dot. So if a directory had a dot or the file had an
'extra' dot then the code did the wrong thing. For
example, if it was given:
/tmp/foo.bar/baz.tar.gz
Then it would treat /tmp/foo as the extensionless
basename, but it actually should have grabbed:
/tmp/foo.bar/baz
This patch fixes the issue by instead looking at the
rightmost dot(s).
This bug was discovered by ChatGPT 5.4. I wrote the
patch and tested vim.
closes: vim/vim#19930
4a1bcc67b4
Co-authored-by: Aaron Burrow <burrows@fastmail.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
" 2026 Feb 07 by Vim Project: make the path traversal detection more robust (#19341)
|
||||
" 2026 Apr 06 by Vim Project: fix bugs with lz4 support (#19925)
|
||||
" 2026 Apr 09 by Vim Project: fix bugs with zstd support (#19930)
|
||||
" 2026 Apr 09 by Vim Project: fix bug with dotted filename (#19930)
|
||||
"
|
||||
" Contains many ideas from Michael Toren's <tar.vim>
|
||||
"
|
||||
@@ -611,117 +612,120 @@ fun! tar#Extract()
|
||||
return
|
||||
endif
|
||||
|
||||
let tarball = expand("%")
|
||||
let tarbase = substitute(tarball,'\..*$','','')
|
||||
|
||||
let extractcmd= s:WinPath(g:tar_extractcmd)
|
||||
if filereadable(tarbase.".tar")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname))
|
||||
let tarball = expand("%")
|
||||
if !filereadable(tarball)
|
||||
let &report= repkeep
|
||||
return
|
||||
endif
|
||||
|
||||
if tarball =~# "\.tar$"
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ". fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tgz")
|
||||
elseif tarball =~# "\.tgz$"
|
||||
let extractcmd= substitute(extractcmd,"-","-z","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tgz {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.gz")
|
||||
elseif tarball =~# "\.tar\.gz$"
|
||||
let extractcmd= substitute(extractcmd,"-","-z","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.gz {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tbz")
|
||||
elseif tarball =~# "\.tbz$"
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tbz {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.bz2")
|
||||
elseif tarball =~# "\.tar\.bz2$"
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz2 {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.bz3")
|
||||
elseif tarball =~# "\.tar\.bz3$"
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz3 {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".txz")
|
||||
elseif tarball =~# "\.txz$"
|
||||
let extractcmd= substitute(extractcmd,"-","-J","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.txz {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.xz")
|
||||
elseif tarball =~# "\.tar\.xz$"
|
||||
let extractcmd= substitute(extractcmd,"-","-J","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.xz {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tzst")
|
||||
elseif tarball =~# "\.tzst$"
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd -","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tzst {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.zst")
|
||||
elseif tarball =~# "\.tar\.zst$"
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd -","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.zst {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tlz4")
|
||||
elseif tarball =~# "\.tlz4$"
|
||||
if has("linux")
|
||||
let extractcmd= substitute(extractcmd,"-","-I lz4 -","")
|
||||
endif
|
||||
call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tlz4 {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.lz4")
|
||||
elseif tarball =~# "\.tar\.lz4$"
|
||||
if has("linux")
|
||||
let extractcmd= substitute(extractcmd,"-","-I lz4 -","")
|
||||
endif
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.lz4 ".shellescape(fname))
|
||||
call system(extractcmd." ".shellescape(tarball)." ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.lz4 {fname}: failed!")
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarball} {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
@@ -266,3 +266,53 @@ func Test_extraction()
|
||||
bw!
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
func Test_extract_with_dotted_dir()
|
||||
call delete('X.txt')
|
||||
call writefile(['when they kiss they spit white noise'], 'X.txt')
|
||||
|
||||
let dirname = tempname()
|
||||
call mkdir(dirname, 'R')
|
||||
let dirname = dirname .. '/foo.bar'
|
||||
call mkdir(dirname, 'R')
|
||||
let tarpath = dirname .. '/Xarchive.tar.gz'
|
||||
call system('tar -czf ' .. tarpath .. ' X.txt')
|
||||
call assert_true(filereadable(tarpath))
|
||||
call assert_equal(0, v:shell_error)
|
||||
|
||||
call delete('X.txt')
|
||||
defer delete(tarpath)
|
||||
|
||||
execute 'e ' .. tarpath
|
||||
call assert_match('X.txt', getline(5))
|
||||
:5
|
||||
normal x
|
||||
call assert_true(filereadable('X.txt'))
|
||||
call assert_equal(['when they kiss they spit white noise'], readfile('X.txt'))
|
||||
call delete('X.txt')
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_extract_with_dotted_filename()
|
||||
call delete('X.txt')
|
||||
call writefile(['holiday inn'], 'X.txt')
|
||||
|
||||
let dirname = tempname()
|
||||
call mkdir(dirname, 'R')
|
||||
let tarpath = dirname .. '/Xarchive.foo.tar.gz'
|
||||
call system('tar -czf ' .. tarpath .. ' X.txt')
|
||||
call assert_true(filereadable(tarpath))
|
||||
call assert_equal(0, v:shell_error)
|
||||
|
||||
call delete('X.txt')
|
||||
defer delete(tarpath)
|
||||
|
||||
execute 'e ' .. tarpath
|
||||
call assert_match('X.txt', getline(5))
|
||||
:5
|
||||
normal x
|
||||
call assert_true(filereadable('X.txt'))
|
||||
call assert_equal(['holiday inn'], readfile('X.txt'))
|
||||
call delete('X.txt')
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
Reference in New Issue
Block a user