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/*.vim \ | ||||
| 		src/testdir/samples/evil.zip \ | ||||
| 		src/testdir/samples/evil.tar \ | ||||
| 		src/testdir/samples/poc.zip \ | ||||
| 		src/testdir/samples/sample.tar \ | ||||
| 		src/testdir/samples/test.zip \ | ||||
| 		src/testdir/samples/test000 \ | ||||
| 		src/testdir/samples/test_undo.txt.undo \ | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| "                               instead of shelling out to file(1) | ||||
| "   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 Jul 13 by Vim Project: warn with path traversal attacks | ||||
| " | ||||
| "	Contains many ideas from Michael Toren's <tar.vim> | ||||
| " | ||||
| @@ -34,9 +35,9 @@ if &cp || exists("g:loaded_tar") | ||||
|  finish | ||||
| endif | ||||
| let g:loaded_tar= "v32b" | ||||
| if v:version < 702 | ||||
| if v:version < 900 | ||||
|  echohl WarningMsg | ||||
|  echo "***warning*** this version of tar needs vim 7.2" | ||||
|  echo "***warning*** this version of tar needs vim 9.0" | ||||
|  echohl Normal | ||||
|  finish | ||||
| endif | ||||
| @@ -46,10 +47,10 @@ set cpo&vim | ||||
| " --------------------------------------------------------------------- | ||||
| "  Default Settings: {{{1 | ||||
| if !exists("g:tar_browseoptions") | ||||
|  let g:tar_browseoptions= "Ptf" | ||||
|  let g:tar_browseoptions= "tf" | ||||
| endif | ||||
| if !exists("g:tar_readoptions") | ||||
|  let g:tar_readoptions= "pPxf" | ||||
|  let g:tar_readoptions= "pxf" | ||||
| endif | ||||
| if !exists("g:tar_cmd") | ||||
|  let g:tar_cmd= "tar" | ||||
| @@ -58,6 +59,7 @@ if !exists("g:tar_writeoptions") | ||||
|  let g:tar_writeoptions= "uf" | ||||
| endif | ||||
| if !exists("g:tar_delfile") | ||||
|  " Note: not supported on BSD | ||||
|  let g:tar_delfile="--delete -f" | ||||
| endif | ||||
| if !exists("g:netrw_cygwin") | ||||
| @@ -106,10 +108,26 @@ if !exists("g:tar_shq") | ||||
|  endif | ||||
| endif | ||||
|  | ||||
| let g:tar_secure=' -- ' | ||||
| let g:tar_leading_pat='^\%([.]\{,2\}/\)\+' | ||||
|  | ||||
| " ---------------- | ||||
| "  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 | ||||
| fun! tar#Browse(tarfile) | ||||
| @@ -118,16 +136,14 @@ fun! tar#Browse(tarfile) | ||||
|  | ||||
|   " sanity checks | ||||
|   if !executable(g:tar_cmd) | ||||
|    redraw! | ||||
|    echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system' | ||||
|    call s:Msg('tar#Browse', 'error', $"{g:tar_cmd} not available on your system") | ||||
|    let &report= repkeep | ||||
|    return | ||||
|   endif | ||||
|   if !filereadable(a:tarfile) | ||||
|    if a:tarfile !~# '^\a\+://' | ||||
|     " if it's an url, don't complain, let url-handlers such as vim do its thing | ||||
|     redraw! | ||||
|     echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None | ||||
|     call s:Msg('tar#Browse', 'error', $"File not readable<{a:tarfile}>") | ||||
|    endif | ||||
|    let &report= repkeep | ||||
|    return | ||||
| @@ -203,28 +219,18 @@ fun! tar#Browse(tarfile) | ||||
|    exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1) | ||||
|   endif | ||||
|   if v:shell_error != 0 | ||||
|    redraw! | ||||
|    echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">" | ||||
|    call s:Msg('tar#Browse', 'warning', $"please check your g:tar_browseoptions '<{g:tar_browseoptions}>'") | ||||
|    return | ||||
|   endif | ||||
|   " | ||||
|   " The following should not be neccessary, since in case of errors the | ||||
|   " previous if statement should have caught the problem (because tar exited | ||||
|   " with a non-zero exit code). | ||||
|   " if line("$") == curlast || ( line("$") == (curlast + 1) && | ||||
|   "       \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' && | ||||
|   "       \ getline("$") =~  '\s' ) | ||||
|   "  redraw! | ||||
|   "  echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None | ||||
|   "  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 | ||||
|  | ||||
|   " remove tar: Removing leading '/' from member names | ||||
|   " Note: the message could be localized | ||||
|   if search('^tar: ') > 0 || search(g:tar_leading_pat) > 0 | ||||
|     call append(3,'" Note: Path Traversal Attack detected!') | ||||
|     let b:leading_slash = 1 | ||||
|     " remove the message output | ||||
|     sil g/^tar: /d | ||||
|   endif | ||||
|  | ||||
|   " set up maps supported for tar | ||||
|   setlocal noma nomod ro | ||||
| @@ -243,12 +249,7 @@ fun! s:TarBrowseSelect() | ||||
|   let repkeep= &report | ||||
|   set report=10 | ||||
|   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 | ||||
|   let ls= get(b:, 'leading_slash', 0) | ||||
|  | ||||
|   " sanity check | ||||
|   if fname =~ '^"' | ||||
| @@ -270,7 +271,8 @@ fun! s:TarBrowseSelect() | ||||
|    wincmd _ | ||||
|   endif | ||||
|   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 | ||||
|   set nomod | ||||
|   exe 'com! -buffer -nargs=? -complete=file TarDiff	:call tar#Diff(<q-args>,"'.fnameescape(fname).'")' | ||||
| @@ -280,26 +282,18 @@ endfun | ||||
|  | ||||
| " --------------------------------------------------------------------- | ||||
| " tar#Read: {{{2 | ||||
| fun! tar#Read(fname,mode) | ||||
| fun! tar#Read(fname) | ||||
|   let repkeep= &report | ||||
|   set report=10 | ||||
|   let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','') | ||||
|   let fname   = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','') | ||||
|   " be careful not to execute special crafted files | ||||
|   let escape_file = fname->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 escape_file = fname->substitute(g:tar_leading_pat, '', '')->fnameescape() | ||||
|  | ||||
|   let curdir= getcwd() | ||||
|   let b:curdir= curdir | ||||
|   let tmpdir= tempname() | ||||
|   let b:curdir= tmpdir | ||||
|   let b:tmpdir= curdir | ||||
|   let b:tmpdir= tmpdir | ||||
|   if tmpdir =~ '\.' | ||||
|    let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') | ||||
|   endif | ||||
| @@ -309,8 +303,7 @@ fun! tar#Read(fname,mode) | ||||
|   try | ||||
|    exe "lcd ".fnameescape(tmpdir) | ||||
|   catch /^Vim\%((\a\+)\)\=:E344/ | ||||
|    redraw! | ||||
|    echohl Error | echo "***error*** (tar#Write) cannot lcd to temporary directory" | Echohl None | ||||
|    call s:Msg('tar#Read', 'error', "cannot lcd to temporary directory") | ||||
|    let &report= repkeep | ||||
|    return | ||||
|   endtry | ||||
| @@ -356,68 +349,66 @@ fun! tar#Read(fname,mode) | ||||
|    endif | ||||
|   endif | ||||
|  | ||||
|   if exists("g:tar_secure") | ||||
|    let tar_secure= " -- " | ||||
|   else | ||||
|    let tar_secure= " " | ||||
|   endif | ||||
|  | ||||
|   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 | ||||
|   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 | ||||
|   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 | ||||
|   elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)' | ||||
|    let filekind= s:Header(tarfile) | ||||
|    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 | ||||
|    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 | ||||
|    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 | ||||
|    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 | ||||
|    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 | ||||
|    endif | ||||
|  | ||||
|   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 | ||||
|   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 | ||||
|   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 | ||||
|   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 | ||||
|   else | ||||
|    if tarfile =~ '^\s*-' | ||||
|     " A file name starting with a dash is taken as an option.  Prepend ./ to avoid that. | ||||
|     let tarfile = substitute(tarfile, '-', './-', '') | ||||
|    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 | ||||
|   endif | ||||
|   if get(b:, 'leading_slash', 0) | ||||
|     sil g/^tar: /d | ||||
|   endif | ||||
|  | ||||
|    redraw! | ||||
|  | ||||
| if v:shell_error != 0 | ||||
|   if v:shell_error != 0 | ||||
|    lcd .. | ||||
|    call s:Rmdir("_ZIPVIM_") | ||||
|    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 | ||||
|  | ||||
|   if doro | ||||
| @@ -426,7 +417,6 @@ if v:shell_error != 0 | ||||
|   endif | ||||
|  | ||||
|   let b:tarfile= a:fname | ||||
|   exe "file tarfile::".fnameescape(fname) | ||||
|  | ||||
|   " cleanup | ||||
|   keepj sil! 0d | ||||
| @@ -434,7 +424,7 @@ if v:shell_error != 0 | ||||
|  | ||||
|   let &report= repkeep | ||||
|   exe "lcd ".fnameescape(curdir) | ||||
|   silent exe "file tarfile::".escape_file | ||||
|   silent exe "file tarfile::". fname->fnameescape() | ||||
| endfun | ||||
|  | ||||
| " --------------------------------------------------------------------- | ||||
| @@ -446,22 +436,35 @@ fun! tar#Write(fname) | ||||
|   let curdir= b:curdir | ||||
|   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 | ||||
|   if !executable(g:tar_cmd) | ||||
|    redraw! | ||||
|    let &report= repkeep | ||||
|    return | ||||
|   endif | ||||
|  | ||||
|   let tarfile = 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 | ||||
|   if tarfile =~# '\.bz2' | ||||
|    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 | ||||
|  | ||||
|   if v:shell_error != 0 | ||||
|    redraw! | ||||
|    echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None | ||||
|    call s:Msg('tar#Write', 'error', $"sorry, unable to update {tarfile} with {fname}") | ||||
|   else | ||||
|  | ||||
|    if fname =~ '/' | ||||
| @@ -519,28 +521,22 @@ fun! tar#Write(fname) | ||||
|     let tarfile = substitute(tarfile, '-', './-', '') | ||||
|    endif | ||||
|  | ||||
|    if exists("g:tar_secure") | ||||
|     let tar_secure= " -- " | ||||
|    else | ||||
|     let tar_secure= " " | ||||
|    endif | ||||
|    exe "w! ".fnameescape(fname) | ||||
|    " don't overwrite a file forcefully | ||||
|    exe "w ".fnameescape(fname) | ||||
|    if has("win32unix") && executable("cygpath") | ||||
|     let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e') | ||||
|    endif | ||||
|  | ||||
|    " 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 | ||||
|     redraw! | ||||
|     echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None | ||||
|     call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)} --delete not supported?") | ||||
|    else | ||||
|  | ||||
|     " 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 | ||||
|      redraw! | ||||
|      echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None | ||||
|      call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)}") | ||||
|     elseif exists("compress") | ||||
|      call system(compress) | ||||
|      if exists("tgz") | ||||
| @@ -581,6 +577,7 @@ fun! tar#Diff(userfname,fname) | ||||
|   if a:userfname != "" | ||||
|    let fname= a:userfname | ||||
|   endif | ||||
|   exe "lcd ".fnameescape(b:tmpdir). '/_ZIPVIM_' | ||||
|   if filereadable(fname) | ||||
|    " sets current file (from tarball) for diff'ing | ||||
|    " splits window vertically | ||||
| @@ -604,12 +601,6 @@ fun! tar#Extract() | ||||
|   set report=10 | ||||
|   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 | ||||
|   if fname =~ '^"' | ||||
|    let &report= repkeep | ||||
| @@ -623,16 +614,16 @@ fun! tar#Extract() | ||||
|   if filereadable(tarbase.".tar") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|     echo "***note*** successfully extracted ". fname | ||||
|    endif | ||||
|  | ||||
|   elseif filereadable(tarbase.".tgz") | ||||
|    let extractcmd= substitute(extractcmd,"-","-z","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -641,7 +632,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-z","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -650,7 +641,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-j","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -659,7 +650,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-j","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -668,7 +659,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-j","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -677,7 +668,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-J","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -686,7 +677,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-J","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -695,7 +686,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","--zstd","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -704,7 +695,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","--zstd","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -713,7 +704,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-I lz4","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -722,7 +713,7 @@ fun! tar#Extract() | ||||
|    let extractcmd= substitute(extractcmd,"-","-I lz4","") | ||||
|    call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname)) | ||||
|    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 | ||||
|     echo "***note*** successfully extracted ".fname | ||||
|    endif | ||||
| @@ -735,15 +726,7 @@ endfun | ||||
| " --------------------------------------------------------------------- | ||||
| " s:Rmdir: {{{2 | ||||
| fun! s:Rmdir(fname) | ||||
|   if has("unix") | ||||
|    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 | ||||
|   call delete(a:fname, 'rf') | ||||
| endfun | ||||
|  | ||||
| " 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 | | ||||
| 		       +====================+ | ||||
|  | ||||
| Author:  Charles E. Campbell  <NcampObell@SdrPchip.AorgM-NOSPAM> | ||||
| 	  (remove NOSPAM from Campbell's email first) | ||||
| Original Author:  Charles E. Campbell | ||||
| Copyright 2005-2017:					*tar-copyright* | ||||
| 	The VIM LICENSE (see |copyright|) applies to the files in this | ||||
| 	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 | ||||
| 	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. | ||||
|  | ||||
|  | ||||
| @@ -95,24 +94,25 @@ Copyright 2005-2017:					*tar-copyright* | ||||
|    *g:tar_readoptions*	  "OPxf"  used to extract a file from a tarball | ||||
|    *g:tar_cmd*		  "tar"   the name of the tar program | ||||
|    *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 | ||||
|  | ||||
|  | ||||
| ============================================================================== | ||||
| 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 | ||||
| 				  files in a zip archive created unencrypted | ||||
| 				  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_nomax	pi_tar.txt	/*g:tar_nomax* | ||||
| 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:termdebug_config	terminal.txt	/*g:termdebug_config* | ||||
| g:termdebugger	terminal.txt	/*g:termdebugger* | ||||
|   | ||||
| @@ -23,14 +23,14 @@ set cpo&vim | ||||
| "  Public Interface: {{{1 | ||||
| augroup tar | ||||
|   au! | ||||
|   au BufReadCmd   tarfile::*	call tar#Read(expand("<amatch>"), 1) | ||||
|   au FileReadCmd  tarfile::*	call tar#Read(expand("<amatch>"), 0) | ||||
|   au BufReadCmd   tarfile::*	call tar#Read(expand("<amatch>")) | ||||
|   au FileReadCmd  tarfile::*	call tar#Read(expand("<amatch>")) | ||||
|   au BufWriteCmd  tarfile::*	call tar#Write(expand("<amatch>")) | ||||
|   au FileWriteCmd tarfile::*	call tar#Write(expand("<amatch>")) | ||||
|  | ||||
|   if has("unix") | ||||
|    au BufReadCmd   tarfile::*/*	call tar#Read(expand("<amatch>"), 1) | ||||
|    au FileReadCmd  tarfile::*/*	call tar#Read(expand("<amatch>"), 0) | ||||
|    au BufReadCmd   tarfile::*/*	call tar#Read(expand("<amatch>")) | ||||
|    au FileReadCmd  tarfile::*/*	call tar#Read(expand("<amatch>")) | ||||
|    au BufWriteCmd  tarfile::*/*	call tar#Write(expand("<amatch>")) | ||||
|    au FileWriteCmd tarfile::*/*	call tar#Write(expand("<amatch>")) | ||||
|   endif | ||||
|   | ||||
							
								
								
									
										162
									
								
								src/po/vim.pot
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								src/po/vim.pot
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\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" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -4257,327 +4257,327 @@ msgstr "" | ||||
| msgid "%s (%s, compiled %s)" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4036 | ||||
| #: ../version.c:4038 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows ARM64 GUI/console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4038 | ||||
| #: ../version.c:4040 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 64-bit GUI/console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4041 | ||||
| #: ../version.c:4043 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 32-bit GUI/console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4046 | ||||
| #: ../version.c:4048 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows ARM64 GUI version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4048 | ||||
| #: ../version.c:4050 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 64-bit GUI version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4051 | ||||
| #: ../version.c:4053 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 32-bit GUI version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4055 | ||||
| #: ../version.c:4057 | ||||
| msgid " with OLE support" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4060 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows ARM64 console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4062 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows ARM64 console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4064 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 64-bit console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4065 | ||||
| #: ../version.c:4067 | ||||
| msgid "" | ||||
| "\n" | ||||
| "MS-Windows 32-bit console version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4071 | ||||
| #: ../version.c:4073 | ||||
| msgid "" | ||||
| "\n" | ||||
| "macOS version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4073 | ||||
| #: ../version.c:4075 | ||||
| msgid "" | ||||
| "\n" | ||||
| "macOS version w/o darwin feat." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4083 | ||||
| #: ../version.c:4085 | ||||
| msgid "" | ||||
| "\n" | ||||
| "OpenVMS version" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4098 | ||||
| #: ../version.c:4100 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Included patches: " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4123 | ||||
| #: ../version.c:4125 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Extra patches: " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4135 ../version.c:4446 | ||||
| #: ../version.c:4137 ../version.c:4448 | ||||
| msgid "Modified by " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4142 | ||||
| #: ../version.c:4144 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Compiled " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4145 | ||||
| #: ../version.c:4147 | ||||
| msgid "by " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4157 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Huge version " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4159 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Normal version " | ||||
| "Huge version " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4161 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Normal version " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4163 | ||||
| msgid "" | ||||
| "\n" | ||||
| "Tiny version " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4164 | ||||
| #: ../version.c:4166 | ||||
| msgid "without GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4167 | ||||
| #: ../version.c:4169 | ||||
| msgid "with GTK3 GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4169 | ||||
| #: ../version.c:4171 | ||||
| msgid "with GTK2-GNOME GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4171 | ||||
| #: ../version.c:4173 | ||||
| msgid "with GTK2 GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4174 | ||||
| #: ../version.c:4176 | ||||
| msgid "with X11-Motif GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4176 | ||||
| #: ../version.c:4178 | ||||
| msgid "with Haiku GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4178 | ||||
| #: ../version.c:4180 | ||||
| msgid "with Photon GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4180 | ||||
| #: ../version.c:4182 | ||||
| msgid "with GUI." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4182 | ||||
| #: ../version.c:4184 | ||||
| msgid "  Features included (+) or not (-):\n" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4189 | ||||
| #: ../version.c:4191 | ||||
| msgid "   system vimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4194 | ||||
| #: ../version.c:4196 | ||||
| msgid "     user vimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4199 | ||||
| #: ../version.c:4201 | ||||
| msgid " 2nd user vimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4204 ../version.c:4211 ../version.c:4215 | ||||
| #: ../version.c:4206 ../version.c:4213 ../version.c:4217 | ||||
| msgid " 3rd user vimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4207 | ||||
| #: ../version.c:4209 | ||||
| msgid " 4th user vimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4220 | ||||
| #: ../version.c:4222 | ||||
| msgid "      user exrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4225 | ||||
| #: ../version.c:4227 | ||||
| msgid "  2nd user exrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4231 | ||||
| #: ../version.c:4233 | ||||
| msgid "  system gvimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4235 | ||||
| #: ../version.c:4237 | ||||
| msgid "    user gvimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4239 | ||||
| #: ../version.c:4241 | ||||
| msgid "2nd user gvimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4244 | ||||
| #: ../version.c:4246 | ||||
| msgid "3rd user gvimrc file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4249 | ||||
| #: ../version.c:4251 | ||||
| msgid "       defaults file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4254 | ||||
| #: ../version.c:4256 | ||||
| msgid "    system menu file: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4262 | ||||
| #: ../version.c:4264 | ||||
| msgid "  fall-back for $VIM: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4268 | ||||
| #: ../version.c:4270 | ||||
| msgid " f-b for $VIMRUNTIME: \"" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4272 | ||||
| #: ../version.c:4274 | ||||
| msgid "Compilation: " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4278 | ||||
| #: ../version.c:4280 | ||||
| msgid "Compiler: " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4283 | ||||
| #: ../version.c:4285 | ||||
| msgid "Linking: " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4288 | ||||
| #: ../version.c:4290 | ||||
| msgid "  DEBUG BUILD" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4324 | ||||
| #: ../version.c:4326 | ||||
| msgid "VIM - Vi IMproved" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4326 | ||||
| #: ../version.c:4328 | ||||
| msgid "version " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4327 | ||||
| #: ../version.c:4329 | ||||
| msgid "by Bram Moolenaar et al." | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4331 | ||||
| #: ../version.c:4333 | ||||
| msgid "Vim is open source and freely distributable" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4333 | ||||
| #: ../version.c:4335 | ||||
| msgid "Help poor children in Uganda!" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4334 | ||||
| #: ../version.c:4336 | ||||
| msgid "type  :help iccf<Enter>       for information " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4336 | ||||
| #: ../version.c:4338 | ||||
| msgid "type  :q<Enter>               to exit         " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4337 | ||||
| #: ../version.c:4339 | ||||
| msgid "type  :help<Enter>  or  <F1>  for on-line help" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4338 | ||||
| #: ../version.c:4340 | ||||
| msgid "type  :help version9<Enter>   for version info" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4341 | ||||
| #: ../version.c:4343 | ||||
| msgid "Running in Vi compatible mode" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4342 | ||||
| #: ../version.c:4344 | ||||
| msgid "type  :set nocp<Enter>        for Vim defaults" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4343 | ||||
| #: ../version.c:4345 | ||||
| msgid "type  :help cp-default<Enter> for info on this" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4358 | ||||
| #: ../version.c:4360 | ||||
| msgid "menu  Help->Orphans           for information    " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4360 | ||||
| #: ../version.c:4362 | ||||
| msgid "Running modeless, typed text is inserted" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4361 | ||||
| #: ../version.c:4363 | ||||
| msgid "menu  Edit->Global Settings->Toggle Insert Mode  " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4362 | ||||
| #: ../version.c:4364 | ||||
| msgid "                              for two modes      " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4366 | ||||
| #: ../version.c:4368 | ||||
| msgid "menu  Edit->Global Settings->Toggle Vi Compatible" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4367 | ||||
| #: ../version.c:4369 | ||||
| msgid "                              for Vim defaults   " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4408 | ||||
| #: ../version.c:4410 | ||||
| msgid "Sponsor Vim development!" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4409 | ||||
| #: ../version.c:4411 | ||||
| msgid "Become a registered Vim user!" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4412 | ||||
| #: ../version.c:4414 | ||||
| msgid "type  :help sponsor<Enter>    for information " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4413 | ||||
| #: ../version.c:4415 | ||||
| msgid "type  :help register<Enter>   for information " | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../version.c:4415 | ||||
| #: ../version.c:4417 | ||||
| msgid "menu  Help->Sponsor/Register  for information    " | ||||
| msgstr "" | ||||
| 
 | ||||
|   | ||||
| @@ -245,6 +245,7 @@ NEW_TESTS = \ | ||||
| 	test_plugin_helptoc \ | ||||
| 	test_plugin_man \ | ||||
| 	test_plugin_matchparen \ | ||||
| 	test_plugin_tar \ | ||||
| 	test_plugin_termdebug \ | ||||
| 	test_plugin_tohtml \ | ||||
| 	test_plugin_tutor \ | ||||
| @@ -517,6 +518,7 @@ NEW_TESTS_RES = \ | ||||
| 	test_plugin_helptoc.res \ | ||||
| 	test_plugin_man.res \ | ||||
| 	test_plugin_matchparen.res \ | ||||
| 	test_plugin_tar.res \ | ||||
| 	test_plugin_termdebug.res \ | ||||
| 	test_plugin_tohtml.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[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     1552, | ||||
| /**/ | ||||
|     1551, | ||||
| /**/ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user