mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0325: runtime(tar): bug in zstd handling
Problem: patch 9.2.0325: runtime(tar): bug in zstd handling
Solution: use correct --zstd argument, separated from other arguments,
rework testing framework (Aaron Burrow).
The tar.vim plugin allows vim to read and manipulate zstd archives,
but it had a bug that caused extraction attempts to fail.
Specifically, if the archive has a .tar.zst or .tzst extension, then
the code was generating invalid extraction commands that looked like
this:
tar --zstdpxf foo.tar.zst foo
When they should be like this:
tar --zstd -pxf foo.tar.zst foo
This patch changes the flag manipulation logic so that --zstd isn't
glued to pxf.
The labor for this change was divided between ChatGPT 5.4 and me.
ChatGPT 5.4 identified the issue (from a code scan?), and I wrote
the patch and tested vim.
related: #19930
Signed-off-by: Aaron Burrow <burrows@fastmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
3e2012914e
commit
00285c035a
@@ -21,6 +21,7 @@
|
||||
" 2026 Feb 06 by Vim Project: consider 'nowrapscan' (#19333)
|
||||
" 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)
|
||||
"
|
||||
" Contains many ideas from Michael Toren's <tar.vim>
|
||||
"
|
||||
@@ -687,7 +688,7 @@ fun! tar#Extract()
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tzst")
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd","")
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd -","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tzst {fname}: failed!")
|
||||
@@ -696,7 +697,7 @@ fun! tar#Extract()
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tar.zst")
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd","")
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd -","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.zst {fname}: failed!")
|
||||
|
||||
+110
-48
@@ -148,56 +148,118 @@ def g:Test_tar_path_traversal_with_nowrapscan()
|
||||
bw!
|
||||
enddef
|
||||
|
||||
def g:Test_tar_lz4_extract()
|
||||
CheckExecutable lz4
|
||||
|
||||
delete('X.txt')
|
||||
delete('Xarchive.tar')
|
||||
delete('Xarchive.tar.lz4')
|
||||
call writefile(['hello'], 'X.txt')
|
||||
call system('tar -cf Xarchive.tar X.txt')
|
||||
def CreateTar(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar -C ' .. tempdir .. ' -cf ' .. outputdir .. '/' .. archivename .. ' X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
|
||||
call system('lz4 -z Xarchive.tar Xarchive.tar.lz4')
|
||||
assert_equal(0, v:shell_error)
|
||||
|
||||
delete('X.txt')
|
||||
delete('Xarchive.tar')
|
||||
defer delete('Xarchive.tar.lz4')
|
||||
|
||||
e Xarchive.tar.lz4
|
||||
assert_match('X.txt', getline(5))
|
||||
:5
|
||||
normal x
|
||||
assert_true(filereadable('X.txt'))
|
||||
assert_equal(['hello'], readfile('X.txt'))
|
||||
delete('X.txt')
|
||||
bw!
|
||||
enddef
|
||||
|
||||
def g:Test_tlz4_extract()
|
||||
CheckExecutable lz4
|
||||
|
||||
delete('X.txt')
|
||||
delete('Xarchive.tar')
|
||||
delete('Xarchive.tlz4')
|
||||
call writefile(['goodbye'], 'X.txt')
|
||||
call system('tar -cf Xarchive.tar X.txt')
|
||||
def CreateTgz(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar -C ' .. tempdir .. ' -czf ' .. outputdir .. '/' .. archivename .. ' X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
|
||||
call system('lz4 -z Xarchive.tar Xarchive.tlz4')
|
||||
assert_equal(0, v:shell_error)
|
||||
|
||||
delete('X.txt')
|
||||
delete('Xarchive.tar')
|
||||
defer delete('Xarchive.tlz4')
|
||||
|
||||
e Xarchive.tlz4
|
||||
assert_match('X.txt', getline(5))
|
||||
:5
|
||||
normal x
|
||||
assert_true(filereadable('X.txt'))
|
||||
assert_equal(['goodbye'], readfile('X.txt'))
|
||||
delete('X.txt')
|
||||
bw!
|
||||
enddef
|
||||
|
||||
def CreateTbz(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar -C ' .. tempdir .. ' -cjf ' .. outputdir .. '/' .. archivename .. ' X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
enddef
|
||||
|
||||
def CreateTxz(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar -C ' .. tempdir .. ' -cJf ' .. outputdir .. '/' .. archivename .. ' X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
enddef
|
||||
|
||||
def CreateTzst(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar --zstd -C ' .. tempdir .. ' -cf ' .. outputdir .. '/' .. archivename .. ' X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
enddef
|
||||
|
||||
def CreateTlz4(archivename: string, content: string, outputdir: string)
|
||||
var tempdir = tempname()
|
||||
mkdir(tempdir, 'R')
|
||||
call writefile([content], tempdir .. '/X.txt')
|
||||
assert_true(filereadable(tempdir .. '/X.txt'))
|
||||
call system('tar -C ' .. tempdir .. ' -cf ' .. tempdir .. '/Xarchive.tar X.txt')
|
||||
assert_equal(0, v:shell_error)
|
||||
assert_true(filereadable(tempdir .. '/Xarchive.tar'))
|
||||
call system('lz4 -z ' .. tempdir .. '/Xarchive.tar ' .. outputdir .. '/' .. archivename)
|
||||
assert_equal(0, v:shell_error)
|
||||
enddef
|
||||
|
||||
# XXX: Add test for .tar.bz3
|
||||
def g:Test_extraction()
|
||||
var control = [
|
||||
{create: CreateTar,
|
||||
archive: 'Xarchive.tar'},
|
||||
{create: CreateTgz,
|
||||
archive: 'Xarchive.tgz'},
|
||||
{create: CreateTgz,
|
||||
archive: 'Xarchive.tar.gz'},
|
||||
{create: CreateTbz,
|
||||
archive: 'Xarchive.tbz'},
|
||||
{create: CreateTbz,
|
||||
archive: 'Xarchive.tar.bz2'},
|
||||
{create: CreateTxz,
|
||||
archive: 'Xarchive.txz'},
|
||||
{create: CreateTxz,
|
||||
archive: 'Xarchive.tar.xz'},
|
||||
]
|
||||
|
||||
if executable('lz4') == 1
|
||||
control->add({
|
||||
create: CreateTlz4,
|
||||
archive: 'Xarchive.tar.lz4'
|
||||
})
|
||||
control->add({
|
||||
create: CreateTlz4,
|
||||
archive: 'Xarchive.tlz4'
|
||||
})
|
||||
endif
|
||||
if executable('zstd') == 1
|
||||
control->add({
|
||||
create: CreateTzst,
|
||||
archive: 'Xarchive.tar.zst'
|
||||
})
|
||||
control->add({
|
||||
create: CreateTzst,
|
||||
archive: 'Xarchive.tzst'
|
||||
})
|
||||
endif
|
||||
|
||||
for c in control
|
||||
var dir = tempname()
|
||||
mkdir(dir, 'R')
|
||||
call(c.create, [c.archive, 'hello', dir])
|
||||
|
||||
delete('X.txt')
|
||||
execute 'edit ' .. dir .. '/' .. c.archive
|
||||
assert_match('X.txt', getline(5), 'line 5 wrong in archive: ' .. c.archive)
|
||||
:5
|
||||
normal x
|
||||
assert_equal(0, v:shell_error, 'vshell error not 0')
|
||||
assert_true(filereadable('X.txt'), 'X.txt not readable for archive: ' .. c.archive)
|
||||
assert_equal(['hello'], readfile('X.txt'), 'X.txt wrong contents for archive: ' .. c.archive)
|
||||
delete('X.txt')
|
||||
delete(dir .. '/' .. c.archive)
|
||||
bw!
|
||||
endfor
|
||||
enddef
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
325,
|
||||
/**/
|
||||
324,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user