mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	patch 9.1.0686: zip-plugin has problems with special characters
Problem:  zip-plugin has problems with special characters
          (user202729)
Solution: escape '*?[\' on Unix and handle those chars
          a bit differently on MS-Windows, add a test, check
          before overwriting files
runtime(zip): small fixes for zip plugin
This does the following:
- verify the unzip plugin is executable when loading the autoload plugin
- handle extracting file names with '[*?\' in its name correctly by
  escaping those characters for the unzip command (and handle those
  characters a bit differently on MS-Windows, since the quoting is different)
- verify, that the extract plugin is not overwriting a file (could cause
  a hang, because unzip asking for confirmation)
- add a test zip file which contains those special file names
fixes: #15505
closes: #15519
Signed-off-by: Christian Brabandt <cb@256bit.org>
			
			
This commit is contained in:
		
							
								
								
									
										1
									
								
								Filelist
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Filelist
									
									
									
									
									
								
							| @@ -221,6 +221,7 @@ SRC_ALL =	\ | ||||
| 		src/testdir/samples/*.vim \ | ||||
| 		src/testdir/samples/test000 \ | ||||
| 		src/testdir/samples/test.zip \ | ||||
| 		src/testdir/samples/testa.zip \ | ||||
| 		src/testdir/color_ramp.vim \ | ||||
| 		src/testdir/silent.wav \ | ||||
| 		src/testdir/popupbounce.vim \ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| " zip.vim: Handles browsing zipfiles | ||||
| " AUTOLOAD PORTION | ||||
| " Date:		Aug 05, 2024 | ||||
| " Date:		Aug 18, 2024 | ||||
| " Version:	34 | ||||
| " Maintainer:	This runtime file is looking for a new maintainer. | ||||
| " Former Maintainer:	Charles E Campbell | ||||
| @@ -12,6 +12,7 @@ | ||||
| " 2024 Aug 04 by Vim Project: escape '[' in name of file to be extracted | ||||
| " 2024 Aug 05 by Vim Project: workaround for the FreeBSD's unzip | ||||
| " 2024 Aug 05 by Vim Project: clean-up and make it work with shellslash on Windows | ||||
| " 2024 Aug 18 by Vim Project: correctly handle special globbing chars | ||||
| " License:	Vim License  (see vim's :help license) | ||||
| " Copyright:	Copyright (C) 2005-2019 Charles E. Campbell {{{1 | ||||
| "		Permission is hereby granted to use and distribute this code, | ||||
| @@ -73,6 +74,11 @@ if v:version < 901 | ||||
|  call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later") | ||||
|  finish | ||||
| endif | ||||
| " sanity checks | ||||
| if !executable(g:zip_unzipcmd) | ||||
|  call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system") | ||||
|  finish | ||||
| endif | ||||
| if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd) | ||||
|  call s:Mess('Error', "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!") | ||||
|  finish | ||||
| @@ -199,7 +205,7 @@ fun! zip#Read(fname,mode) | ||||
|    let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','') | ||||
|    let fname   = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','') | ||||
|   endif | ||||
|   let fname    = substitute(fname, '[', '[[]', 'g') | ||||
|   let fname    = fname->substitute('[', '[[]', 'g')->escape('?*\\') | ||||
|   " sanity check | ||||
|   if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','','')) | ||||
|    call s:Mess('Error', "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program") | ||||
| @@ -331,9 +337,24 @@ fun! zip#Extract() | ||||
|    call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory") | ||||
|    return | ||||
|   endif | ||||
|   if filereadable(fname) | ||||
|    call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!") | ||||
|    return | ||||
|   endif | ||||
|   let target = fname->substitute('\[', '[[]', 'g') | ||||
|   if &shell =~ 'cmd' && (has("win32") || has("win64")) | ||||
|     let target = target | ||||
| 		\ ->substitute('[?*]', '[&]', 'g') | ||||
| 		\ ->substitute('[\\]', '?', 'g') | ||||
| 		\ ->shellescape() | ||||
|     " there cannot be a file name with '\' in its name, unzip replaces it by _ | ||||
|     let fname = fname->substitute('[\\?*]', '_', 'g') | ||||
|   else | ||||
|     let target = target->escape('*?\\')->shellescape() | ||||
|   endif | ||||
|  | ||||
|   " extract the file mentioned under the cursor | ||||
|   call system($"{g:zip_extractcmd} {shellescape(b:zipfile)} {shellescape(fname)}") | ||||
|   call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}") | ||||
|   if v:shell_error != 0 | ||||
|    call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!") | ||||
|   elseif !filereadable(fname) | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								src/testdir/samples/testa.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/testdir/samples/testa.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -40,7 +40,8 @@ def Test_zip_basic() | ||||
|                execute("normal \<CR>")) | ||||
|  | ||||
|   ### Check ENTER on file | ||||
|   :1|:/^$//file/ | ||||
|   :1 | ||||
|   search('file.txt') | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::Xzip/file.txt', @%) | ||||
|   assert_equal('one', getline(1)) | ||||
| @@ -65,6 +66,10 @@ def Test_zip_basic() | ||||
|   :1|:/^$//file/ | ||||
|   normal x | ||||
|   assert_true(filereadable("Xzip/file.txt")) | ||||
|  | ||||
|   ## Check not overwriting existing file | ||||
|   assert_match('<Xzip/file.txt> .* not overwriting!', execute("normal x")) | ||||
|  | ||||
|   delete("Xzip", "rf") | ||||
|  | ||||
|   ### Check extracting directory | ||||
| @@ -131,5 +136,102 @@ def Test_zip_basic() | ||||
|   assert_match('File not readable', execute("e Xnot_exists.zip")) | ||||
|  | ||||
|   bw | ||||
|  | ||||
| enddef | ||||
|  | ||||
| def Test_zip_glob_fname() | ||||
|   CheckNotMSWindows | ||||
|   # does not work on Windows, why? | ||||
|  | ||||
|   ### copy sample zip file | ||||
|   if !filecopy("samples/testa.zip", "X.zip") | ||||
|     assert_report("Can't copy samples/testa.zip") | ||||
|     return | ||||
|   endif | ||||
|   defer delete("X.zip") | ||||
|   defer delete('zipglob', 'rf') | ||||
|  | ||||
|   e X.zip | ||||
|  | ||||
|   ### 1) Check extracting strange files | ||||
|   :1 | ||||
|   var fname = 'a[a].txt' | ||||
|   search('\V' .. fname) | ||||
|   normal x | ||||
|   assert_true(filereadable('zipglob/' .. fname)) | ||||
|   delete('zipglob', 'rf') | ||||
|  | ||||
|   :1 | ||||
|   fname = 'a*.txt' | ||||
|   search('\V' .. fname) | ||||
|   normal x | ||||
|   assert_true(filereadable('zipglob/' .. fname)) | ||||
|   delete('zipglob', 'rf') | ||||
|  | ||||
|   :1 | ||||
|   fname = 'a?.txt' | ||||
|   search('\V' .. fname) | ||||
|   normal x | ||||
|   assert_true(filereadable('zipglob/' .. fname)) | ||||
|   delete('zipglob', 'rf') | ||||
|  | ||||
|   :1 | ||||
|   fname = 'a\.txt' | ||||
|   search('\V' .. escape(fname, '\\')) | ||||
|   normal x | ||||
|   assert_true(filereadable('zipglob/' .. fname)) | ||||
|   delete('zipglob', 'rf') | ||||
|  | ||||
|   :1 | ||||
|   fname = 'a\\.txt' | ||||
|   search('\V' .. escape(fname, '\\')) | ||||
|   normal x | ||||
|   assert_true(filereadable('zipglob/' .. fname)) | ||||
|   delete('zipglob', 'rf') | ||||
|  | ||||
|   ### 2) Check entering strange file names | ||||
|   :1 | ||||
|   fname = 'a[a].txt' | ||||
|   search('\V' .. fname) | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::zipglob/a\[a\].txt', @%) | ||||
|   assert_equal('a test file with []', getline(1)) | ||||
|   bw | ||||
|  | ||||
|   e X.zip | ||||
|   :1 | ||||
|   fname = 'a*.txt' | ||||
|   search('\V' .. fname) | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::zipglob/a\*.txt', @%) | ||||
|   assert_equal('a test file with a*', getline(1)) | ||||
|   bw | ||||
|  | ||||
|   e X.zip | ||||
|   :1 | ||||
|   fname = 'a?.txt' | ||||
|   search('\V' .. fname) | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::zipglob/a?.txt', @%) | ||||
|   assert_equal('a test file with a?', getline(1)) | ||||
|   bw | ||||
|  | ||||
|   e X.zip | ||||
|   :1 | ||||
|   fname = 'a\.txt' | ||||
|   search('\V' .. escape(fname, '\\')) | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::zipglob/a\\.txt', @%) | ||||
|   assert_equal('a test file with a\', getline(1)) | ||||
|   bw | ||||
|  | ||||
|   e X.zip | ||||
|   :1 | ||||
|   fname = 'a\\.txt' | ||||
|   search('\V' .. escape(fname, '\\')) | ||||
|   exe ":normal \<cr>" | ||||
|   assert_match('zipfile://.*/X.zip::zipglob/a\\\\.txt', @%) | ||||
|   assert_equal('a test file with a double \', getline(1)) | ||||
|   bw | ||||
|  | ||||
|   bw | ||||
| enddef | ||||
|   | ||||
| @@ -704,6 +704,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     686, | ||||
| /**/ | ||||
|     685, | ||||
| /**/ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user