Mercurial > vim
annotate runtime/autoload/gzip.vim @ 33716:bd3ee5abdd7a
runtime(dist): centralize safe executable check and add vim library (#13413)
Commit: https://github.com/vim/vim/commit/cd8a3eaf5348feacfecab4b374b7ea4ce6a97422
Author: D. Ben Knoble <ben.knoble+github@gmail.com>
Date: Sat Nov 4 05:11:17 2023 -0400
runtime(dist): centralize safe executable check and add vim library (https://github.com/vim/vim/issues/13413)
Follow up to 816fbcc26 (patch 9.0.1833: [security] runtime file fixes,
2023-08-31) and f7ac0ef50 (runtime: don't execute external commands when
loading ftplugins, 2023-09-06).
This puts the logic for safe executable checks in a single place, by introducing
a central vim library, so all filetypes benefit from consistency.
Notable changes:
- dist#vim because the (autoload) namespace for a new runtime support
library. Supporting functions should get documentation. It might make
life easier for NeoVim devs to make the documentation a new file
rather than cram it into existing files, though we may want
cross-references to it somewhere?
- The gzip and zip plugins need to be opted into by enabling execution
of those programs (or the global plugin_exec). This needs
documentation or discussion.
- This fixes a bug in the zig plugin: code setting s:tmp_cwd was removed
in f7ac0ef50 (runtime: don't execute external commands when loading
ftplugins, 2023-09-06), but the variable was still referenced. Since
the new function takes care of that automatically, the variable is no
longer needed.
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 04 Nov 2023 10:15:06 +0100 |
parents | 8bc48ca90534 |
children |
rev | line source |
---|---|
446 | 1 " Vim autoload file for editing compressed files. |
32770
4027cefc2aab
Farewell to Bram and dedicate upcoming Vim 9.1 to him (#12749)
Christian Brabandt <cb@256bit.org>
parents:
10244
diff
changeset
|
2 " Maintainer: The Vim Project <https://github.com/vim/vim> |
4027cefc2aab
Farewell to Bram and dedicate upcoming Vim 9.1 to him (#12749)
Christian Brabandt <cb@256bit.org>
parents:
10244
diff
changeset
|
3 " Last Change: 2023 Aug 10 |
4027cefc2aab
Farewell to Bram and dedicate upcoming Vim 9.1 to him (#12749)
Christian Brabandt <cb@256bit.org>
parents:
10244
diff
changeset
|
4 " Former Maintainer: Bram Moolenaar <Bram@vim.org> |
446 | 5 |
6 " These functions are used by the gzip plugin. | |
7 | |
8 " Function to check that executing "cmd [-f]" works. | |
9 " The result is cached in s:have_"cmd" for speed. | |
10 fun s:check(cmd) | |
11 let name = substitute(a:cmd, '\(\S*\).*', '\1', '') | |
12 if !exists("s:have_" . name) | |
33096
828bcb1a37e7
patch 9.0.1833: [security] runtime file fixes
Christian Brabandt <cb@256bit.org>
parents:
32770
diff
changeset
|
13 " safety check, don't execute anything from the current directory |
33716
bd3ee5abdd7a
runtime(dist): centralize safe executable check and add vim library (#13413)
Christian Brabandt <cb@256bit.org>
parents:
33196
diff
changeset
|
14 let f = dist#vim#IsSafeExecutable('gzip', name) |
33096
828bcb1a37e7
patch 9.0.1833: [security] runtime file fixes
Christian Brabandt <cb@256bit.org>
parents:
32770
diff
changeset
|
15 if !f |
828bcb1a37e7
patch 9.0.1833: [security] runtime file fixes
Christian Brabandt <cb@256bit.org>
parents:
32770
diff
changeset
|
16 echoerr "Warning: NOT executing " .. name .. " from current directory!" |
828bcb1a37e7
patch 9.0.1833: [security] runtime file fixes
Christian Brabandt <cb@256bit.org>
parents:
32770
diff
changeset
|
17 endif |
446 | 18 let e = executable(name) |
19 if e < 0 | |
20 let r = system(name . " --version") | |
21 let e = (r !~ "not found" && r != "") | |
22 endif | |
33096
828bcb1a37e7
patch 9.0.1833: [security] runtime file fixes
Christian Brabandt <cb@256bit.org>
parents:
32770
diff
changeset
|
23 exe "let s:have_" . name . "=" . (e && f) |
446 | 24 endif |
25 exe "return s:have_" . name | |
26 endfun | |
27 | |
28 " Set b:gzip_comp_arg to the gzip argument to be used for compression, based on | |
29 " the flags in the compressed file. | |
30 " The only compression methods that can be detected are max speed (-1) and max | |
31 " compression (-9). | |
32 fun s:set_compression(line) | |
33 " get the Compression Method | |
34 let l:cm = char2nr(a:line[2]) | |
35 " if it's 8 (DEFLATE), we can check for the compression level | |
36 if l:cm == 8 | |
37 " get the eXtra FLags | |
38 let l:xfl = char2nr(a:line[8]) | |
39 " max compression | |
40 if l:xfl == 2 | |
41 let b:gzip_comp_arg = "-9" | |
42 " min compression | |
43 elseif l:xfl == 4 | |
44 let b:gzip_comp_arg = "-1" | |
45 endif | |
46 endif | |
47 endfun | |
48 | |
49 | |
50 " After reading compressed file: Uncompress text in buffer with "cmd" | |
51 fun gzip#read(cmd) | |
52 " don't do anything if the cmd is not supported | |
53 if !s:check(a:cmd) | |
54 return | |
55 endif | |
56 | |
57 " for gzip check current compression level and set b:gzip_comp_arg. | |
58 silent! unlet b:gzip_comp_arg | |
59 if a:cmd[0] == 'g' | |
60 call s:set_compression(getline(1)) | |
61 endif | |
62 | |
63 " make 'patchmode' empty, we don't want a copy of the written file | |
64 let pm_save = &pm | |
65 set pm= | |
66 " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes | |
67 let cpo_save = &cpo | |
68 set cpo-=a cpo-=A | |
69 " set 'modifiable' | |
70 let ma_save = &ma | |
71 setlocal ma | |
10244
876fbdd84e52
commit https://github.com/vim/vim/commit/2ec618c9feac4573b154510236ad8121c77d0eca
Christian Brabandt <cb@256bit.org>
parents:
6336
diff
changeset
|
72 " set 'write' |
876fbdd84e52
commit https://github.com/vim/vim/commit/2ec618c9feac4573b154510236ad8121c77d0eca
Christian Brabandt <cb@256bit.org>
parents:
6336
diff
changeset
|
73 let write_save = &write |
876fbdd84e52
commit https://github.com/vim/vim/commit/2ec618c9feac4573b154510236ad8121c77d0eca
Christian Brabandt <cb@256bit.org>
parents:
6336
diff
changeset
|
74 set write |
1190 | 75 " Reset 'foldenable', otherwise line numbers get adjusted. |
76 if has("folding") | |
77 let fen_save = &fen | |
78 setlocal nofen | |
79 endif | |
80 | |
446 | 81 " when filtering the whole buffer, it will become empty |
82 let empty = line("'[") == 1 && line("']") == line("$") | |
83 let tmp = tempname() | |
84 let tmpe = tmp . "." . expand("<afile>:e") | |
1592 | 85 if exists('*fnameescape') |
86 let tmp_esc = fnameescape(tmp) | |
87 let tmpe_esc = fnameescape(tmpe) | |
88 else | |
89 let tmp_esc = escape(tmp, ' ') | |
90 let tmpe_esc = escape(tmpe, ' ') | |
91 endif | |
446 | 92 " write the just read lines to a temp file "'[,']w tmp.gz" |
1592 | 93 execute "silent '[,']w " . tmpe_esc |
446 | 94 " uncompress the temp file: call system("gzip -dn tmp.gz") |
985 | 95 call system(a:cmd . " " . s:escape(tmpe)) |
446 | 96 if !filereadable(tmp) |
97 " uncompress didn't work! Keep the compressed file then. | |
98 echoerr "Error: Could not read uncompressed file" | |
1190 | 99 let ok = 0 |
446 | 100 else |
1190 | 101 let ok = 1 |
102 " delete the compressed lines; remember the line number | |
103 let l = line("'[") - 1 | |
104 if exists(":lockmarks") | |
105 lockmarks '[,']d _ | |
106 else | |
107 '[,']d _ | |
108 endif | |
109 " read in the uncompressed lines "'[-1r tmp" | |
110 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options. | |
111 setlocal nobin | |
112 if exists(":lockmarks") | |
113 if empty | |
1592 | 114 execute "silent lockmarks " . l . "r ++edit " . tmp_esc |
1190 | 115 else |
1592 | 116 execute "silent lockmarks " . l . "r " . tmp_esc |
1190 | 117 endif |
118 else | |
1592 | 119 execute "silent " . l . "r " . tmp_esc |
1190 | 120 endif |
121 | |
122 " if buffer became empty, delete trailing blank line | |
819 | 123 if empty |
1190 | 124 silent $delete _ |
125 1 | |
819 | 126 endif |
1190 | 127 " delete the temp file and the used buffers |
128 call delete(tmp) | |
1592 | 129 silent! exe "bwipe " . tmp_esc |
130 silent! exe "bwipe " . tmpe_esc | |
446 | 131 endif |
6336 | 132 " Store the OK flag, so that we can use it when writing. |
133 let b:uncompressOk = ok | |
446 | 134 |
1190 | 135 " Restore saved option values. |
446 | 136 let &pm = pm_save |
137 let &cpo = cpo_save | |
138 let &l:ma = ma_save | |
10244
876fbdd84e52
commit https://github.com/vim/vim/commit/2ec618c9feac4573b154510236ad8121c77d0eca
Christian Brabandt <cb@256bit.org>
parents:
6336
diff
changeset
|
139 let &write = write_save |
1190 | 140 if has("folding") |
141 let &l:fen = fen_save | |
142 endif | |
143 | |
446 | 144 " When uncompressed the whole buffer, do autocommands |
1190 | 145 if ok && empty |
1592 | 146 if exists('*fnameescape') |
147 let fname = fnameescape(expand("%:r")) | |
148 else | |
149 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<") | |
150 endif | |
446 | 151 if &verbose >= 8 |
1592 | 152 execute "doau BufReadPost " . fname |
446 | 153 else |
1592 | 154 execute "silent! doau BufReadPost " . fname |
446 | 155 endif |
156 endif | |
157 endfun | |
158 | |
159 " After writing compressed file: Compress written file with "cmd" | |
160 fun gzip#write(cmd) | |
6336 | 161 if exists('b:uncompressOk') && !b:uncompressOk |
162 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway" | |
446 | 163 " don't do anything if the cmd is not supported |
6336 | 164 elseif s:check(a:cmd) |
446 | 165 " Rename the file before compressing it. |
166 let nm = resolve(expand("<afile>")) | |
167 let nmt = s:tempname(nm) | |
168 if rename(nm, nmt) == 0 | |
169 if exists("b:gzip_comp_arg") | |
1668 | 170 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt)) |
446 | 171 else |
1668 | 172 call system(a:cmd . " -- " . s:escape(nmt)) |
446 | 173 endif |
174 call rename(nmt . "." . expand("<afile>:e"), nm) | |
175 endif | |
176 endif | |
177 endfun | |
178 | |
179 " Before appending to compressed file: Uncompress file with "cmd" | |
180 fun gzip#appre(cmd) | |
181 " don't do anything if the cmd is not supported | |
182 if s:check(a:cmd) | |
183 let nm = expand("<afile>") | |
184 | |
185 " for gzip check current compression level and set b:gzip_comp_arg. | |
186 silent! unlet b:gzip_comp_arg | |
187 if a:cmd[0] == 'g' | |
188 call s:set_compression(readfile(nm, "b", 1)[0]) | |
189 endif | |
190 | |
191 " Rename to a weird name to avoid the risk of overwriting another file | |
192 let nmt = expand("<afile>:p:h") . "/X~=@l9q5" | |
193 let nmte = nmt . "." . expand("<afile>:e") | |
194 if rename(nm, nmte) == 0 | |
195 if &patchmode != "" && getfsize(nm . &patchmode) == -1 | |
196 " Create patchmode file by creating the decompressed file new | |
1668 | 197 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt)) |
446 | 198 call rename(nmte, nm . &patchmode) |
199 else | |
1668 | 200 call system(a:cmd . " -- " . s:escape(nmte)) |
446 | 201 endif |
202 call rename(nmt, nm) | |
203 endif | |
204 endif | |
205 endfun | |
206 | |
207 " find a file name for the file to be compressed. Use "name" without an | |
208 " extension if possible. Otherwise use a weird name to avoid overwriting an | |
209 " existing file. | |
210 fun s:tempname(name) | |
211 let fn = fnamemodify(a:name, ":r") | |
212 if !filereadable(fn) && !isdirectory(fn) | |
213 return fn | |
214 endif | |
215 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5" | |
216 endfun | |
217 | |
985 | 218 fun s:escape(name) |
219 " shellescape() was added by patch 7.0.111 | |
1132 | 220 if exists("*shellescape") |
985 | 221 return shellescape(a:name) |
222 endif | |
223 return "'" . a:name . "'" | |
224 endfun | |
225 | |
446 | 226 " vim: set sw=2 : |