mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	patch 9.1.1552: [security]: path traversal issue in tar.vim
Problem:  [security]: path traversal issue in tar.vim
          (@ax)
Solution: warn the user for such things, drop leading /, don't
          forcefully overwrite files when writing temporary files,
          refactor autoload/tar.vim
tar.vim: drop leading / in path names
A tar archive containing files with leading `/` may cause confusions as
to where the content is extracted.  Let's make sure we drop the leading
`/` and use a relative path instead.
Also while at it, had to refactor it quite a bit and increase the
minimum supported Vim version to v9. Also add a test for some basic tar
functionality
closes: #17733
			
			
This commit is contained in:
		
							
								
								
									
										2
									
								
								Filelist
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Filelist
									
									
									
									
									
								
							| @@ -213,7 +213,9 @@ SRC_ALL =	\ | |||||||
| 		src/testdir/samples/*.txt \ | 		src/testdir/samples/*.txt \ | ||||||
| 		src/testdir/samples/*.vim \ | 		src/testdir/samples/*.vim \ | ||||||
| 		src/testdir/samples/evil.zip \ | 		src/testdir/samples/evil.zip \ | ||||||
|  | 		src/testdir/samples/evil.tar \ | ||||||
| 		src/testdir/samples/poc.zip \ | 		src/testdir/samples/poc.zip \ | ||||||
|  | 		src/testdir/samples/sample.tar \ | ||||||
| 		src/testdir/samples/test.zip \ | 		src/testdir/samples/test.zip \ | ||||||
| 		src/testdir/samples/test000 \ | 		src/testdir/samples/test000 \ | ||||||
| 		src/testdir/samples/test_undo.txt.undo \ | 		src/testdir/samples/test_undo.txt.undo \ | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
| "                               instead of shelling out to file(1) | "                               instead of shelling out to file(1) | ||||||
| "   2025 Apr 16 by Vim Project: decouple from netrw by adding s:WinPath() | "   2025 Apr 16 by Vim Project: decouple from netrw by adding s:WinPath() | ||||||
| "   2025 May 19 by Vim Project: restore working directory after read/write | "   2025 May 19 by Vim Project: restore working directory after read/write | ||||||
|  | "   2025 Jul 13 by Vim Project: warn with path traversal attacks | ||||||
| " | " | ||||||
| "	Contains many ideas from Michael Toren's <tar.vim> | "	Contains many ideas from Michael Toren's <tar.vim> | ||||||
| " | " | ||||||
| @@ -34,9 +35,9 @@ if &cp || exists("g:loaded_tar") | |||||||
|  finish |  finish | ||||||
| endif | endif | ||||||
| let g:loaded_tar= "v32b" | let g:loaded_tar= "v32b" | ||||||
| if v:version < 702 | if v:version < 900 | ||||||
|  echohl WarningMsg |  echohl WarningMsg | ||||||
|  echo "***warning*** this version of tar needs vim 7.2" |  echo "***warning*** this version of tar needs vim 9.0" | ||||||
|  echohl Normal |  echohl Normal | ||||||
|  finish |  finish | ||||||
| endif | endif | ||||||
| @@ -46,10 +47,10 @@ set cpo&vim | |||||||
| " --------------------------------------------------------------------- | " --------------------------------------------------------------------- | ||||||
| "  Default Settings: {{{1 | "  Default Settings: {{{1 | ||||||
| if !exists("g:tar_browseoptions") | if !exists("g:tar_browseoptions") | ||||||
|  let g:tar_browseoptions= "Ptf" |  let g:tar_browseoptions= "tf" | ||||||
| endif | endif | ||||||
| if !exists("g:tar_readoptions") | if !exists("g:tar_readoptions") | ||||||
|  let g:tar_readoptions= "pPxf" |  let g:tar_readoptions= "pxf" | ||||||
| endif | endif | ||||||
| if !exists("g:tar_cmd") | if !exists("g:tar_cmd") | ||||||
|  let g:tar_cmd= "tar" |  let g:tar_cmd= "tar" | ||||||
| @@ -58,6 +59,7 @@ if !exists("g:tar_writeoptions") | |||||||
|  let g:tar_writeoptions= "uf" |  let g:tar_writeoptions= "uf" | ||||||
| endif | endif | ||||||
| if !exists("g:tar_delfile") | if !exists("g:tar_delfile") | ||||||
|  |  " Note: not supported on BSD | ||||||
|  let g:tar_delfile="--delete -f" |  let g:tar_delfile="--delete -f" | ||||||
| endif | endif | ||||||
| if !exists("g:netrw_cygwin") | if !exists("g:netrw_cygwin") | ||||||
| @@ -106,10 +108,26 @@ if !exists("g:tar_shq") | |||||||
|  endif |  endif | ||||||
| endif | endif | ||||||
|  |  | ||||||
|  | let g:tar_secure=' -- ' | ||||||
|  | let g:tar_leading_pat='^\%([.]\{,2\}/\)\+' | ||||||
|  |  | ||||||
| " ---------------- | " ---------------- | ||||||
| "  Functions: {{{1 | "  Functions: {{{1 | ||||||
| " ---------------- | " ---------------- | ||||||
|  |  | ||||||
|  | " --------------------------------------------------------------------- | ||||||
|  | " s:Msg: {{{2 | ||||||
|  | fun! s:Msg(func, severity, msg) | ||||||
|  |   redraw! | ||||||
|  |   if a:severity =~? 'error' | ||||||
|  |     echohl Error  | ||||||
|  |   else | ||||||
|  |     echohl WarningMsg | ||||||
|  |   endif | ||||||
|  |   echo $"***{a:severity}*** ({a:func}) {a:msg}" | ||||||
|  |   echohl None | ||||||
|  | endfunc | ||||||
|  |  | ||||||
| " --------------------------------------------------------------------- | " --------------------------------------------------------------------- | ||||||
| " tar#Browse: {{{2 | " tar#Browse: {{{2 | ||||||
| fun! tar#Browse(tarfile) | fun! tar#Browse(tarfile) | ||||||
| @@ -118,16 +136,14 @@ fun! tar#Browse(tarfile) | |||||||
|  |  | ||||||
|   " sanity checks |   " sanity checks | ||||||
|   if !executable(g:tar_cmd) |   if !executable(g:tar_cmd) | ||||||
|    redraw! |    call s:Msg('tar#Browse', 'error', $"{g:tar_cmd} not available on your system") | ||||||
|    echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system' |  | ||||||
|    let &report= repkeep |    let &report= repkeep | ||||||
|    return |    return | ||||||
|   endif |   endif | ||||||
|   if !filereadable(a:tarfile) |   if !filereadable(a:tarfile) | ||||||
|    if a:tarfile !~# '^\a\+://' |    if a:tarfile !~# '^\a\+://' | ||||||
|     " if it's an url, don't complain, let url-handlers such as vim do its thing |     " if it's an url, don't complain, let url-handlers such as vim do its thing | ||||||
|     redraw! |     call s:Msg('tar#Browse', 'error', $"File not readable<{a:tarfile}>") | ||||||
|     echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None |  | ||||||
|    endif |    endif | ||||||
|    let &report= repkeep |    let &report= repkeep | ||||||
|    return |    return | ||||||
| @@ -203,28 +219,18 @@ fun! tar#Browse(tarfile) | |||||||
|    exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1) |    exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1) | ||||||
|   endif |   endif | ||||||
|   if v:shell_error != 0 |   if v:shell_error != 0 | ||||||
|    redraw! |    call s:Msg('tar#Browse', 'warning', $"please check your g:tar_browseoptions '<{g:tar_browseoptions}>'") | ||||||
|    echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">" |  | ||||||
|    return |    return | ||||||
|   endif |   endif | ||||||
|   " |  | ||||||
|   " The following should not be neccessary, since in case of errors the |   " remove tar: Removing leading '/' from member names | ||||||
|   " previous if statement should have caught the problem (because tar exited |   " Note: the message could be localized | ||||||
|   " with a non-zero exit code). |   if search('^tar: ') > 0 || search(g:tar_leading_pat) > 0 | ||||||
|   " if line("$") == curlast || ( line("$") == (curlast + 1) && |     call append(3,'" Note: Path Traversal Attack detected!') | ||||||
|   "       \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' && |     let b:leading_slash = 1 | ||||||
|   "       \ getline("$") =~  '\s' ) |     " remove the message output | ||||||
|   "  redraw! |     sil g/^tar: /d | ||||||
|   "  echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None |   endif | ||||||
|   "  keepj sil! %d |  | ||||||
|   "  let eikeep= &ei |  | ||||||
|   "  set ei=BufReadCmd,FileReadCmd |  | ||||||
|   "  exe "r ".fnameescape(a:tarfile) |  | ||||||
|   "  let &ei= eikeep |  | ||||||
|   "  keepj sil! 1d |  | ||||||
|   "   call Dret("tar#Browse : a:tarfile<".a:tarfile.">") |  | ||||||
|   "  return |  | ||||||
|   " endif |  | ||||||
|  |  | ||||||
|   " set up maps supported for tar |   " set up maps supported for tar | ||||||
|   setlocal noma nomod ro |   setlocal noma nomod ro | ||||||
| @@ -243,12 +249,7 @@ fun! s:TarBrowseSelect() | |||||||
|   let repkeep= &report |   let repkeep= &report | ||||||
|   set report=10 |   set report=10 | ||||||
|   let fname= getline(".") |   let fname= getline(".") | ||||||
|  |   let ls= get(b:, 'leading_slash', 0) | ||||||
|   if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-' |  | ||||||
|    redraw! |  | ||||||
|    echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"' |  | ||||||
|    return |  | ||||||
|   endif |  | ||||||
|  |  | ||||||
|   " sanity check |   " sanity check | ||||||
|   if fname =~ '^"' |   if fname =~ '^"' | ||||||
| @@ -270,7 +271,8 @@ fun! s:TarBrowseSelect() | |||||||
|    wincmd _ |    wincmd _ | ||||||
|   endif |   endif | ||||||
|   let s:tblfile_{winnr()}= curfile |   let s:tblfile_{winnr()}= curfile | ||||||
|   call tar#Read("tarfile:".tarfile.'::'.fname,1) |   let b:leading_slash= ls | ||||||
|  |   call tar#Read("tarfile:".tarfile.'::'.fname) | ||||||
|   filetype detect |   filetype detect | ||||||
|   set nomod |   set nomod | ||||||
|   exe 'com! -buffer -nargs=? -complete=file TarDiff	:call tar#Diff(<q-args>,"'.fnameescape(fname).'")' |   exe 'com! -buffer -nargs=? -complete=file TarDiff	:call tar#Diff(<q-args>,"'.fnameescape(fname).'")' | ||||||
| @@ -280,26 +282,18 @@ endfun | |||||||
|  |  | ||||||
| " --------------------------------------------------------------------- | " --------------------------------------------------------------------- | ||||||
| " tar#Read: {{{2 | " tar#Read: {{{2 | ||||||
| fun! tar#Read(fname,mode) | fun! tar#Read(fname) | ||||||
|   let repkeep= &report |   let repkeep= &report | ||||||
|   set report=10 |   set report=10 | ||||||
|   let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','') |   let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','') | ||||||
|   let fname   = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','') |   let fname   = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','') | ||||||
|   " be careful not to execute special crafted files |   " be careful not to execute special crafted files | ||||||
|   let escape_file = fname->fnameescape() |   let escape_file = fname->substitute(g:tar_leading_pat, '', '')->fnameescape() | ||||||
|  |  | ||||||
|   " changing the directory to the temporary earlier to allow tar to extract the file with permissions intact |  | ||||||
|   if !exists("*mkdir") |  | ||||||
|    redraw! |  | ||||||
|    echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None |  | ||||||
|    let &report= repkeep |  | ||||||
|    return |  | ||||||
|   endif |  | ||||||
|  |  | ||||||
|   let curdir= getcwd() |   let curdir= getcwd() | ||||||
|  |   let b:curdir= curdir | ||||||
|   let tmpdir= tempname() |   let tmpdir= tempname() | ||||||
|   let b:curdir= tmpdir |   let b:tmpdir= tmpdir | ||||||
|   let b:tmpdir= curdir |  | ||||||
|   if tmpdir =~ '\.' |   if tmpdir =~ '\.' | ||||||
|    let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') |    let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') | ||||||
|   endif |   endif | ||||||
| @@ -309,8 +303,7 @@ fun! tar#Read(fname,mode) | |||||||
|   try |   try | ||||||
|    exe "lcd ".fnameescape(tmpdir) |    exe "lcd ".fnameescape(tmpdir) | ||||||
|   catch /^Vim\%((\a\+)\)\=:E344/ |   catch /^Vim\%((\a\+)\)\=:E344/ | ||||||
|    redraw! |    call s:Msg('tar#Read', 'error', "cannot lcd to temporary directory") | ||||||
|    echohl Error | echo "***error*** (tar#Write) cannot lcd to temporary directory" | Echohl None |  | ||||||
|    let &report= repkeep |    let &report= repkeep | ||||||
|    return |    return | ||||||
|   endtry |   endtry | ||||||
| @@ -333,7 +326,7 @@ fun! tar#Read(fname,mode) | |||||||
|   elseif  fname =~ '\.bz3$' && executable("bz3cat") |   elseif  fname =~ '\.bz3$' && executable("bz3cat") | ||||||
|    let decmp= "|bz3cat" |    let decmp= "|bz3cat" | ||||||
|    let doro = 1 |    let doro = 1 | ||||||
|   elseif      fname =~ '\.t\=gz$'  && executable("zcat") |   elseif  fname =~ '\.t\=gz$'  && executable("zcat") | ||||||
|    let decmp= "|zcat" |    let decmp= "|zcat" | ||||||
|    let doro = 1 |    let doro = 1 | ||||||
|   elseif  fname =~ '\.lzma$' && executable("lzcat") |   elseif  fname =~ '\.lzma$' && executable("lzcat") | ||||||
| @@ -356,68 +349,66 @@ fun! tar#Read(fname,mode) | |||||||
|    endif |    endif | ||||||
|   endif |   endif | ||||||
|  |  | ||||||
|   if exists("g:tar_secure") |  | ||||||
|    let tar_secure= " -- " |  | ||||||
|   else |  | ||||||
|    let tar_secure= " " |  | ||||||
|   endif |  | ||||||
|  |  | ||||||
|   if tarfile =~# '\.bz2$' |   if tarfile =~# '\.bz2$' | ||||||
|    exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\.bz3$' |   elseif tarfile =~# '\.bz3$' | ||||||
|    exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\.\(gz\)$' |   elseif tarfile =~# '\.\(gz\)$' | ||||||
|    exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)' |   elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)' | ||||||
|    let filekind= s:Header(tarfile) |    let filekind= s:Header(tarfile) | ||||||
|    if filekind =~? "bzip2" |    if filekind =~? "bzip2" | ||||||
|     exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |     exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|     exe "read ".escape_file |     exe "read ".escape_file | ||||||
|    elseif filekind =~ "bzip3" |    elseif filekind =~ "bzip3" | ||||||
|     exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |     exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|     exe "read ".escape_file |     exe "read ".escape_file | ||||||
|    elseif filekind =~? "xz" |    elseif filekind =~? "xz" | ||||||
|     exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |     exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|     exe "read ".escape_file |     exe "read ".escape_file | ||||||
|    elseif filekind =~? "zstd" |    elseif filekind =~? "zstd" | ||||||
|     exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |     exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|     exe "read ".escape_file |     exe "read ".escape_file | ||||||
|    elseif filekind =~? "gzip" |    elseif filekind =~? "gzip" | ||||||
|     exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |     exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|     exe "read ".escape_file |     exe "read ".escape_file | ||||||
|    endif |    endif | ||||||
|  |  | ||||||
|   elseif tarfile =~# '\.lrp$' |   elseif tarfile =~# '\.lrp$' | ||||||
|    exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\.lzma$' |   elseif tarfile =~# '\.lzma$' | ||||||
|    exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\.\(xz\|txz\)$' |   elseif tarfile =~# '\.\(xz\|txz\)$' | ||||||
|    exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   elseif tarfile =~# '\.\(lz4\|tlz4\)$' |   elseif tarfile =~# '\.\(lz4\|tlz4\)$' | ||||||
|    exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp |    exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   else |   else | ||||||
|    if tarfile =~ '^\s*-' |    if tarfile =~ '^\s*-' | ||||||
|     " A file name starting with a dash is taken as an option.  Prepend ./ to avoid that. |     " A file name starting with a dash is taken as an option.  Prepend ./ to avoid that. | ||||||
|     let tarfile = substitute(tarfile, '-', './-', '') |     let tarfile = substitute(tarfile, '-', './-', '') | ||||||
|    endif |    endif | ||||||
|    exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp |    exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".g:tar_secure.shellescape(fname,1).decmp | ||||||
|    exe "read ".escape_file |    exe "read ".escape_file | ||||||
|   endif |   endif | ||||||
|  |   if get(b:, 'leading_slash', 0) | ||||||
|  |     sil g/^tar: /d | ||||||
|  |   endif | ||||||
|  |  | ||||||
|    redraw! |    redraw! | ||||||
|  |  | ||||||
| if v:shell_error != 0 |   if v:shell_error != 0 | ||||||
|    lcd .. |    lcd .. | ||||||
|    call s:Rmdir("_ZIPVIM_") |    call s:Rmdir("_ZIPVIM_") | ||||||
|    exe "lcd ".fnameescape(curdir) |    exe "lcd ".fnameescape(curdir) | ||||||
|    echohl Error | echo "***error*** (tar#Read) sorry, unable to open or extract ".tarfile." with ".fname | echohl None |    call s:Msg('tar#Read', 'error', $"sorry, unable to open or extract {tarfile} with {fname}") | ||||||
|   endif |   endif | ||||||
|  |  | ||||||
|   if doro |   if doro | ||||||
| @@ -426,7 +417,6 @@ if v:shell_error != 0 | |||||||
|   endif |   endif | ||||||
|  |  | ||||||
|   let b:tarfile= a:fname |   let b:tarfile= a:fname | ||||||
|   exe "file tarfile::".fnameescape(fname) |  | ||||||
|  |  | ||||||
|   " cleanup |   " cleanup | ||||||
|   keepj sil! 0d |   keepj sil! 0d | ||||||
| @@ -434,7 +424,7 @@ if v:shell_error != 0 | |||||||
|  |  | ||||||
|   let &report= repkeep |   let &report= repkeep | ||||||
|   exe "lcd ".fnameescape(curdir) |   exe "lcd ".fnameescape(curdir) | ||||||
|   silent exe "file tarfile::".escape_file |   silent exe "file tarfile::". fname->fnameescape() | ||||||
| endfun | endfun | ||||||
|  |  | ||||||
| " --------------------------------------------------------------------- | " --------------------------------------------------------------------- | ||||||
| @@ -446,22 +436,35 @@ fun! tar#Write(fname) | |||||||
|   let curdir= b:curdir |   let curdir= b:curdir | ||||||
|   let tmpdir= b:tmpdir |   let tmpdir= b:tmpdir | ||||||
|  |  | ||||||
|   if !exists("g:tar_secure") && a:fname =~ '^\s*-\|\s\+-' |  | ||||||
|    redraw! |  | ||||||
|    echohl WarningMsg | echo '***warning*** (tar#Write) rejecting tarfile member<'.a:fname.'> because of embedded "-"' |  | ||||||
|    return |  | ||||||
|   endif |  | ||||||
|  |  | ||||||
|   " sanity checks |   " sanity checks | ||||||
|   if !executable(g:tar_cmd) |   if !executable(g:tar_cmd) | ||||||
|    redraw! |    redraw! | ||||||
|    let &report= repkeep |    let &report= repkeep | ||||||
|    return |    return | ||||||
|   endif |   endif | ||||||
|  |  | ||||||
|   let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','') |   let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','') | ||||||
|   let fname   = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','') |   let fname   = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','') | ||||||
|  |  | ||||||
|  |   if get(b:, 'leading_slash', 0) | ||||||
|  |    call s:Msg('tar#Write', 'error', $"sorry, not attempting to update {tarfile} with {fname}") | ||||||
|  |    let &report= repkeep | ||||||
|  |    return | ||||||
|  |   endif | ||||||
|  |  | ||||||
|  |   if !isdirectory(fnameescape(tmpdir)) | ||||||
|  |     call mkdir(fnameescape(tmpdir), 'p') | ||||||
|  |   endif | ||||||
|  |   exe $"lcd {fnameescape(tmpdir)}" | ||||||
|  |   if isdirectory("_ZIPVIM_") | ||||||
|  |     call s:Rmdir("_ZIPVIM_") | ||||||
|  |   endif | ||||||
|  |   call mkdir("_ZIPVIM_") | ||||||
|  |   lcd _ZIPVIM_ | ||||||
|  |   let dir = fnamemodify(fname, ':p:h') | ||||||
|  |   if dir !~# '_ZIPVIM_$' | ||||||
|  |     call mkdir(dir) | ||||||
|  |   endif | ||||||
|  |  | ||||||
|   " handle compressed archives |   " handle compressed archives | ||||||
|   if tarfile =~# '\.bz2' |   if tarfile =~# '\.bz2' | ||||||
|    call system("bzip2 -d -- ".shellescape(tarfile,0)) |    call system("bzip2 -d -- ".shellescape(tarfile,0)) | ||||||
| @@ -500,8 +503,7 @@ fun! tar#Write(fname) | |||||||
|   " Note: no support for name.tar.tbz/.txz/.tgz/.tlz4/.tzst |   " Note: no support for name.tar.tbz/.txz/.tgz/.tlz4/.tzst | ||||||
|  |  | ||||||
|   if v:shell_error != 0 |   if v:shell_error != 0 | ||||||
|    redraw! |    call s:Msg('tar#Write', 'error', $"sorry, unable to update {tarfile} with {fname}") | ||||||
|    echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None |  | ||||||
|   else |   else | ||||||
|  |  | ||||||
|    if fname =~ '/' |    if fname =~ '/' | ||||||
| @@ -519,28 +521,22 @@ fun! tar#Write(fname) | |||||||
|     let tarfile = substitute(tarfile, '-', './-', '') |     let tarfile = substitute(tarfile, '-', './-', '') | ||||||
|    endif |    endif | ||||||
|  |  | ||||||
|    if exists("g:tar_secure") |    " don't overwrite a file forcefully | ||||||
|     let tar_secure= " -- " |    exe "w ".fnameescape(fname) | ||||||
|    else |  | ||||||
|     let tar_secure= " " |  | ||||||
|    endif |  | ||||||
|    exe "w! ".fnameescape(fname) |  | ||||||
|    if has("win32unix") && executable("cygpath") |    if has("win32unix") && executable("cygpath") | ||||||
|     let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e') |     let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e') | ||||||
|    endif |    endif | ||||||
|  |  | ||||||
|    " delete old file from tarfile |    " delete old file from tarfile | ||||||
|    call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0)) |    " Note: BSD tar does not support --delete flag | ||||||
|  |    call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     redraw! |     call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)} --delete not supported?") | ||||||
|     echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None |  | ||||||
|    else |    else | ||||||
|  |  | ||||||
|     " update tarfile with new file |     " update tarfile with new file | ||||||
|     call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0)) |     call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0)) | ||||||
|     if v:shell_error != 0 |     if v:shell_error != 0 | ||||||
|      redraw! |      call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)}") | ||||||
|      echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None |  | ||||||
|     elseif exists("compress") |     elseif exists("compress") | ||||||
|      call system(compress) |      call system(compress) | ||||||
|      if exists("tgz") |      if exists("tgz") | ||||||
| @@ -581,6 +577,7 @@ fun! tar#Diff(userfname,fname) | |||||||
|   if a:userfname != "" |   if a:userfname != "" | ||||||
|    let fname= a:userfname |    let fname= a:userfname | ||||||
|   endif |   endif | ||||||
|  |   exe "lcd ".fnameescape(b:tmpdir). '/_ZIPVIM_' | ||||||
|   if filereadable(fname) |   if filereadable(fname) | ||||||
|    " sets current file (from tarball) for diff'ing |    " sets current file (from tarball) for diff'ing | ||||||
|    " splits window vertically |    " splits window vertically | ||||||
| @@ -604,12 +601,6 @@ fun! tar#Extract() | |||||||
|   set report=10 |   set report=10 | ||||||
|   let fname= getline(".") |   let fname= getline(".") | ||||||
|  |  | ||||||
|   if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-' |  | ||||||
|    redraw! |  | ||||||
|    echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"' |  | ||||||
|    return |  | ||||||
|   endif |  | ||||||
|  |  | ||||||
|   " sanity check |   " sanity check | ||||||
|   if fname =~ '^"' |   if fname =~ '^"' | ||||||
|    let &report= repkeep |    let &report= repkeep | ||||||
| @@ -623,16 +614,16 @@ fun! tar#Extract() | |||||||
|   if filereadable(tarbase.".tar") |   if filereadable(tarbase.".tar") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ". fname | ||||||
|    endif |    endif | ||||||
|  |  | ||||||
|   elseif filereadable(tarbase.".tgz") |   elseif filereadable(tarbase.".tgz") | ||||||
|    let extractcmd= substitute(extractcmd,"-","-z","") |    let extractcmd= substitute(extractcmd,"-","-z","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tgz ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tgz {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -641,7 +632,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-z","") |    let extractcmd= substitute(extractcmd,"-","-z","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.gz ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.gz {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -650,7 +641,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-j","") |    let extractcmd= substitute(extractcmd,"-","-j","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tbz ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tbz {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -659,7 +650,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-j","") |    let extractcmd= substitute(extractcmd,"-","-j","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz2 ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz2 {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -668,7 +659,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-j","") |    let extractcmd= substitute(extractcmd,"-","-j","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz3 ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz3 {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -677,7 +668,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-J","") |    let extractcmd= substitute(extractcmd,"-","-J","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".txz ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.txz {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -686,7 +677,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-J","") |    let extractcmd= substitute(extractcmd,"-","-J","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.xz ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.xz {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -695,7 +686,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","--zstd","") |    let extractcmd= substitute(extractcmd,"-","--zstd","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tzst ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tzst {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -704,7 +695,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","--zstd","") |    let extractcmd= substitute(extractcmd,"-","--zstd","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.zst ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.zst {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -713,7 +704,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-I lz4","") |    let extractcmd= substitute(extractcmd,"-","-I lz4","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tlz4 ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tlz4 {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -722,7 +713,7 @@ fun! tar#Extract() | |||||||
|    let extractcmd= substitute(extractcmd,"-","-I lz4","") |    let extractcmd= substitute(extractcmd,"-","-I lz4","") | ||||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname)) |    call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname)) | ||||||
|    if v:shell_error != 0 |    if v:shell_error != 0 | ||||||
|     echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.lz4 ".fname.": failed!" | echohl NONE |     call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.lz4 {fname}: failed!") | ||||||
|    else |    else | ||||||
|     echo "***note*** successfully extracted ".fname |     echo "***note*** successfully extracted ".fname | ||||||
|    endif |    endif | ||||||
| @@ -735,15 +726,7 @@ endfun | |||||||
| " --------------------------------------------------------------------- | " --------------------------------------------------------------------- | ||||||
| " s:Rmdir: {{{2 | " s:Rmdir: {{{2 | ||||||
| fun! s:Rmdir(fname) | fun! s:Rmdir(fname) | ||||||
|   if has("unix") |   call delete(a:fname, 'rf') | ||||||
|    call system("/bin/rm -rf -- ".shellescape(a:fname,0)) |  | ||||||
|   elseif has("win32") || has("win95") || has("win64") || has("win16") |  | ||||||
|    if &shell =~? "sh$" |  | ||||||
|     call system("/bin/rm -rf -- ".shellescape(a:fname,0)) |  | ||||||
|    else |  | ||||||
|     call system("del /S ".shellescape(a:fname,0)) |  | ||||||
|    endif |  | ||||||
|   endif |  | ||||||
| endfun | endfun | ||||||
|  |  | ||||||
| " s:FileHeader: {{{2 | " s:FileHeader: {{{2 | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
| *pi_tar.txt*	For Vim version 9.1.  Last change: 2025 Mar 16 | *pi_tar.txt*	For Vim version 9.1.  Last change: 2025 Jul 15 | ||||||
|  |  | ||||||
| 		       +====================+ | 		       +====================+ | ||||||
| 		       | Tar File Interface | | 		       | Tar File Interface | | ||||||
| 		       +====================+ | 		       +====================+ | ||||||
|  |  | ||||||
| Author:  Charles E. Campbell  <NcampObell@SdrPchip.AorgM-NOSPAM> | Original Author:  Charles E. Campbell | ||||||
| 	  (remove NOSPAM from Campbell's email first) |  | ||||||
| Copyright 2005-2017:					*tar-copyright* | Copyright 2005-2017:					*tar-copyright* | ||||||
| 	The VIM LICENSE (see |copyright|) applies to the files in this | 	The VIM LICENSE (see |copyright|) applies to the files in this | ||||||
| 	package, including tarPlugin.vim, tar.vim, and pi_tar.txt.  Like | 	package, including tarPlugin.vim, tar.vim, and pi_tar.txt.  Like | ||||||
| @@ -61,7 +60,7 @@ Copyright 2005-2017:					*tar-copyright* | |||||||
| 	the file mentioned in the tarball.  If the current directory is not | 	the file mentioned in the tarball.  If the current directory is not | ||||||
| 	correct for that path, :TarDiff will fail to find the associated file. | 	correct for that path, :TarDiff will fail to find the associated file. | ||||||
|  |  | ||||||
| 	If the [filename] is given, that that filename (and path) will be used | 	If the [filename] is given, that filename (and path) will be used | ||||||
| 	to specify the associated file. | 	to specify the associated file. | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -95,24 +94,25 @@ Copyright 2005-2017:					*tar-copyright* | |||||||
|    *g:tar_readoptions*	  "OPxf"  used to extract a file from a tarball |    *g:tar_readoptions*	  "OPxf"  used to extract a file from a tarball | ||||||
|    *g:tar_cmd*		  "tar"   the name of the tar program |    *g:tar_cmd*		  "tar"   the name of the tar program | ||||||
|    *g:tar_nomax*	    0	  if true, file window will not be maximized |    *g:tar_nomax*	    0	  if true, file window will not be maximized | ||||||
|    *g:tar_secure*	  undef   if exists: |  | ||||||
| 					"--"s will be used to prevent unwanted |  | ||||||
| 					option expansion in tar commands. |  | ||||||
| 					Please be sure that your tar command |  | ||||||
| 					accepts "--"; Posix compliant tar |  | ||||||
| 					utilities do accept them. |  | ||||||
| 				  if not exists: |  | ||||||
| 					The tar plugin will reject any tar |  | ||||||
| 					files or member files that begin with |  | ||||||
| 					"-" |  | ||||||
| 				  Not all tar's support the "--" which is why |  | ||||||
| 				  it isn't default. |  | ||||||
|    *g:tar_writeoptions*	  "uf"    used to update/replace a file |    *g:tar_writeoptions*	  "uf"    used to update/replace a file | ||||||
|  |  | ||||||
|  |  | ||||||
| ============================================================================== | ============================================================================== | ||||||
| 4. History						*tar-history* | 4. History						*tar-history* | ||||||
|  |  | ||||||
|  | 	unreleased: | ||||||
|  | 		Jul 13, 2025	* drop leading / | ||||||
|  | 		May 19, 2025	* restore working directory after read/write | ||||||
|  | 		Apr 16, 2025	* decouple from netrw by adding s:WinPath() | ||||||
|  | 				instead of shelling out to file(1) | ||||||
|  | 		Mar 02, 2025	* determine the compression using readblob() | ||||||
|  | 		Mar 02, 2025	* escape the filename before using :read | ||||||
|  | 		Mar 01, 2025	* fix syntax error in tar#Read() | ||||||
|  | 		Feb 28, 2025	* add support for bzip3 (#16755) | ||||||
|  | 		Feb 06, 2025	* add support for lz4 (#16591) | ||||||
|  | 		Nov 11, 2024	* support permissions (#7379) | ||||||
|  | 		Feb 19, 2024	* announce adoption | ||||||
|  | 		Jan 08, 2024	* fix a few problems (#138331, #12637, #8109) | ||||||
| 	v31	Apr 02, 2017	* (klartext) reported that browsing encrypted | 	v31	Apr 02, 2017	* (klartext) reported that browsing encrypted | ||||||
| 				  files in a zip archive created unencrypted | 				  files in a zip archive created unencrypted | ||||||
| 				  swap files.  I am applying a similar fix | 				  swap files.  I am applying a similar fix | ||||||
|   | |||||||
| @@ -7857,7 +7857,6 @@ g:tar_copycmd	pi_tar.txt	/*g:tar_copycmd* | |||||||
| g:tar_extractcmd	pi_tar.txt	/*g:tar_extractcmd* | g:tar_extractcmd	pi_tar.txt	/*g:tar_extractcmd* | ||||||
| g:tar_nomax	pi_tar.txt	/*g:tar_nomax* | g:tar_nomax	pi_tar.txt	/*g:tar_nomax* | ||||||
| g:tar_readoptions	pi_tar.txt	/*g:tar_readoptions* | g:tar_readoptions	pi_tar.txt	/*g:tar_readoptions* | ||||||
| g:tar_secure	pi_tar.txt	/*g:tar_secure* |  | ||||||
| g:tar_writeoptions	pi_tar.txt	/*g:tar_writeoptions* | g:tar_writeoptions	pi_tar.txt	/*g:tar_writeoptions* | ||||||
| g:termdebug_config	terminal.txt	/*g:termdebug_config* | g:termdebug_config	terminal.txt	/*g:termdebug_config* | ||||||
| g:termdebugger	terminal.txt	/*g:termdebugger* | g:termdebugger	terminal.txt	/*g:termdebugger* | ||||||
|   | |||||||
| @@ -23,14 +23,14 @@ set cpo&vim | |||||||
| "  Public Interface: {{{1 | "  Public Interface: {{{1 | ||||||
| augroup tar | augroup tar | ||||||
|   au! |   au! | ||||||
|   au BufReadCmd   tarfile::*	call tar#Read(expand("<amatch>"), 1) |   au BufReadCmd   tarfile::*	call tar#Read(expand("<amatch>")) | ||||||
|   au FileReadCmd  tarfile::*	call tar#Read(expand("<amatch>"), 0) |   au FileReadCmd  tarfile::*	call tar#Read(expand("<amatch>")) | ||||||
|   au BufWriteCmd  tarfile::*	call tar#Write(expand("<amatch>")) |   au BufWriteCmd  tarfile::*	call tar#Write(expand("<amatch>")) | ||||||
|   au FileWriteCmd tarfile::*	call tar#Write(expand("<amatch>")) |   au FileWriteCmd tarfile::*	call tar#Write(expand("<amatch>")) | ||||||
|  |  | ||||||
|   if has("unix") |   if has("unix") | ||||||
|    au BufReadCmd   tarfile::*/*	call tar#Read(expand("<amatch>"), 1) |    au BufReadCmd   tarfile::*/*	call tar#Read(expand("<amatch>")) | ||||||
|    au FileReadCmd  tarfile::*/*	call tar#Read(expand("<amatch>"), 0) |    au FileReadCmd  tarfile::*/*	call tar#Read(expand("<amatch>")) | ||||||
|    au BufWriteCmd  tarfile::*/*	call tar#Write(expand("<amatch>")) |    au BufWriteCmd  tarfile::*/*	call tar#Write(expand("<amatch>")) | ||||||
|    au FileWriteCmd tarfile::*/*	call tar#Write(expand("<amatch>")) |    au FileWriteCmd tarfile::*/*	call tar#Write(expand("<amatch>")) | ||||||
|   endif |   endif | ||||||
|   | |||||||
							
								
								
									
										162
									
								
								src/po/vim.pot
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								src/po/vim.pot
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PACKAGE VERSION\n" | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: \n" | "Report-Msgid-Bugs-To: \n" | ||||||
| "POT-Creation-Date: 2025-07-15 21:42+0200\n" | "POT-Creation-Date: 2025-07-15 21:50+0200\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
| @@ -4257,327 +4257,327 @@ msgstr "" | |||||||
| msgid "%s (%s, compiled %s)" | msgid "%s (%s, compiled %s)" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4036 | #: ../version.c:4038 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows ARM64 GUI/console version" | "MS-Windows ARM64 GUI/console version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4038 | #: ../version.c:4040 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows 64-bit GUI/console version" | "MS-Windows 64-bit GUI/console version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4041 | #: ../version.c:4043 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows 32-bit GUI/console version" | "MS-Windows 32-bit GUI/console version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4046 | #: ../version.c:4048 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows ARM64 GUI version" | "MS-Windows ARM64 GUI version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4048 | #: ../version.c:4050 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows 64-bit GUI version" | "MS-Windows 64-bit GUI version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4051 | #: ../version.c:4053 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows 32-bit GUI version" | "MS-Windows 32-bit GUI version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4055 | #: ../version.c:4057 | ||||||
| msgid " with OLE support" | msgid " with OLE support" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4060 |  | ||||||
| msgid "" |  | ||||||
| "\n" |  | ||||||
| "MS-Windows ARM64 console version" |  | ||||||
| msgstr "" |  | ||||||
| 
 |  | ||||||
| #: ../version.c:4062 | #: ../version.c:4062 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
|  | "MS-Windows ARM64 console version" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | #: ../version.c:4064 | ||||||
|  | msgid "" | ||||||
|  | "\n" | ||||||
| "MS-Windows 64-bit console version" | "MS-Windows 64-bit console version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4065 | #: ../version.c:4067 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "MS-Windows 32-bit console version" | "MS-Windows 32-bit console version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4071 | #: ../version.c:4073 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "macOS version" | "macOS version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4073 | #: ../version.c:4075 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "macOS version w/o darwin feat." | "macOS version w/o darwin feat." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4083 | #: ../version.c:4085 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "OpenVMS version" | "OpenVMS version" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4098 | #: ../version.c:4100 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "Included patches: " | "Included patches: " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4123 | #: ../version.c:4125 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "Extra patches: " | "Extra patches: " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4135 ../version.c:4446 | #: ../version.c:4137 ../version.c:4448 | ||||||
| msgid "Modified by " | msgid "Modified by " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4142 | #: ../version.c:4144 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "Compiled " | "Compiled " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4145 | #: ../version.c:4147 | ||||||
| msgid "by " | msgid "by " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4157 |  | ||||||
| msgid "" |  | ||||||
| "\n" |  | ||||||
| "Huge version " |  | ||||||
| msgstr "" |  | ||||||
| 
 |  | ||||||
| #: ../version.c:4159 | #: ../version.c:4159 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "Normal version " | "Huge version " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4161 | #: ../version.c:4161 | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
|  | "Normal version " | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | #: ../version.c:4163 | ||||||
|  | msgid "" | ||||||
|  | "\n" | ||||||
| "Tiny version " | "Tiny version " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4164 | #: ../version.c:4166 | ||||||
| msgid "without GUI." | msgid "without GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4167 | #: ../version.c:4169 | ||||||
| msgid "with GTK3 GUI." | msgid "with GTK3 GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4169 | #: ../version.c:4171 | ||||||
| msgid "with GTK2-GNOME GUI." | msgid "with GTK2-GNOME GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4171 | #: ../version.c:4173 | ||||||
| msgid "with GTK2 GUI." | msgid "with GTK2 GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4174 | #: ../version.c:4176 | ||||||
| msgid "with X11-Motif GUI." | msgid "with X11-Motif GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4176 | #: ../version.c:4178 | ||||||
| msgid "with Haiku GUI." | msgid "with Haiku GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4178 | #: ../version.c:4180 | ||||||
| msgid "with Photon GUI." | msgid "with Photon GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4180 | #: ../version.c:4182 | ||||||
| msgid "with GUI." | msgid "with GUI." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4182 | #: ../version.c:4184 | ||||||
| msgid "  Features included (+) or not (-):\n" | msgid "  Features included (+) or not (-):\n" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4189 | #: ../version.c:4191 | ||||||
| msgid "   system vimrc file: \"" | msgid "   system vimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4194 | #: ../version.c:4196 | ||||||
| msgid "     user vimrc file: \"" | msgid "     user vimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4199 | #: ../version.c:4201 | ||||||
| msgid " 2nd user vimrc file: \"" | msgid " 2nd user vimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4204 ../version.c:4211 ../version.c:4215 | #: ../version.c:4206 ../version.c:4213 ../version.c:4217 | ||||||
| msgid " 3rd user vimrc file: \"" | msgid " 3rd user vimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4207 | #: ../version.c:4209 | ||||||
| msgid " 4th user vimrc file: \"" | msgid " 4th user vimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4220 | #: ../version.c:4222 | ||||||
| msgid "      user exrc file: \"" | msgid "      user exrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4225 | #: ../version.c:4227 | ||||||
| msgid "  2nd user exrc file: \"" | msgid "  2nd user exrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4231 | #: ../version.c:4233 | ||||||
| msgid "  system gvimrc file: \"" | msgid "  system gvimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4235 | #: ../version.c:4237 | ||||||
| msgid "    user gvimrc file: \"" | msgid "    user gvimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4239 | #: ../version.c:4241 | ||||||
| msgid "2nd user gvimrc file: \"" | msgid "2nd user gvimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4244 | #: ../version.c:4246 | ||||||
| msgid "3rd user gvimrc file: \"" | msgid "3rd user gvimrc file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4249 | #: ../version.c:4251 | ||||||
| msgid "       defaults file: \"" | msgid "       defaults file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4254 | #: ../version.c:4256 | ||||||
| msgid "    system menu file: \"" | msgid "    system menu file: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4262 | #: ../version.c:4264 | ||||||
| msgid "  fall-back for $VIM: \"" | msgid "  fall-back for $VIM: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4268 | #: ../version.c:4270 | ||||||
| msgid " f-b for $VIMRUNTIME: \"" | msgid " f-b for $VIMRUNTIME: \"" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4272 | #: ../version.c:4274 | ||||||
| msgid "Compilation: " | msgid "Compilation: " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4278 | #: ../version.c:4280 | ||||||
| msgid "Compiler: " | msgid "Compiler: " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4283 | #: ../version.c:4285 | ||||||
| msgid "Linking: " | msgid "Linking: " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4288 | #: ../version.c:4290 | ||||||
| msgid "  DEBUG BUILD" | msgid "  DEBUG BUILD" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4324 | #: ../version.c:4326 | ||||||
| msgid "VIM - Vi IMproved" | msgid "VIM - Vi IMproved" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4326 | #: ../version.c:4328 | ||||||
| msgid "version " | msgid "version " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4327 | #: ../version.c:4329 | ||||||
| msgid "by Bram Moolenaar et al." | msgid "by Bram Moolenaar et al." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4331 | #: ../version.c:4333 | ||||||
| msgid "Vim is open source and freely distributable" | msgid "Vim is open source and freely distributable" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4333 | #: ../version.c:4335 | ||||||
| msgid "Help poor children in Uganda!" | msgid "Help poor children in Uganda!" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4334 | #: ../version.c:4336 | ||||||
| msgid "type  :help iccf<Enter>       for information " | msgid "type  :help iccf<Enter>       for information " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4336 | #: ../version.c:4338 | ||||||
| msgid "type  :q<Enter>               to exit         " | msgid "type  :q<Enter>               to exit         " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4337 | #: ../version.c:4339 | ||||||
| msgid "type  :help<Enter>  or  <F1>  for on-line help" | msgid "type  :help<Enter>  or  <F1>  for on-line help" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4338 | #: ../version.c:4340 | ||||||
| msgid "type  :help version9<Enter>   for version info" | msgid "type  :help version9<Enter>   for version info" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4341 | #: ../version.c:4343 | ||||||
| msgid "Running in Vi compatible mode" | msgid "Running in Vi compatible mode" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4342 | #: ../version.c:4344 | ||||||
| msgid "type  :set nocp<Enter>        for Vim defaults" | msgid "type  :set nocp<Enter>        for Vim defaults" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4343 | #: ../version.c:4345 | ||||||
| msgid "type  :help cp-default<Enter> for info on this" | msgid "type  :help cp-default<Enter> for info on this" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4358 | #: ../version.c:4360 | ||||||
| msgid "menu  Help->Orphans           for information    " | msgid "menu  Help->Orphans           for information    " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4360 | #: ../version.c:4362 | ||||||
| msgid "Running modeless, typed text is inserted" | msgid "Running modeless, typed text is inserted" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4361 | #: ../version.c:4363 | ||||||
| msgid "menu  Edit->Global Settings->Toggle Insert Mode  " | msgid "menu  Edit->Global Settings->Toggle Insert Mode  " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4362 | #: ../version.c:4364 | ||||||
| msgid "                              for two modes      " | msgid "                              for two modes      " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4366 | #: ../version.c:4368 | ||||||
| msgid "menu  Edit->Global Settings->Toggle Vi Compatible" | msgid "menu  Edit->Global Settings->Toggle Vi Compatible" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4367 | #: ../version.c:4369 | ||||||
| msgid "                              for Vim defaults   " | msgid "                              for Vim defaults   " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4408 | #: ../version.c:4410 | ||||||
| msgid "Sponsor Vim development!" | msgid "Sponsor Vim development!" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4409 | #: ../version.c:4411 | ||||||
| msgid "Become a registered Vim user!" | msgid "Become a registered Vim user!" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4412 | #: ../version.c:4414 | ||||||
| msgid "type  :help sponsor<Enter>    for information " | msgid "type  :help sponsor<Enter>    for information " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4413 | #: ../version.c:4415 | ||||||
| msgid "type  :help register<Enter>   for information " | msgid "type  :help register<Enter>   for information " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| #: ../version.c:4415 | #: ../version.c:4417 | ||||||
| msgid "menu  Help->Sponsor/Register  for information    " | msgid "menu  Help->Sponsor/Register  for information    " | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -245,6 +245,7 @@ NEW_TESTS = \ | |||||||
| 	test_plugin_helptoc \ | 	test_plugin_helptoc \ | ||||||
| 	test_plugin_man \ | 	test_plugin_man \ | ||||||
| 	test_plugin_matchparen \ | 	test_plugin_matchparen \ | ||||||
|  | 	test_plugin_tar \ | ||||||
| 	test_plugin_termdebug \ | 	test_plugin_termdebug \ | ||||||
| 	test_plugin_tohtml \ | 	test_plugin_tohtml \ | ||||||
| 	test_plugin_tutor \ | 	test_plugin_tutor \ | ||||||
| @@ -517,6 +518,7 @@ NEW_TESTS_RES = \ | |||||||
| 	test_plugin_helptoc.res \ | 	test_plugin_helptoc.res \ | ||||||
| 	test_plugin_man.res \ | 	test_plugin_man.res \ | ||||||
| 	test_plugin_matchparen.res \ | 	test_plugin_matchparen.res \ | ||||||
|  | 	test_plugin_tar.res \ | ||||||
| 	test_plugin_termdebug.res \ | 	test_plugin_termdebug.res \ | ||||||
| 	test_plugin_tohtml.res \ | 	test_plugin_tohtml.res \ | ||||||
| 	test_plugin_tutor.res \ | 	test_plugin_tutor.res \ | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								src/testdir/samples/evil.tar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/testdir/samples/evil.tar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/testdir/samples/sample.tar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/testdir/samples/sample.tar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										128
									
								
								src/testdir/test_plugin_tar.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/testdir/test_plugin_tar.vim
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | vim9script | ||||||
|  |  | ||||||
|  | CheckExecutable tar | ||||||
|  | CheckNotMSWindows | ||||||
|  |  | ||||||
|  | runtime plugin/tarPlugin.vim | ||||||
|  |  | ||||||
|  | def CopyFile(source: string) | ||||||
|  |   if !filecopy($"samples/{source}", "X.tar") | ||||||
|  |     assert_report($"Can't copy samples/{source}") | ||||||
|  |   endif | ||||||
|  | enddef | ||||||
|  |  | ||||||
|  | def g:Test_tar_basic() | ||||||
|  |   CopyFile("sample.tar") | ||||||
|  |   defer delete("X.tar") | ||||||
|  |   defer delete("./testtar", 'rf') | ||||||
|  |   e X.tar | ||||||
|  |  | ||||||
|  |   ### Check header | ||||||
|  |   assert_match('^" tar\.vim version v\d\+', getline(1)) | ||||||
|  |   assert_match('^" Browsing tarfile .*/X.tar', getline(2)) | ||||||
|  |   assert_match('^" Select a file with cursor and press ENTER, "x" to extract a file', getline(3)) | ||||||
|  |   assert_match('^$', getline(4)) | ||||||
|  |   assert_match('testtar/', getline(5)) | ||||||
|  |   assert_match('testtar/file1.txt', getline(6)) | ||||||
|  |  | ||||||
|  |   ### Check ENTER on header | ||||||
|  |   :1 | ||||||
|  |   exe ":normal \<cr>" | ||||||
|  |   assert_equal("X.tar", @%) | ||||||
|  |  | ||||||
|  |   ### Check ENTER on file | ||||||
|  |   :6 | ||||||
|  |   exe ":normal \<cr>" | ||||||
|  |   assert_equal("tarfile::testtar/file1.txt", @%) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ### Check editing file | ||||||
|  |   ### Note: deleting entries not supported on BSD | ||||||
|  |   if has("mac") | ||||||
|  |     return | ||||||
|  |   endif | ||||||
|  |   if has("bsd") | ||||||
|  |     return | ||||||
|  |   endif | ||||||
|  |   s/.*/some-content/ | ||||||
|  |   assert_equal("some-content", getline(1)) | ||||||
|  |   w! | ||||||
|  |   assert_equal("tarfile::testtar/file1.txt", @%) | ||||||
|  |   bw! | ||||||
|  |   close | ||||||
|  |   bw! | ||||||
|  |  | ||||||
|  |   e X.tar | ||||||
|  |   :6 | ||||||
|  |   exe "normal \<cr>" | ||||||
|  |   assert_equal("some-content", getline(1)) | ||||||
|  |   bw! | ||||||
|  |   close | ||||||
|  |  | ||||||
|  |   ### Check extracting file | ||||||
|  |   :5 | ||||||
|  |   normal x | ||||||
|  |   assert_true(filereadable("./testtar/file1.txt")) | ||||||
|  |   bw! | ||||||
|  | enddef | ||||||
|  |  | ||||||
|  | def g:Test_tar_evil() | ||||||
|  |   CopyFile("evil.tar") | ||||||
|  |   defer delete("X.tar") | ||||||
|  |   defer delete("./etc", 'rf') | ||||||
|  |   e X.tar | ||||||
|  |  | ||||||
|  |   ### Check header | ||||||
|  |   assert_match('^" tar\.vim version v\d\+', getline(1)) | ||||||
|  |   assert_match('^" Browsing tarfile .*/X.tar', getline(2)) | ||||||
|  |   assert_match('^" Select a file with cursor and press ENTER, "x" to extract a file', getline(3)) | ||||||
|  |   assert_match('^" Note: Path Traversal Attack detected', getline(4)) | ||||||
|  |   assert_match('^$', getline(5)) | ||||||
|  |   assert_match('/etc/ax-pwn', getline(6)) | ||||||
|  |  | ||||||
|  |   ### Check ENTER on header | ||||||
|  |   :1 | ||||||
|  |   exe ":normal \<cr>" | ||||||
|  |   assert_equal("X.tar", @%) | ||||||
|  |   assert_equal(1, b:leading_slash) | ||||||
|  |  | ||||||
|  |   ### Check ENTER on file | ||||||
|  |   :6 | ||||||
|  |   exe ":normal \<cr>" | ||||||
|  |   assert_equal(1, b:leading_slash) | ||||||
|  |   assert_equal("tarfile::/etc/ax-pwn", @%) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ### Check editing file | ||||||
|  |   ### Note: deleting entries not supported on BSD | ||||||
|  |   if has("mac") | ||||||
|  |     return | ||||||
|  |   endif | ||||||
|  |   if has("bsd") | ||||||
|  |     return | ||||||
|  |   endif | ||||||
|  |   s/.*/none/ | ||||||
|  |   assert_equal("none", getline(1)) | ||||||
|  |   w! | ||||||
|  |   assert_equal(1, b:leading_slash) | ||||||
|  |   assert_equal("tarfile::/etc/ax-pwn", @%) | ||||||
|  |   bw! | ||||||
|  |   close | ||||||
|  |   bw! | ||||||
|  |  | ||||||
|  |   # Writing was aborted | ||||||
|  |   e X.tar | ||||||
|  |   assert_match('^" Note: Path Traversal Attack detected', getline(4)) | ||||||
|  |   :6 | ||||||
|  |   exe "normal \<cr>" | ||||||
|  |   assert_equal("something", getline(1)) | ||||||
|  |   bw! | ||||||
|  |   close | ||||||
|  |  | ||||||
|  |   ### Check extracting file | ||||||
|  |   :5 | ||||||
|  |   normal x | ||||||
|  |   assert_true(filereadable("./etc/ax-pwn")) | ||||||
|  |  | ||||||
|  |   bw! | ||||||
|  | enddef | ||||||
| @@ -719,6 +719,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1552, | ||||||
| /**/ | /**/ | ||||||
|     1551, |     1551, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user