diff options
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2025-27614-CVE-2025-27613-CVE-2025-46334-CVE-2025-46835.patch | 2500 | ||||
-rw-r--r-- | meta/recipes-devtools/git/git_2.35.7.bb | 1 |
2 files changed, 2501 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/git/CVE-2025-27614-CVE-2025-27613-CVE-2025-46334-CVE-2025-46835.patch b/meta/recipes-devtools/git/git/CVE-2025-27614-CVE-2025-27613-CVE-2025-46334-CVE-2025-46835.patch new file mode 100644 index 0000000000..e08bf41b3c --- /dev/null +++ b/meta/recipes-devtools/git/git/CVE-2025-27614-CVE-2025-27613-CVE-2025-46334-CVE-2025-46835.patch | |||
@@ -0,0 +1,2500 @@ | |||
1 | From: d61cfed2c23705fbeb9c0d08f59e75ee08738950 Merge: 664d4fa692 311d9ada3a | ||
2 | Author: Taylor Blau <me@ttaylorr.com> | ||
3 | Date: Fri May 23 17:17:06 2025 -0400 | ||
4 | |||
5 | Merge branch 'js/gitk-git-gui-harden-exec-open' into maint-2.43 | ||
6 | |||
7 | This merges in fixes for CVE-2025-27614, CVE-2025-27613, CVE-2025-46334, | ||
8 | and CVE-2025-46835 targeting Gitk and Git GUI. | ||
9 | |||
10 | * js/gitk-git-gui-harden-exec-open: (41 commits) | ||
11 | git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls | ||
12 | git-gui: do not mistake command arguments as redirection operators | ||
13 | git-gui: introduce function git_redir for git calls with redirections | ||
14 | git-gui: pass redirections as separate argument to git_read | ||
15 | git-gui: pass redirections as separate argument to _open_stdout_stderr | ||
16 | git-gui: convert git_read*, git_write to be non-variadic | ||
17 | git-gui: override exec and open only on Windows | ||
18 | gitk: sanitize 'open' arguments: revisit recently updated 'open' calls | ||
19 | git-gui: use git_read in githook_read | ||
20 | git-gui: sanitize $PATH on all platforms | ||
21 | git-gui: break out a separate function git_read_nice | ||
22 | git-gui: assure PATH has only absolute elements. | ||
23 | git-gui: remove option --stderr from git_read | ||
24 | git-gui: cleanup git-bash menu item | ||
25 | git-gui: sanitize 'exec' arguments: background | ||
26 | git-gui: avoid auto_execok in do_windows_shortcut | ||
27 | git-gui: sanitize 'exec' arguments: simple cases | ||
28 | git-gui: avoid auto_execok for git-bash menu item | ||
29 | git-gui: treat file names beginning with "|" as relative paths | ||
30 | git-gui: remove unused proc is_shellscript | ||
31 | git-gui: remove git config --list handling for git < 1.5.3 | ||
32 | git-gui: remove special treatment of Windows from open_cmd_pipe | ||
33 | git-gui: remove HEAD detachment implementation for git < 1.5.3 | ||
34 | git-gui: use only the configured shell | ||
35 | git-gui: remove Tcl 8.4 workaround on 2>@1 redirection | ||
36 | git-gui: make _shellpath usable on startup | ||
37 | git-gui: use [is_Windows], not bad _shellpath | ||
38 | git-gui: _which, only add .exe suffix if not present | ||
39 | gitk: encode arguments correctly with "open" | ||
40 | gitk: sanitize 'open' arguments: command pipeline | ||
41 | gitk: collect construction of blameargs into a single conditional | ||
42 | gitk: sanitize 'open' arguments: simple commands, readable and writable | ||
43 | gitk: sanitize 'open' arguments: simple commands with redirections | ||
44 | gitk: sanitize 'open' arguments: simple commands | ||
45 | gitk: sanitize 'exec' arguments: redirect to process | ||
46 | gitk: sanitize 'exec' arguments: redirections and background | ||
47 | gitk: sanitize 'exec' arguments: redirections | ||
48 | gitk: sanitize 'exec' arguments: 'eval exec' | ||
49 | gitk: sanitize 'exec' arguments: simple cases | ||
50 | gitk: have callers of diffcmd supply pipe symbol when necessary | ||
51 | gitk: treat file names beginning with "|" as relative paths | ||
52 | ... | ||
53 | |||
54 | Signed-off-by: Taylor Blau <me@ttaylorr.com> | ||
55 | |||
56 | Upstream-Status: Backport from [https://github.com/git/git/commit/d61cfed2c23705fbeb9c0d08f59e75ee08738950] | ||
57 | CVE: CVE-2025-27614, CVE-2025-27613, CVE-2025-46334, CVE-2025-46835 | ||
58 | Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> | ||
59 | --- | ||
60 | git-gui/git-gui.sh | 622 +++++++++++++++++---------- | ||
61 | git-gui/lib/blame.tcl | 12 +- | ||
62 | git-gui/lib/branch.tcl | 6 +- | ||
63 | git-gui/lib/browser.tcl | 2 +- | ||
64 | git-gui/lib/checkout_op.tcl | 25 +- | ||
65 | git-gui/lib/choose_repository.tcl | 23 +- | ||
66 | git-gui/lib/choose_rev.tcl | 8 +- | ||
67 | git-gui/lib/commit.tcl | 14 +- | ||
68 | git-gui/lib/console.tcl | 5 +- | ||
69 | git-gui/lib/database.tcl | 2 +- | ||
70 | git-gui/lib/diff.tcl | 12 +- | ||
71 | git-gui/lib/index.tcl | 8 +- | ||
72 | git-gui/lib/merge.tcl | 6 +- | ||
73 | git-gui/lib/mergetool.tcl | 8 +- | ||
74 | git-gui/lib/remote.tcl | 8 +- | ||
75 | git-gui/lib/remote_branch_delete.tcl | 2 +- | ||
76 | git-gui/lib/shortcut.tcl | 16 +- | ||
77 | git-gui/lib/sshkey.tcl | 7 +- | ||
78 | git-gui/lib/tools.tcl | 7 +- | ||
79 | git-gui/lib/win32.tcl | 9 +- | ||
80 | gitk-git/gitk | 298 ++++++++----- | ||
81 | 21 files changed, 667 insertions(+), 433 deletions(-) | ||
82 | |||
83 | diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh | ||
84 | index 201524c..2f38291 100755 | ||
85 | --- a/git-gui/git-gui.sh | ||
86 | +++ b/git-gui/git-gui.sh | ||
87 | @@ -24,7 +24,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
88 | GNU General Public License for more details. | ||
89 | |||
90 | You should have received a copy of the GNU General Public License | ||
91 | -along with this program; if not, see <http://www.gnu.org/licenses/>.}] | ||
92 | +along with this program; if not, see <https://www.gnu.org/licenses/>.}] | ||
93 | |||
94 | ###################################################################### | ||
95 | ## | ||
96 | @@ -44,6 +44,211 @@ if {[catch {package require Tcl 8.5} err] | ||
97 | |||
98 | catch {rename send {}} ; # What an evil concept... | ||
99 | |||
100 | +###################################################################### | ||
101 | +## | ||
102 | +## Enabling platform-specific code paths | ||
103 | + | ||
104 | +proc is_MacOSX {} { | ||
105 | + if {[tk windowingsystem] eq {aqua}} { | ||
106 | + return 1 | ||
107 | + } | ||
108 | + return 0 | ||
109 | +} | ||
110 | + | ||
111 | +proc is_Windows {} { | ||
112 | + if {$::tcl_platform(platform) eq {windows}} { | ||
113 | + return 1 | ||
114 | + } | ||
115 | + return 0 | ||
116 | +} | ||
117 | + | ||
118 | +set _iscygwin {} | ||
119 | +proc is_Cygwin {} { | ||
120 | + global _iscygwin | ||
121 | + if {$_iscygwin eq {}} { | ||
122 | + if {[string match "CYGWIN_*" $::tcl_platform(os)]} { | ||
123 | + set _iscygwin 1 | ||
124 | + } else { | ||
125 | + set _iscygwin 0 | ||
126 | + } | ||
127 | + } | ||
128 | + return $_iscygwin | ||
129 | +} | ||
130 | + | ||
131 | +###################################################################### | ||
132 | +## | ||
133 | +## PATH lookup. Sanitize $PATH, assure exec/open use only that | ||
134 | + | ||
135 | +if {[is_Windows]} { | ||
136 | + set _path_sep {;} | ||
137 | + set _search_exe .exe | ||
138 | +} else { | ||
139 | + set _path_sep {:} | ||
140 | + set _search_exe {} | ||
141 | +} | ||
142 | + | ||
143 | +if {[is_Windows]} { | ||
144 | + set gitguidir [file dirname [info script]] | ||
145 | + regsub -all ";" $gitguidir "\\;" gitguidir | ||
146 | + set env(PATH) "$gitguidir;$env(PATH)" | ||
147 | +} | ||
148 | + | ||
149 | +set _search_path {} | ||
150 | +set _path_seen [dict create] | ||
151 | +foreach p [split $env(PATH) $_path_sep] { | ||
152 | + # Keep only absolute paths, getting rid of ., empty, etc. | ||
153 | + if {[file pathtype $p] ne {absolute}} { | ||
154 | + continue | ||
155 | + } | ||
156 | + # Keep only the first occurence of any duplicates. | ||
157 | + set norm_p [file normalize $p] | ||
158 | + if {[dict exists $_path_seen $norm_p]} { | ||
159 | + continue | ||
160 | + } | ||
161 | + dict set _path_seen $norm_p 1 | ||
162 | + lappend _search_path $norm_p | ||
163 | +} | ||
164 | +unset _path_seen | ||
165 | + | ||
166 | +set env(PATH) [join $_search_path $_path_sep] | ||
167 | + | ||
168 | +if {[is_Windows]} { | ||
169 | + proc _which {what args} { | ||
170 | + global _search_exe _search_path | ||
171 | + | ||
172 | + if {[lsearch -exact $args -script] >= 0} { | ||
173 | + set suffix {} | ||
174 | + } elseif {[string match *$_search_exe [string tolower $what]]} { | ||
175 | + # The search string already has the file extension | ||
176 | + set suffix {} | ||
177 | + } else { | ||
178 | + set suffix $_search_exe | ||
179 | + } | ||
180 | + | ||
181 | + foreach p $_search_path { | ||
182 | + set p [file join $p $what$suffix] | ||
183 | + if {[file exists $p]} { | ||
184 | + return [file normalize $p] | ||
185 | + } | ||
186 | + } | ||
187 | + return {} | ||
188 | + } | ||
189 | + | ||
190 | + proc sanitize_command_line {command_line from_index} { | ||
191 | + set i $from_index | ||
192 | + while {$i < [llength $command_line]} { | ||
193 | + set cmd [lindex $command_line $i] | ||
194 | + if {[llength [file split $cmd]] < 2} { | ||
195 | + set fullpath [_which $cmd] | ||
196 | + if {$fullpath eq ""} { | ||
197 | + throw {NOT-FOUND} "$cmd not found in PATH" | ||
198 | + } | ||
199 | + lset command_line $i $fullpath | ||
200 | + } | ||
201 | + | ||
202 | + # handle piped commands, e.g. `exec A | B` | ||
203 | + for {incr i} {$i < [llength $command_line]} {incr i} { | ||
204 | + if {[lindex $command_line $i] eq "|"} { | ||
205 | + incr i | ||
206 | + break | ||
207 | + } | ||
208 | + } | ||
209 | + } | ||
210 | + return $command_line | ||
211 | + } | ||
212 | + | ||
213 | + # Override `exec` to avoid unsafe PATH lookup | ||
214 | + | ||
215 | + rename exec real_exec | ||
216 | + | ||
217 | + proc exec {args} { | ||
218 | + # skip options | ||
219 | + for {set i 0} {$i < [llength $args]} {incr i} { | ||
220 | + set arg [lindex $args $i] | ||
221 | + if {$arg eq "--"} { | ||
222 | + incr i | ||
223 | + break | ||
224 | + } | ||
225 | + if {[string range $arg 0 0] ne "-"} { | ||
226 | + break | ||
227 | + } | ||
228 | + } | ||
229 | + set args [sanitize_command_line $args $i] | ||
230 | + uplevel 1 real_exec $args | ||
231 | + } | ||
232 | + | ||
233 | + # Override `open` to avoid unsafe PATH lookup | ||
234 | + | ||
235 | + rename open real_open | ||
236 | + | ||
237 | + proc open {args} { | ||
238 | + set arg0 [lindex $args 0] | ||
239 | + if {[string range $arg0 0 0] eq "|"} { | ||
240 | + set command_line [string trim [string range $arg0 1 end]] | ||
241 | + lset args 0 "| [sanitize_command_line $command_line 0]" | ||
242 | + } | ||
243 | + uplevel 1 real_open $args | ||
244 | + } | ||
245 | + | ||
246 | +} else { | ||
247 | + # On non-Windows platforms, auto_execok, exec, and open are safe, and will | ||
248 | + # use the sanitized search path. But, we need _which for these. | ||
249 | + | ||
250 | + proc _which {what args} { | ||
251 | + return [lindex [auto_execok $what] 0] | ||
252 | + } | ||
253 | +} | ||
254 | + | ||
255 | +# Wrap exec/open to sanitize arguments | ||
256 | + | ||
257 | +# unsafe arguments begin with redirections or the pipe or background operators | ||
258 | +proc is_arg_unsafe {arg} { | ||
259 | + regexp {^([<|>&]|2>)} $arg | ||
260 | +} | ||
261 | + | ||
262 | +proc make_arg_safe {arg} { | ||
263 | + if {[is_arg_unsafe $arg]} { | ||
264 | + set arg [file join . $arg] | ||
265 | + } | ||
266 | + return $arg | ||
267 | +} | ||
268 | + | ||
269 | +proc make_arglist_safe {arglist} { | ||
270 | + set res {} | ||
271 | + foreach arg $arglist { | ||
272 | + lappend res [make_arg_safe $arg] | ||
273 | + } | ||
274 | + return $res | ||
275 | +} | ||
276 | + | ||
277 | +# executes one command | ||
278 | +# no redirections or pipelines are possible | ||
279 | +# cmd is a list that specifies the command and its arguments | ||
280 | +# calls `exec` and returns its value | ||
281 | +proc safe_exec {cmd} { | ||
282 | + eval exec [make_arglist_safe $cmd] | ||
283 | +} | ||
284 | + | ||
285 | +# executes one command in the background | ||
286 | +# no redirections or pipelines are possible | ||
287 | +# cmd is a list that specifies the command and its arguments | ||
288 | +# calls `exec` and returns its value | ||
289 | +proc safe_exec_bg {cmd} { | ||
290 | + eval exec [make_arglist_safe $cmd] & | ||
291 | +} | ||
292 | + | ||
293 | +proc safe_open_file {filename flags} { | ||
294 | + # a file name starting with "|" would attempt to run a process | ||
295 | + # but such a file name must be treated as a relative path | ||
296 | + # hide the "|" behind "./" | ||
297 | + if {[string index $filename 0] eq "|"} { | ||
298 | + set filename [file join . $filename] | ||
299 | + } | ||
300 | + open $filename $flags | ||
301 | +} | ||
302 | + | ||
303 | +# End exec/open wrappers | ||
304 | + | ||
305 | ###################################################################### | ||
306 | ## | ||
307 | ## locate our library | ||
308 | @@ -144,14 +349,64 @@ unset oguimsg | ||
309 | |||
310 | if {[tk windowingsystem] eq "aqua"} { | ||
311 | catch { | ||
312 | - exec osascript -e [format { | ||
313 | + safe_exec [list osascript -e [format { | ||
314 | tell application "System Events" | ||
315 | set frontmost of processes whose unix id is %d to true | ||
316 | end tell | ||
317 | - } [pid]] | ||
318 | + } [pid]]] | ||
319 | } | ||
320 | } | ||
321 | |||
322 | +# Wrap exec/open to sanitize arguments | ||
323 | + | ||
324 | +# unsafe arguments begin with redirections or the pipe or background operators | ||
325 | +proc is_arg_unsafe {arg} { | ||
326 | + regexp {^([<|>&]|2>)} $arg | ||
327 | +} | ||
328 | + | ||
329 | +proc make_arg_safe {arg} { | ||
330 | + if {[is_arg_unsafe $arg]} { | ||
331 | + set arg [file join . $arg] | ||
332 | + } | ||
333 | + return $arg | ||
334 | +} | ||
335 | + | ||
336 | +proc make_arglist_safe {arglist} { | ||
337 | + set res {} | ||
338 | + foreach arg $arglist { | ||
339 | + lappend res [make_arg_safe $arg] | ||
340 | + } | ||
341 | + return $res | ||
342 | +} | ||
343 | + | ||
344 | +# executes one command | ||
345 | +# no redirections or pipelines are possible | ||
346 | +# cmd is a list that specifies the command and its arguments | ||
347 | +# calls `exec` and returns its value | ||
348 | +proc safe_exec {cmd} { | ||
349 | + eval exec [make_arglist_safe $cmd] | ||
350 | +} | ||
351 | + | ||
352 | +# executes one command in the background | ||
353 | +# no redirections or pipelines are possible | ||
354 | +# cmd is a list that specifies the command and its arguments | ||
355 | +# calls `exec` and returns its value | ||
356 | +proc safe_exec_bg {cmd} { | ||
357 | + eval exec [make_arglist_safe $cmd] & | ||
358 | +} | ||
359 | + | ||
360 | +proc safe_open_file {filename flags} { | ||
361 | + # a file name starting with "|" would attempt to run a process | ||
362 | + # but such a file name must be treated as a relative path | ||
363 | + # hide the "|" behind "./" | ||
364 | + if {[string index $filename 0] eq "|"} { | ||
365 | + set filename [file join . $filename] | ||
366 | + } | ||
367 | + open $filename $flags | ||
368 | +} | ||
369 | + | ||
370 | +# End exec/open wrappers | ||
371 | + | ||
372 | ###################################################################### | ||
373 | ## | ||
374 | ## read only globals | ||
375 | @@ -180,15 +435,37 @@ if {$_trace >= 0} { | ||
376 | # branches). | ||
377 | set _last_merged_branch {} | ||
378 | |||
379 | -proc shellpath {} { | ||
380 | - global _shellpath env | ||
381 | - if {[string match @@* $_shellpath]} { | ||
382 | - if {[info exists env(SHELL)]} { | ||
383 | - return $env(SHELL) | ||
384 | - } else { | ||
385 | - return /bin/sh | ||
386 | - } | ||
387 | +# for testing, allow unconfigured _shellpath | ||
388 | +if {[string match @@* $_shellpath]} { | ||
389 | + if {[info exists env(SHELL)]} { | ||
390 | + set _shellpath $env(SHELL) | ||
391 | + } else { | ||
392 | + set _shellpath /bin/sh | ||
393 | } | ||
394 | +} | ||
395 | + | ||
396 | +if {[is_Windows]} { | ||
397 | + set _shellpath [safe_exec [list cygpath -m $_shellpath]] | ||
398 | +} | ||
399 | + | ||
400 | +if {![file executable $_shellpath] || \ | ||
401 | + !([file pathtype $_shellpath] eq {absolute})} { | ||
402 | + set errmsg "The defined shell ('$_shellpath') is not usable, \ | ||
403 | + it must be an absolute path to an executable." | ||
404 | + puts stderr $errmsg | ||
405 | + | ||
406 | + catch {wm withdraw .} | ||
407 | + tk_messageBox \ | ||
408 | + -icon error \ | ||
409 | + -type ok \ | ||
410 | + -title "git-gui: configuration error" \ | ||
411 | + -message $errmsg | ||
412 | + exit 1 | ||
413 | +} | ||
414 | + | ||
415 | + | ||
416 | +proc shellpath {} { | ||
417 | + global _shellpath | ||
418 | return $_shellpath | ||
419 | } | ||
420 | |||
421 | @@ -252,40 +529,6 @@ proc reponame {} { | ||
422 | return $::_reponame | ||
423 | } | ||
424 | |||
425 | -proc is_MacOSX {} { | ||
426 | - if {[tk windowingsystem] eq {aqua}} { | ||
427 | - return 1 | ||
428 | - } | ||
429 | - return 0 | ||
430 | -} | ||
431 | - | ||
432 | -proc is_Windows {} { | ||
433 | - if {$::tcl_platform(platform) eq {windows}} { | ||
434 | - return 1 | ||
435 | - } | ||
436 | - return 0 | ||
437 | -} | ||
438 | - | ||
439 | -proc is_Cygwin {} { | ||
440 | - global _iscygwin | ||
441 | - if {$_iscygwin eq {}} { | ||
442 | - if {$::tcl_platform(platform) eq {windows}} { | ||
443 | - if {[catch {set p [exec cygpath --windir]} err]} { | ||
444 | - set _iscygwin 0 | ||
445 | - } else { | ||
446 | - set _iscygwin 1 | ||
447 | - # Handle MSys2 which is only cygwin when MSYSTEM is MSYS. | ||
448 | - if {[info exists ::env(MSYSTEM)] && $::env(MSYSTEM) ne "MSYS"} { | ||
449 | - set _iscygwin 0 | ||
450 | - } | ||
451 | - } | ||
452 | - } else { | ||
453 | - set _iscygwin 0 | ||
454 | - } | ||
455 | - } | ||
456 | - return $_iscygwin | ||
457 | -} | ||
458 | - | ||
459 | proc is_enabled {option} { | ||
460 | global enabled_options | ||
461 | if {[catch {set on $enabled_options($option)}]} {return 0} | ||
462 | @@ -418,7 +661,7 @@ proc _git_cmd {name} { | ||
463 | # Tcl on Windows doesn't know it. | ||
464 | # | ||
465 | set p [gitexec git-$name] | ||
466 | - set f [open $p r] | ||
467 | + set f [safe_open_file $p r] | ||
468 | set s [gets $f] | ||
469 | close $f | ||
470 | |||
471 | @@ -473,6 +716,9 @@ proc _which {what args} { | ||
472 | |||
473 | if {[is_Windows] && [lsearch -exact $args -script] >= 0} { | ||
474 | set suffix {} | ||
475 | + } elseif {[is_Windows] && [string match *$_search_exe [string tolower $what]]} { | ||
476 | + # The search string already has the file extension | ||
477 | + set suffix {} | ||
478 | } else { | ||
479 | set suffix $_search_exe | ||
480 | } | ||
481 | @@ -486,32 +732,14 @@ proc _which {what args} { | ||
482 | return {} | ||
483 | } | ||
484 | |||
485 | -# Test a file for a hashbang to identify executable scripts on Windows. | ||
486 | -proc is_shellscript {filename} { | ||
487 | - if {![file exists $filename]} {return 0} | ||
488 | - set f [open $filename r] | ||
489 | - fconfigure $f -encoding binary | ||
490 | - set magic [read $f 2] | ||
491 | - close $f | ||
492 | - return [expr {$magic eq "#!"}] | ||
493 | -} | ||
494 | - | ||
495 | -# Run a command connected via pipes on stdout. | ||
496 | +# Run a shell command connected via pipes on stdout. | ||
497 | # This is for use with textconv filters and uses sh -c "..." to allow it to | ||
498 | -# contain a command with arguments. On windows we must check for shell | ||
499 | -# scripts specifically otherwise just call the filter command. | ||
500 | +# contain a command with arguments. We presume this | ||
501 | +# to be a shellscript that the configured shell (/bin/sh by default) knows | ||
502 | +# how to run. | ||
503 | proc open_cmd_pipe {cmd path} { | ||
504 | - global env | ||
505 | - if {![file executable [shellpath]]} { | ||
506 | - set exe [auto_execok [lindex $cmd 0]] | ||
507 | - if {[is_shellscript [lindex $exe 0]]} { | ||
508 | - set run [linsert [auto_execok sh] end -c "$cmd \"\$0\"" $path] | ||
509 | - } else { | ||
510 | - set run [concat $exe [lrange $cmd 1 end] $path] | ||
511 | - } | ||
512 | - } else { | ||
513 | - set run [list [shellpath] -c "$cmd \"\$0\"" $path] | ||
514 | - } | ||
515 | + set run [list [shellpath] -c "$cmd \"\$0\"" $path] | ||
516 | + set run [make_arglist_safe $run] | ||
517 | return [open |$run r] | ||
518 | } | ||
519 | |||
520 | @@ -521,7 +749,7 @@ proc _lappend_nice {cmd_var} { | ||
521 | |||
522 | if {![info exists _nice]} { | ||
523 | set _nice [_which nice] | ||
524 | - if {[catch {exec $_nice git version}]} { | ||
525 | + if {[catch {safe_exec [list $_nice git version]}]} { | ||
526 | set _nice {} | ||
527 | } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { | ||
528 | set _nice {} | ||
529 | @@ -533,7 +761,11 @@ proc _lappend_nice {cmd_var} { | ||
530 | } | ||
531 | |||
532 | proc git {args} { | ||
533 | - set fd [eval [list git_read] $args] | ||
534 | + git_redir $args {} | ||
535 | +} | ||
536 | + | ||
537 | +proc git_redir {cmd redir} { | ||
538 | + set fd [git_read $cmd $redir] | ||
539 | fconfigure $fd -translation binary -encoding utf-8 | ||
540 | set result [string trimright [read $fd] "\n"] | ||
541 | close $fd | ||
542 | @@ -543,111 +775,47 @@ proc git {args} { | ||
543 | return $result | ||
544 | } | ||
545 | |||
546 | -proc _open_stdout_stderr {cmd} { | ||
547 | - _trace_exec $cmd | ||
548 | +proc safe_open_command {cmd {redir {}}} { | ||
549 | + set cmd [make_arglist_safe $cmd] | ||
550 | + _trace_exec [concat $cmd $redir] | ||
551 | if {[catch { | ||
552 | - set fd [open [concat [list | ] $cmd] r] | ||
553 | - } err]} { | ||
554 | - if { [lindex $cmd end] eq {2>@1} | ||
555 | - && $err eq {can not find channel named "1"} | ||
556 | - } { | ||
557 | - # Older versions of Tcl 8.4 don't have this 2>@1 IO | ||
558 | - # redirect operator. Fallback to |& cat for those. | ||
559 | - # The command was not actually started, so its safe | ||
560 | - # to try to start it a second time. | ||
561 | - # | ||
562 | - set fd [open [concat \ | ||
563 | - [list | ] \ | ||
564 | - [lrange $cmd 0 end-1] \ | ||
565 | - [list |& cat] \ | ||
566 | - ] r] | ||
567 | - } else { | ||
568 | - error $err | ||
569 | - } | ||
570 | + set fd [open [concat [list | ] $cmd $redir] r] | ||
571 | + } err]} { | ||
572 | + error $err | ||
573 | } | ||
574 | fconfigure $fd -eofchar {} | ||
575 | return $fd | ||
576 | } | ||
577 | |||
578 | -proc git_read {args} { | ||
579 | - set opt [list] | ||
580 | - | ||
581 | - while {1} { | ||
582 | - switch -- [lindex $args 0] { | ||
583 | - --nice { | ||
584 | - _lappend_nice opt | ||
585 | - } | ||
586 | - | ||
587 | - --stderr { | ||
588 | - lappend args 2>@1 | ||
589 | - } | ||
590 | +proc git_read {cmd {redir {}}} { | ||
591 | + set cmdp [_git_cmd [lindex $cmd 0]] | ||
592 | + set cmd [lrange $cmd 1 end] | ||
593 | |||
594 | - default { | ||
595 | - break | ||
596 | - } | ||
597 | - | ||
598 | - } | ||
599 | - | ||
600 | - set args [lrange $args 1 end] | ||
601 | - } | ||
602 | - | ||
603 | - set cmdp [_git_cmd [lindex $args 0]] | ||
604 | - set args [lrange $args 1 end] | ||
605 | - | ||
606 | - return [_open_stdout_stderr [concat $opt $cmdp $args]] | ||
607 | + return [safe_open_command [concat $cmdp $cmd] $redir] | ||
608 | } | ||
609 | |||
610 | -proc git_write {args} { | ||
611 | +proc git_read_nice {cmd} { | ||
612 | set opt [list] | ||
613 | |||
614 | - while {1} { | ||
615 | - switch -- [lindex $args 0] { | ||
616 | - --nice { | ||
617 | - _lappend_nice opt | ||
618 | - } | ||
619 | + _lappend_nice opt | ||
620 | |||
621 | - default { | ||
622 | - break | ||
623 | - } | ||
624 | + set cmdp [_git_cmd [lindex $cmd 0]] | ||
625 | + set cmd [lrange $cmd 1 end] | ||
626 | |||
627 | - } | ||
628 | - | ||
629 | - set args [lrange $args 1 end] | ||
630 | - } | ||
631 | + return [safe_open_command [concat $opt $cmdp $cmd]] | ||
632 | +} | ||
633 | |||
634 | - set cmdp [_git_cmd [lindex $args 0]] | ||
635 | - set args [lrange $args 1 end] | ||
636 | +proc git_write {cmd} { | ||
637 | + set cmd [make_arglist_safe $cmd] | ||
638 | + set cmdp [_git_cmd [lindex $cmd 0]] | ||
639 | + set cmd [lrange $cmd 1 end] | ||
640 | |||
641 | - _trace_exec [concat $opt $cmdp $args] | ||
642 | - return [open [concat [list | ] $opt $cmdp $args] w] | ||
643 | + _trace_exec [concat $cmdp $cmd] | ||
644 | + return [open [concat [list | ] $cmdp $cmd] w] | ||
645 | } | ||
646 | |||
647 | proc githook_read {hook_name args} { | ||
648 | - set pchook [gitdir hooks $hook_name] | ||
649 | - lappend args 2>@1 | ||
650 | - | ||
651 | - # On Windows [file executable] might lie so we need to ask | ||
652 | - # the shell if the hook is executable. Yes that's annoying. | ||
653 | - # | ||
654 | - if {[is_Windows]} { | ||
655 | - upvar #0 _sh interp | ||
656 | - if {![info exists interp]} { | ||
657 | - set interp [_which sh] | ||
658 | - } | ||
659 | - if {$interp eq {}} { | ||
660 | - error "hook execution requires sh (not in PATH)" | ||
661 | - } | ||
662 | - | ||
663 | - set scr {if test -x "$1";then exec "$@";fi} | ||
664 | - set sh_c [list $interp -c $scr $interp $pchook] | ||
665 | - return [_open_stdout_stderr [concat $sh_c $args]] | ||
666 | - } | ||
667 | - | ||
668 | - if {[file executable $pchook]} { | ||
669 | - return [_open_stdout_stderr [concat [list $pchook] $args]] | ||
670 | - } | ||
671 | - | ||
672 | - return {} | ||
673 | + git_read [concat [list hook run --ignore-missing $hook_name --] $args] [list 2>@1] | ||
674 | } | ||
675 | |||
676 | proc kill_file_process {fd} { | ||
677 | @@ -655,9 +823,9 @@ proc kill_file_process {fd} { | ||
678 | |||
679 | catch { | ||
680 | if {[is_Windows]} { | ||
681 | - exec taskkill /pid $process | ||
682 | + safe_exec [list taskkill /pid $process] | ||
683 | } else { | ||
684 | - exec kill $process | ||
685 | + safe_exec [list kill $process] | ||
686 | } | ||
687 | } | ||
688 | } | ||
689 | @@ -683,7 +851,7 @@ proc sq {value} { | ||
690 | proc load_current_branch {} { | ||
691 | global current_branch is_detached | ||
692 | |||
693 | - set fd [open [gitdir HEAD] r] | ||
694 | + set fd [safe_open_file [gitdir HEAD] r] | ||
695 | fconfigure $fd -translation binary -encoding utf-8 | ||
696 | if {[gets $fd ref] < 1} { | ||
697 | set ref {} | ||
698 | @@ -1045,7 +1213,7 @@ You are using [git-version]: | ||
699 | ## configure our library | ||
700 | |||
701 | set idx [file join $oguilib tclIndex] | ||
702 | -if {[catch {set fd [open $idx r]} err]} { | ||
703 | +if {[catch {set fd [safe_open_file $idx r]} err]} { | ||
704 | catch {wm withdraw .} | ||
705 | tk_messageBox \ | ||
706 | -icon error \ | ||
707 | @@ -1083,53 +1251,30 @@ unset -nocomplain idx fd | ||
708 | ## | ||
709 | ## config file parsing | ||
710 | |||
711 | -git-version proc _parse_config {arr_name args} { | ||
712 | - >= 1.5.3 { | ||
713 | - upvar $arr_name arr | ||
714 | - array unset arr | ||
715 | - set buf {} | ||
716 | - catch { | ||
717 | - set fd_rc [eval \ | ||
718 | - [list git_read config] \ | ||
719 | - $args \ | ||
720 | - [list --null --list]] | ||
721 | - fconfigure $fd_rc -translation binary -encoding utf-8 | ||
722 | - set buf [read $fd_rc] | ||
723 | - close $fd_rc | ||
724 | - } | ||
725 | - foreach line [split $buf "\0"] { | ||
726 | - if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { | ||
727 | - if {[is_many_config $name]} { | ||
728 | - lappend arr($name) $value | ||
729 | - } else { | ||
730 | - set arr($name) $value | ||
731 | - } | ||
732 | - } elseif {[regexp {^([^\n]+)$} $line line name]} { | ||
733 | - # no value given, but interpreting them as | ||
734 | - # boolean will be handled as true | ||
735 | - set arr($name) {} | ||
736 | - } | ||
737 | - } | ||
738 | - } | ||
739 | - default { | ||
740 | - upvar $arr_name arr | ||
741 | - array unset arr | ||
742 | - catch { | ||
743 | - set fd_rc [eval [list git_read config --list] $args] | ||
744 | - while {[gets $fd_rc line] >= 0} { | ||
745 | - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { | ||
746 | - if {[is_many_config $name]} { | ||
747 | - lappend arr($name) $value | ||
748 | - } else { | ||
749 | - set arr($name) $value | ||
750 | - } | ||
751 | - } elseif {[regexp {^([^=]+)$} $line line name]} { | ||
752 | - # no value given, but interpreting them as | ||
753 | - # boolean will be handled as true | ||
754 | - set arr($name) {} | ||
755 | - } | ||
756 | +proc _parse_config {arr_name args} { | ||
757 | + upvar $arr_name arr | ||
758 | + array unset arr | ||
759 | + set buf {} | ||
760 | + catch { | ||
761 | + set fd_rc [git_read \ | ||
762 | + [concat config \ | ||
763 | + $args \ | ||
764 | + --null --list]] | ||
765 | + fconfigure $fd_rc -translation binary -encoding utf-8 | ||
766 | + set buf [read $fd_rc] | ||
767 | + close $fd_rc | ||
768 | + } | ||
769 | + foreach line [split $buf "\0"] { | ||
770 | + if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { | ||
771 | + if {[is_many_config $name]} { | ||
772 | + lappend arr($name) $value | ||
773 | + } else { | ||
774 | + set arr($name) $value | ||
775 | } | ||
776 | - close $fd_rc | ||
777 | + } elseif {[regexp {^([^\n]+)$} $line line name]} { | ||
778 | + # no value given, but interpreting them as | ||
779 | + # boolean will be handled as true | ||
780 | + set arr($name) {} | ||
781 | } | ||
782 | } | ||
783 | } | ||
784 | @@ -1412,7 +1557,7 @@ proc repository_state {ctvar hdvar mhvar} { | ||
785 | set merge_head [gitdir MERGE_HEAD] | ||
786 | if {[file exists $merge_head]} { | ||
787 | set ct merge | ||
788 | - set fd_mh [open $merge_head r] | ||
789 | + set fd_mh [safe_open_file $merge_head r] | ||
790 | while {[gets $fd_mh line] >= 0} { | ||
791 | lappend mh $line | ||
792 | } | ||
793 | @@ -1431,7 +1576,7 @@ proc PARENT {} { | ||
794 | return $p | ||
795 | } | ||
796 | if {$empty_tree eq {}} { | ||
797 | - set empty_tree [git mktree << {}] | ||
798 | + set empty_tree [git_redir [list mktree] [list << {}]] | ||
799 | } | ||
800 | return $empty_tree | ||
801 | } | ||
802 | @@ -1490,12 +1635,12 @@ proc rescan {after {honor_trustmtime 1}} { | ||
803 | } else { | ||
804 | set rescan_active 1 | ||
805 | ui_status [mc "Refreshing file status..."] | ||
806 | - set fd_rf [git_read update-index \ | ||
807 | + set fd_rf [git_read [list update-index \ | ||
808 | -q \ | ||
809 | --unmerged \ | ||
810 | --ignore-missing \ | ||
811 | --refresh \ | ||
812 | - ] | ||
813 | + ]] | ||
814 | fconfigure $fd_rf -blocking 0 -translation binary | ||
815 | fileevent $fd_rf readable \ | ||
816 | [list rescan_stage2 $fd_rf $after] | ||
817 | @@ -1551,11 +1696,11 @@ proc rescan_stage2 {fd after} { | ||
818 | set rescan_active 2 | ||
819 | ui_status [mc "Scanning for modified files ..."] | ||
820 | if {[git-version >= "1.7.2"]} { | ||
821 | - set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]] | ||
822 | + set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] | ||
823 | } else { | ||
824 | - set fd_di [git_read diff-index --cached -z [PARENT]] | ||
825 | + set fd_di [git_read [list diff-index --cached -z [PARENT]]] | ||
826 | } | ||
827 | - set fd_df [git_read diff-files -z] | ||
828 | + set fd_df [git_read [list diff-files -z]] | ||
829 | |||
830 | fconfigure $fd_di -blocking 0 -translation binary -encoding binary | ||
831 | fconfigure $fd_df -blocking 0 -translation binary -encoding binary | ||
832 | @@ -1564,7 +1709,7 @@ proc rescan_stage2 {fd after} { | ||
833 | fileevent $fd_df readable [list read_diff_files $fd_df $after] | ||
834 | |||
835 | if {[is_config_true gui.displayuntracked]} { | ||
836 | - set fd_lo [eval git_read ls-files --others -z $ls_others] | ||
837 | + set fd_lo [git_read [concat ls-files --others -z $ls_others]] | ||
838 | fconfigure $fd_lo -blocking 0 -translation binary -encoding binary | ||
839 | fileevent $fd_lo readable [list read_ls_others $fd_lo $after] | ||
840 | incr rescan_active | ||
841 | @@ -1576,7 +1721,7 @@ proc load_message {file {encoding {}}} { | ||
842 | |||
843 | set f [gitdir $file] | ||
844 | if {[file isfile $f]} { | ||
845 | - if {[catch {set fd [open $f r]}]} { | ||
846 | + if {[catch {set fd [safe_open_file $f r]}]} { | ||
847 | return 0 | ||
848 | } | ||
849 | fconfigure $fd -eofchar {} | ||
850 | @@ -1600,23 +1745,23 @@ proc run_prepare_commit_msg_hook {} { | ||
851 | # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an | ||
852 | # empty file but existent file. | ||
853 | |||
854 | - set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] | ||
855 | + set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a] | ||
856 | |||
857 | if {[file isfile [gitdir MERGE_MSG]]} { | ||
858 | set pcm_source "merge" | ||
859 | - set fd_mm [open [gitdir MERGE_MSG] r] | ||
860 | + set fd_mm [safe_open_file [gitdir MERGE_MSG] r] | ||
861 | fconfigure $fd_mm -encoding utf-8 | ||
862 | puts -nonewline $fd_pcm [read $fd_mm] | ||
863 | close $fd_mm | ||
864 | } elseif {[file isfile [gitdir SQUASH_MSG]]} { | ||
865 | set pcm_source "squash" | ||
866 | - set fd_sm [open [gitdir SQUASH_MSG] r] | ||
867 | + set fd_sm [safe_open_file [gitdir SQUASH_MSG] r] | ||
868 | fconfigure $fd_sm -encoding utf-8 | ||
869 | puts -nonewline $fd_pcm [read $fd_sm] | ||
870 | close $fd_sm | ||
871 | } elseif {[file isfile [get_config commit.template]]} { | ||
872 | set pcm_source "template" | ||
873 | - set fd_sm [open [get_config commit.template] r] | ||
874 | + set fd_sm [safe_open_file [get_config commit.template] r] | ||
875 | fconfigure $fd_sm -encoding utf-8 | ||
876 | puts -nonewline $fd_pcm [read $fd_sm] | ||
877 | close $fd_sm | ||
878 | @@ -2206,7 +2351,7 @@ proc do_gitk {revs {is_submodule false}} { | ||
879 | unset env(GIT_DIR) | ||
880 | unset env(GIT_WORK_TREE) | ||
881 | } | ||
882 | - eval exec $cmd $revs "--" "--" & | ||
883 | + safe_exec_bg [concat $cmd $revs "--" "--"] | ||
884 | |||
885 | set env(GIT_DIR) $_gitdir | ||
886 | set env(GIT_WORK_TREE) $_gitworktree | ||
887 | @@ -2243,7 +2388,7 @@ proc do_git_gui {} { | ||
888 | set pwd [pwd] | ||
889 | cd $current_diff_path | ||
890 | |||
891 | - eval exec $exe gui & | ||
892 | + safe_exec_bg [concat $exe gui] | ||
893 | |||
894 | set env(GIT_DIR) $_gitdir | ||
895 | set env(GIT_WORK_TREE) $_gitworktree | ||
896 | @@ -2272,16 +2417,18 @@ proc get_explorer {} { | ||
897 | |||
898 | proc do_explore {} { | ||
899 | global _gitworktree | ||
900 | - set explorer [get_explorer] | ||
901 | - eval exec $explorer [list [file nativename $_gitworktree]] & | ||
902 | + set cmd [get_explorer] | ||
903 | + lappend cmd [file nativename $_gitworktree] | ||
904 | + safe_exec_bg $cmd | ||
905 | } | ||
906 | |||
907 | # Open file relative to the working tree by the default associated app. | ||
908 | proc do_file_open {file} { | ||
909 | global _gitworktree | ||
910 | - set explorer [get_explorer] | ||
911 | + set cmd [get_explorer] | ||
912 | set full_file_path [file join $_gitworktree $file] | ||
913 | - exec $explorer [file nativename $full_file_path] & | ||
914 | + lappend cmd [file nativename $full_file_path] | ||
915 | + safe_exec_bg $cmd | ||
916 | } | ||
917 | |||
918 | set is_quitting 0 | ||
919 | @@ -2315,7 +2462,7 @@ proc do_quit {{rc {1}}} { | ||
920 | if {![string match amend* $commit_type] | ||
921 | && $msg ne {}} { | ||
922 | catch { | ||
923 | - set fd [open $save w] | ||
924 | + set fd [safe_open_file $save w] | ||
925 | fconfigure $fd -encoding utf-8 | ||
926 | puts -nonewline $fd $msg | ||
927 | close $fd | ||
928 | @@ -2373,7 +2520,7 @@ proc do_quit {{rc {1}}} { | ||
929 | set ret_code $rc | ||
930 | |||
931 | # Briefly enable send again, working around Tk bug | ||
932 | - # http://sourceforge.net/tracker/?func=detail&atid=112997&aid=1821174&group_id=12997 | ||
933 | + # https://sourceforge.net/p/tktoolkit/bugs/2343/ | ||
934 | tk appname [appname] | ||
935 | |||
936 | destroy . | ||
937 | @@ -2759,17 +2906,16 @@ if {![is_bare]} { | ||
938 | |||
939 | if {[is_Windows]} { | ||
940 | # Use /git-bash.exe if available | ||
941 | - set normalized [file normalize $::argv0] | ||
942 | - regsub "/mingw../libexec/git-core/git-gui$" \ | ||
943 | - $normalized "/git-bash.exe" cmdLine | ||
944 | - if {$cmdLine != $normalized && [file exists $cmdLine]} { | ||
945 | - set cmdLine [list "Git Bash" $cmdLine &] | ||
946 | + set _git_bash [safe_exec [list cygpath -m /git-bash.exe]] | ||
947 | + if {[file executable $_git_bash]} { | ||
948 | + set _bash_cmdline [list "Git Bash" $_git_bash] | ||
949 | } else { | ||
950 | - set cmdLine [list "Git Bash" bash --login -l &] | ||
951 | + set _bash_cmdline [list "Git Bash" bash --login -l] | ||
952 | } | ||
953 | .mbar.repository add command \ | ||
954 | -label [mc "Git Bash"] \ | ||
955 | - -command {eval exec [auto_execok start] $cmdLine} | ||
956 | + -command {safe_exec_bg [concat [list [_which cmd] /c start] $_bash_cmdline]} | ||
957 | + unset _git_bash | ||
958 | } | ||
959 | |||
960 | if {[is_Windows] || ![is_bare]} { | ||
961 | @@ -4134,7 +4280,7 @@ if {[winfo exists $ui_comm]} { | ||
962 | } | ||
963 | } elseif {$m} { | ||
964 | catch { | ||
965 | - set fd [open [gitdir GITGUI_BCK] w] | ||
966 | + set fd [safe_open_file [gitdir GITGUI_BCK] w] | ||
967 | fconfigure $fd -encoding utf-8 | ||
968 | puts -nonewline $fd $msg | ||
969 | close $fd | ||
970 | diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl | ||
971 | index 8441e10..d6fd8be 100644 | ||
972 | --- a/git-gui/lib/blame.tcl | ||
973 | +++ b/git-gui/lib/blame.tcl | ||
974 | @@ -481,14 +481,14 @@ method _load {jump} { | ||
975 | if {$do_textconv ne 0} { | ||
976 | set fd [open_cmd_pipe $textconv $path] | ||
977 | } else { | ||
978 | - set fd [open $path r] | ||
979 | + set fd [safe_open_file $path r] | ||
980 | } | ||
981 | fconfigure $fd -eofchar {} | ||
982 | } else { | ||
983 | if {$do_textconv ne 0} { | ||
984 | - set fd [git_read cat-file --textconv "$commit:$path"] | ||
985 | + set fd [git_read [list cat-file --textconv "$commit:$path"]] | ||
986 | } else { | ||
987 | - set fd [git_read cat-file blob "$commit:$path"] | ||
988 | + set fd [git_read [list cat-file blob "$commit:$path"]] | ||
989 | } | ||
990 | } | ||
991 | fconfigure $fd \ | ||
992 | @@ -617,7 +617,7 @@ method _exec_blame {cur_w cur_d options cur_s} { | ||
993 | } | ||
994 | |||
995 | lappend options -- $path | ||
996 | - set fd [eval git_read --nice blame $options] | ||
997 | + set fd [git_read_nice [concat blame $options]] | ||
998 | fconfigure $fd -blocking 0 -translation lf -encoding utf-8 | ||
999 | fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] | ||
1000 | set current_fd $fd | ||
1001 | @@ -986,7 +986,7 @@ method _showcommit {cur_w lno} { | ||
1002 | if {[catch {set msg $header($cmit,message)}]} { | ||
1003 | set msg {} | ||
1004 | catch { | ||
1005 | - set fd [git_read cat-file commit $cmit] | ||
1006 | + set fd [git_read [list cat-file commit $cmit]] | ||
1007 | fconfigure $fd -encoding binary -translation lf | ||
1008 | # By default commits are assumed to be in utf-8 | ||
1009 | set enc utf-8 | ||
1010 | @@ -1134,7 +1134,7 @@ method _blameparent {} { | ||
1011 | } else { | ||
1012 | set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] | ||
1013 | } | ||
1014 | - if {[catch {set fd [eval git_read $diffcmd]} err]} { | ||
1015 | + if {[catch {set fd [git_read $diffcmd]} err]} { | ||
1016 | $status_operation stop [mc "Unable to display parent"] | ||
1017 | error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] | ||
1018 | return | ||
1019 | diff --git a/git-gui/lib/branch.tcl b/git-gui/lib/branch.tcl | ||
1020 | index 8b0c485..39e0f2d 100644 | ||
1021 | --- a/git-gui/lib/branch.tcl | ||
1022 | +++ b/git-gui/lib/branch.tcl | ||
1023 | @@ -7,7 +7,7 @@ proc load_all_heads {} { | ||
1024 | set rh refs/heads | ||
1025 | set rh_len [expr {[string length $rh] + 1}] | ||
1026 | set all_heads [list] | ||
1027 | - set fd [git_read for-each-ref --format=%(refname) $rh] | ||
1028 | + set fd [git_read [list for-each-ref --format=%(refname) $rh]] | ||
1029 | fconfigure $fd -translation binary -encoding utf-8 | ||
1030 | while {[gets $fd line] > 0} { | ||
1031 | if {!$some_heads_tracking || ![is_tracking_branch $line]} { | ||
1032 | @@ -21,10 +21,10 @@ proc load_all_heads {} { | ||
1033 | |||
1034 | proc load_all_tags {} { | ||
1035 | set all_tags [list] | ||
1036 | - set fd [git_read for-each-ref \ | ||
1037 | + set fd [git_read [list for-each-ref \ | ||
1038 | --sort=-taggerdate \ | ||
1039 | --format=%(refname) \ | ||
1040 | - refs/tags] | ||
1041 | + refs/tags]] | ||
1042 | fconfigure $fd -translation binary -encoding utf-8 | ||
1043 | while {[gets $fd line] > 0} { | ||
1044 | if {![regsub ^refs/tags/ $line {} name]} continue | ||
1045 | diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl | ||
1046 | index a982983..6fc8d4d 100644 | ||
1047 | --- a/git-gui/lib/browser.tcl | ||
1048 | +++ b/git-gui/lib/browser.tcl | ||
1049 | @@ -196,7 +196,7 @@ method _ls {tree_id {name {}}} { | ||
1050 | lappend browser_stack [list $tree_id $name] | ||
1051 | $w conf -state disabled | ||
1052 | |||
1053 | - set fd [git_read ls-tree -z $tree_id] | ||
1054 | + set fd [git_read [list ls-tree -z $tree_id]] | ||
1055 | fconfigure $fd -blocking 0 -translation binary -encoding utf-8 | ||
1056 | fileevent $fd readable [cb _read $fd] | ||
1057 | } | ||
1058 | diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl | ||
1059 | index 21ea768..87ed0b4 100644 | ||
1060 | --- a/git-gui/lib/checkout_op.tcl | ||
1061 | +++ b/git-gui/lib/checkout_op.tcl | ||
1062 | @@ -304,12 +304,12 @@ The rescan will be automatically started now. | ||
1063 | _readtree $this | ||
1064 | } else { | ||
1065 | ui_status [mc "Refreshing file status..."] | ||
1066 | - set fd [git_read update-index \ | ||
1067 | + set fd [git_read [list update-index \ | ||
1068 | -q \ | ||
1069 | --unmerged \ | ||
1070 | --ignore-missing \ | ||
1071 | --refresh \ | ||
1072 | - ] | ||
1073 | + ]] | ||
1074 | fconfigure $fd -blocking 0 -translation binary | ||
1075 | fileevent $fd readable [cb _refresh_wait $fd] | ||
1076 | } | ||
1077 | @@ -345,14 +345,15 @@ method _readtree {} { | ||
1078 | [mc "Updating working directory to '%s'..." [_name $this]] \ | ||
1079 | [mc "files checked out"]] | ||
1080 | |||
1081 | - set fd [git_read --stderr read-tree \ | ||
1082 | + set fd [git_read [list read-tree \ | ||
1083 | -m \ | ||
1084 | -u \ | ||
1085 | -v \ | ||
1086 | --exclude-per-directory=.gitignore \ | ||
1087 | $HEAD \ | ||
1088 | $new_hash \ | ||
1089 | - ] | ||
1090 | + ] \ | ||
1091 | + [list 2>@1]] | ||
1092 | fconfigure $fd -blocking 0 -translation binary | ||
1093 | fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation] | ||
1094 | } | ||
1095 | @@ -510,18 +511,8 @@ method _update_repo_state {} { | ||
1096 | delete_this | ||
1097 | } | ||
1098 | |||
1099 | -git-version proc _detach_HEAD {log new} { | ||
1100 | - >= 1.5.3 { | ||
1101 | - git update-ref --no-deref -m $log HEAD $new | ||
1102 | - } | ||
1103 | - default { | ||
1104 | - set p [gitdir HEAD] | ||
1105 | - file delete $p | ||
1106 | - set fd [open $p w] | ||
1107 | - fconfigure $fd -translation lf -encoding utf-8 | ||
1108 | - puts $fd $new | ||
1109 | - close $fd | ||
1110 | - } | ||
1111 | +proc _detach_HEAD {log new} { | ||
1112 | + git update-ref --no-deref -m $log HEAD $new | ||
1113 | } | ||
1114 | |||
1115 | method _confirm_reset {cur} { | ||
1116 | @@ -582,7 +573,7 @@ method _confirm_reset {cur} { | ||
1117 | pack $w.buttons.cancel -side right -padx 5 | ||
1118 | pack $w.buttons -side bottom -fill x -pady 10 -padx 10 | ||
1119 | |||
1120 | - set fd [git_read rev-list --pretty=oneline $cur ^$new_hash] | ||
1121 | + set fd [git_read [list rev-list --pretty=oneline $cur ^$new_hash]] | ||
1122 | while {[gets $fd line] > 0} { | ||
1123 | set abbr [string range $line 0 7] | ||
1124 | set subj [string range $line 41 end] | ||
1125 | diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl | ||
1126 | index af1fee7..76224d9 100644 | ||
1127 | --- a/git-gui/lib/choose_repository.tcl | ||
1128 | +++ b/git-gui/lib/choose_repository.tcl | ||
1129 | @@ -662,8 +662,8 @@ method _do_clone2 {} { | ||
1130 | set pwd [pwd] | ||
1131 | if {[catch { | ||
1132 | file mkdir [gitdir objects info] | ||
1133 | - set f_in [open [file join $objdir info alternates] r] | ||
1134 | - set f_cp [open [gitdir objects info alternates] w] | ||
1135 | + set f_in [safe_open_file [file join $objdir info alternates] r] | ||
1136 | + set f_cp [safe_open_file [gitdir objects info alternates] w] | ||
1137 | fconfigure $f_in -translation binary -encoding binary | ||
1138 | fconfigure $f_cp -translation binary -encoding binary | ||
1139 | cd $objdir | ||
1140 | @@ -752,7 +752,7 @@ method _do_clone2 {} { | ||
1141 | [cb _do_clone_tags] | ||
1142 | } | ||
1143 | shared { | ||
1144 | - set fd [open [gitdir objects info alternates] w] | ||
1145 | + set fd [safe_open_file [gitdir objects info alternates] w] | ||
1146 | fconfigure $fd -translation binary | ||
1147 | puts $fd $objdir | ||
1148 | close $fd | ||
1149 | @@ -785,8 +785,8 @@ method _copy_files {objdir tocopy} { | ||
1150 | } | ||
1151 | foreach p $tocopy { | ||
1152 | if {[catch { | ||
1153 | - set f_in [open [file join $objdir $p] r] | ||
1154 | - set f_cp [open [file join .git objects $p] w] | ||
1155 | + set f_in [safe_open_file [file join $objdir $p] r] | ||
1156 | + set f_cp [safe_open_file [file join .git objects $p] w] | ||
1157 | fconfigure $f_in -translation binary -encoding binary | ||
1158 | fconfigure $f_cp -translation binary -encoding binary | ||
1159 | |||
1160 | @@ -843,12 +843,12 @@ method _clone_refs {} { | ||
1161 | error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] | ||
1162 | return 0 | ||
1163 | } | ||
1164 | - set fd_in [git_read for-each-ref \ | ||
1165 | + set fd_in [git_read [list for-each-ref \ | ||
1166 | --tcl \ | ||
1167 | - {--format=list %(refname) %(objectname) %(*objectname)}] | ||
1168 | + {--format=list %(refname) %(objectname) %(*objectname)}]] | ||
1169 | cd $pwd | ||
1170 | |||
1171 | - set fd [open [gitdir packed-refs] w] | ||
1172 | + set fd [safe_open_file [gitdir packed-refs] w] | ||
1173 | fconfigure $fd -translation binary | ||
1174 | puts $fd "# pack-refs with: peeled" | ||
1175 | while {[gets $fd_in line] >= 0} { | ||
1176 | @@ -902,7 +902,7 @@ method _do_clone_full_end {ok} { | ||
1177 | |||
1178 | set HEAD {} | ||
1179 | if {[file exists [gitdir FETCH_HEAD]]} { | ||
1180 | - set fd [open [gitdir FETCH_HEAD] r] | ||
1181 | + set fd [safe_open_file [gitdir FETCH_HEAD] r] | ||
1182 | while {[gets $fd line] >= 0} { | ||
1183 | if {[regexp "^(.{40})\t\t" $line line HEAD]} { | ||
1184 | break | ||
1185 | @@ -978,13 +978,14 @@ method _do_clone_checkout {HEAD} { | ||
1186 | [mc "files"]] | ||
1187 | |||
1188 | set readtree_err {} | ||
1189 | - set fd [git_read --stderr read-tree \ | ||
1190 | + set fd [git_read [list read-tree \ | ||
1191 | -m \ | ||
1192 | -u \ | ||
1193 | -v \ | ||
1194 | HEAD \ | ||
1195 | HEAD \ | ||
1196 | - ] | ||
1197 | + ] \ | ||
1198 | + [list 2>@1]] | ||
1199 | fconfigure $fd -blocking 0 -translation binary | ||
1200 | fileevent $fd readable [cb _readtree_wait $fd] | ||
1201 | } | ||
1202 | diff --git a/git-gui/lib/choose_rev.tcl b/git-gui/lib/choose_rev.tcl | ||
1203 | index 6dae793..8ae7e8a 100644 | ||
1204 | --- a/git-gui/lib/choose_rev.tcl | ||
1205 | +++ b/git-gui/lib/choose_rev.tcl | ||
1206 | @@ -146,14 +146,14 @@ constructor _new {path unmerged_only title} { | ||
1207 | append fmt { %(*subject)} | ||
1208 | append fmt {]} | ||
1209 | set all_refn [list] | ||
1210 | - set fr_fd [git_read for-each-ref \ | ||
1211 | + set fr_fd [git_read [list for-each-ref \ | ||
1212 | --tcl \ | ||
1213 | --sort=-taggerdate \ | ||
1214 | --format=$fmt \ | ||
1215 | refs/heads \ | ||
1216 | refs/remotes \ | ||
1217 | refs/tags \ | ||
1218 | - ] | ||
1219 | + ]] | ||
1220 | fconfigure $fr_fd -translation lf -encoding utf-8 | ||
1221 | while {[gets $fr_fd line] > 0} { | ||
1222 | set line [eval $line] | ||
1223 | @@ -176,7 +176,7 @@ constructor _new {path unmerged_only title} { | ||
1224 | close $fr_fd | ||
1225 | |||
1226 | if {$unmerged_only} { | ||
1227 | - set fr_fd [git_read rev-list --all ^$::HEAD] | ||
1228 | + set fr_fd [git_read [list rev-list --all ^$::HEAD]] | ||
1229 | while {[gets $fr_fd sha1] > 0} { | ||
1230 | if {[catch {set rlst $cmt_refn($sha1)}]} continue | ||
1231 | foreach refn $rlst { | ||
1232 | @@ -579,7 +579,7 @@ method _reflog_last {name} { | ||
1233 | |||
1234 | set last {} | ||
1235 | if {[catch {set last [file mtime [gitdir $name]]}] | ||
1236 | - && ![catch {set g [open [gitdir logs $name] r]}]} { | ||
1237 | + && ![catch {set g [safe_open_file [gitdir logs $name] r]}]} { | ||
1238 | fconfigure $g -translation binary | ||
1239 | while {[gets $g line] >= 0} { | ||
1240 | if {[regexp {> ([1-9][0-9]*) } $line line when]} { | ||
1241 | diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl | ||
1242 | index 11379f8..bb6056d 100644 | ||
1243 | --- a/git-gui/lib/commit.tcl | ||
1244 | +++ b/git-gui/lib/commit.tcl | ||
1245 | @@ -27,7 +27,7 @@ You are currently in the middle of a merge that has not been fully completed. Y | ||
1246 | if {[catch { | ||
1247 | set name "" | ||
1248 | set email "" | ||
1249 | - set fd [git_read cat-file commit $curHEAD] | ||
1250 | + set fd [git_read [list cat-file commit $curHEAD]] | ||
1251 | fconfigure $fd -encoding binary -translation lf | ||
1252 | # By default commits are assumed to be in utf-8 | ||
1253 | set enc utf-8 | ||
1254 | @@ -225,7 +225,7 @@ A good commit message has the following format: | ||
1255 | # -- Build the message file. | ||
1256 | # | ||
1257 | set msg_p [gitdir GITGUI_EDITMSG] | ||
1258 | - set msg_wt [open $msg_p w] | ||
1259 | + set msg_wt [safe_open_file $msg_p w] | ||
1260 | fconfigure $msg_wt -translation lf | ||
1261 | setup_commit_encoding $msg_wt | ||
1262 | puts $msg_wt $msg | ||
1263 | @@ -325,7 +325,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} { | ||
1264 | |||
1265 | proc commit_writetree {curHEAD msg_p} { | ||
1266 | ui_status [mc "Committing changes..."] | ||
1267 | - set fd_wt [git_read write-tree] | ||
1268 | + set fd_wt [git_read [list write-tree]] | ||
1269 | fileevent $fd_wt readable \ | ||
1270 | [list commit_committree $fd_wt $curHEAD $msg_p] | ||
1271 | } | ||
1272 | @@ -350,7 +350,7 @@ proc commit_committree {fd_wt curHEAD msg_p} { | ||
1273 | # -- Verify this wasn't an empty change. | ||
1274 | # | ||
1275 | if {$commit_type eq {normal}} { | ||
1276 | - set fd_ot [git_read cat-file commit $PARENT] | ||
1277 | + set fd_ot [git_read [list cat-file commit $PARENT]] | ||
1278 | fconfigure $fd_ot -encoding binary -translation lf | ||
1279 | set old_tree [gets $fd_ot] | ||
1280 | close $fd_ot | ||
1281 | @@ -388,8 +388,8 @@ A rescan will be automatically started now. | ||
1282 | foreach p [concat $PARENT $MERGE_HEAD] { | ||
1283 | lappend cmd -p $p | ||
1284 | } | ||
1285 | - lappend cmd <$msg_p | ||
1286 | - if {[catch {set cmt_id [eval git $cmd]} err]} { | ||
1287 | + set msgtxt [list <$msg_p] | ||
1288 | + if {[catch {set cmt_id [git_redir $cmd $msgtxt]} err]} { | ||
1289 | catch {file delete $msg_p} | ||
1290 | error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"] | ||
1291 | ui_status [mc "Commit failed."] | ||
1292 | @@ -409,7 +409,7 @@ A rescan will be automatically started now. | ||
1293 | if {$commit_type ne {normal}} { | ||
1294 | append reflogm " ($commit_type)" | ||
1295 | } | ||
1296 | - set msg_fd [open $msg_p r] | ||
1297 | + set msg_fd [safe_open_file $msg_p r] | ||
1298 | setup_commit_encoding $msg_fd 1 | ||
1299 | gets $msg_fd subject | ||
1300 | close $msg_fd | ||
1301 | diff --git a/git-gui/lib/console.tcl b/git-gui/lib/console.tcl | ||
1302 | index bb6b9c8..4715ce9 100644 | ||
1303 | --- a/git-gui/lib/console.tcl | ||
1304 | +++ b/git-gui/lib/console.tcl | ||
1305 | @@ -92,10 +92,9 @@ method _init {} { | ||
1306 | |||
1307 | method exec {cmd {after {}}} { | ||
1308 | if {[lindex $cmd 0] eq {git}} { | ||
1309 | - set fd_f [eval git_read --stderr [lrange $cmd 1 end]] | ||
1310 | + set fd_f [git_read [lrange $cmd 1 end] [list 2>@1]] | ||
1311 | } else { | ||
1312 | - lappend cmd 2>@1 | ||
1313 | - set fd_f [_open_stdout_stderr $cmd] | ||
1314 | + set fd_f [safe_open_command $cmd [list 2>@1]] | ||
1315 | } | ||
1316 | fconfigure $fd_f -blocking 0 -translation binary | ||
1317 | fileevent $fd_f readable [cb _read $fd_f $after] | ||
1318 | diff --git a/git-gui/lib/database.tcl b/git-gui/lib/database.tcl | ||
1319 | index 8578308..1fc0ea0 100644 | ||
1320 | --- a/git-gui/lib/database.tcl | ||
1321 | +++ b/git-gui/lib/database.tcl | ||
1322 | @@ -3,7 +3,7 @@ | ||
1323 | |||
1324 | proc do_stats {} { | ||
1325 | global use_ttk NS | ||
1326 | - set fd [git_read count-objects -v] | ||
1327 | + set fd [git_read [list count-objects -v]] | ||
1328 | while {[gets $fd line] > 0} { | ||
1329 | if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { | ||
1330 | set stats($name) $value | ||
1331 | diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl | ||
1332 | index 871ad48..8ec740e 100644 | ||
1333 | --- a/git-gui/lib/diff.tcl | ||
1334 | +++ b/git-gui/lib/diff.tcl | ||
1335 | @@ -202,7 +202,7 @@ proc show_other_diff {path w m cont_info} { | ||
1336 | set sz [string length $content] | ||
1337 | } | ||
1338 | file { | ||
1339 | - set fd [open $path r] | ||
1340 | + set fd [safe_open_file $path r] | ||
1341 | fconfigure $fd \ | ||
1342 | -eofchar {} \ | ||
1343 | -encoding [get_path_encoding $path] | ||
1344 | @@ -226,7 +226,7 @@ proc show_other_diff {path w m cont_info} { | ||
1345 | $ui_diff insert end \ | ||
1346 | "* [mc "Git Repository (subproject)"]\n" \ | ||
1347 | d_info | ||
1348 | - } elseif {![catch {set type [exec file $path]}]} { | ||
1349 | + } elseif {![catch {set type [safe_exec [list file $path]]}]} { | ||
1350 | set n [string length $path] | ||
1351 | if {[string equal -length $n $path $type]} { | ||
1352 | set type [string range $type $n end] | ||
1353 | @@ -338,7 +338,7 @@ proc start_show_diff {cont_info {add_opts {}}} { | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | - if {[catch {set fd [eval git_read --nice $cmd]} err]} { | ||
1358 | + if {[catch {set fd [git_read_nice $cmd]} err]} { | ||
1359 | set diff_active 0 | ||
1360 | unlock_index | ||
1361 | ui_status [mc "Unable to display %s" [escape_path $path]] | ||
1362 | @@ -617,7 +617,7 @@ proc apply_or_revert_hunk {x y revert} { | ||
1363 | |||
1364 | if {[catch { | ||
1365 | set enc [get_path_encoding $current_diff_path] | ||
1366 | - set p [eval git_write $apply_cmd] | ||
1367 | + set p [git_write $apply_cmd] | ||
1368 | fconfigure $p -translation binary -encoding $enc | ||
1369 | puts -nonewline $p $wholepatch | ||
1370 | close $p} err]} { | ||
1371 | @@ -853,7 +853,7 @@ proc apply_or_revert_range_or_line {x y revert} { | ||
1372 | |||
1373 | if {[catch { | ||
1374 | set enc [get_path_encoding $current_diff_path] | ||
1375 | - set p [eval git_write $apply_cmd] | ||
1376 | + set p [git_write $apply_cmd] | ||
1377 | fconfigure $p -translation binary -encoding $enc | ||
1378 | puts -nonewline $p $current_diff_header | ||
1379 | puts -nonewline $p $wholepatch | ||
1380 | @@ -890,7 +890,7 @@ proc undo_last_revert {} { | ||
1381 | |||
1382 | if {[catch { | ||
1383 | set enc $last_revert_enc | ||
1384 | - set p [eval git_write $apply_cmd] | ||
1385 | + set p [git_write $apply_cmd] | ||
1386 | fconfigure $p -translation binary -encoding $enc | ||
1387 | puts -nonewline $p $last_revert | ||
1388 | close $p} err]} { | ||
1389 | diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl | ||
1390 | index d2ec24b..857864f 100644 | ||
1391 | --- a/git-gui/lib/index.tcl | ||
1392 | +++ b/git-gui/lib/index.tcl | ||
1393 | @@ -75,7 +75,7 @@ proc update_indexinfo {msg path_list after} { | ||
1394 | if {$batch > 25} {set batch 25} | ||
1395 | |||
1396 | set status_bar_operation [$::main_status start $msg [mc "files"]] | ||
1397 | - set fd [git_write update-index -z --index-info] | ||
1398 | + set fd [git_write [list update-index -z --index-info]] | ||
1399 | fconfigure $fd \ | ||
1400 | -blocking 0 \ | ||
1401 | -buffering full \ | ||
1402 | @@ -144,7 +144,7 @@ proc update_index {msg path_list after} { | ||
1403 | if {$batch > 25} {set batch 25} | ||
1404 | |||
1405 | set status_bar_operation [$::main_status start $msg [mc "files"]] | ||
1406 | - set fd [git_write update-index --add --remove -z --stdin] | ||
1407 | + set fd [git_write [list update-index --add --remove -z --stdin]] | ||
1408 | fconfigure $fd \ | ||
1409 | -blocking 0 \ | ||
1410 | -buffering full \ | ||
1411 | @@ -218,13 +218,13 @@ proc checkout_index {msg path_list after capture_error} { | ||
1412 | if {$batch > 25} {set batch 25} | ||
1413 | |||
1414 | set status_bar_operation [$::main_status start $msg [mc "files"]] | ||
1415 | - set fd [git_write checkout-index \ | ||
1416 | + set fd [git_write [list checkout-index \ | ||
1417 | --index \ | ||
1418 | --quiet \ | ||
1419 | --force \ | ||
1420 | -z \ | ||
1421 | --stdin \ | ||
1422 | - ] | ||
1423 | + ]] | ||
1424 | fconfigure $fd \ | ||
1425 | -blocking 0 \ | ||
1426 | -buffering full \ | ||
1427 | diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl | ||
1428 | index 664803c..44c3f93 100644 | ||
1429 | --- a/git-gui/lib/merge.tcl | ||
1430 | +++ b/git-gui/lib/merge.tcl | ||
1431 | @@ -93,7 +93,7 @@ method _start {} { | ||
1432 | set spec [$w_rev get_tracking_branch] | ||
1433 | set cmit [$w_rev get_commit] | ||
1434 | |||
1435 | - set fh [open [gitdir FETCH_HEAD] w] | ||
1436 | + set fh [safe_open_file [gitdir FETCH_HEAD] w] | ||
1437 | fconfigure $fh -translation lf | ||
1438 | if {$spec eq {}} { | ||
1439 | set remote . | ||
1440 | @@ -118,7 +118,7 @@ method _start {} { | ||
1441 | set cmd [list git] | ||
1442 | lappend cmd merge | ||
1443 | lappend cmd --strategy=recursive | ||
1444 | - lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]] | ||
1445 | + lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]] | ||
1446 | lappend cmd HEAD | ||
1447 | lappend cmd $name | ||
1448 | } | ||
1449 | @@ -239,7 +239,7 @@ Continue with resetting the current changes?"] | ||
1450 | } | ||
1451 | |||
1452 | if {[ask_popup $op_question] eq {yes}} { | ||
1453 | - set fd [git_read --stderr read-tree --reset -u -v HEAD] | ||
1454 | + set fd [git_read [list read-tree --reset -u -v HEAD] [list 2>@1]] | ||
1455 | fconfigure $fd -blocking 0 -translation binary | ||
1456 | set status_bar_operation [$::main_status \ | ||
1457 | start \ | ||
1458 | diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl | ||
1459 | index e688b01..6b26726 100644 | ||
1460 | --- a/git-gui/lib/mergetool.tcl | ||
1461 | +++ b/git-gui/lib/mergetool.tcl | ||
1462 | @@ -88,7 +88,7 @@ proc merge_load_stages {path cont} { | ||
1463 | set merge_stages(3) {} | ||
1464 | set merge_stages_buf {} | ||
1465 | |||
1466 | - set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] | ||
1467 | + set merge_stages_fd [git_read [list ls-files -u -z -- $path]] | ||
1468 | |||
1469 | fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary | ||
1470 | fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] | ||
1471 | @@ -293,7 +293,7 @@ proc merge_tool_get_stages {target stages} { | ||
1472 | foreach fname $stages { | ||
1473 | if {$merge_stages($i) eq {}} { | ||
1474 | file delete $fname | ||
1475 | - catch { close [open $fname w] } | ||
1476 | + catch { close [safe_open_file $fname w] } | ||
1477 | } else { | ||
1478 | # A hack to support autocrlf properly | ||
1479 | git checkout-index -f --stage=$i -- $target | ||
1480 | @@ -343,9 +343,9 @@ proc merge_tool_start {cmdline target backup stages} { | ||
1481 | |||
1482 | # Force redirection to avoid interpreting output on stderr | ||
1483 | # as an error, and launch the tool | ||
1484 | - lappend cmdline {2>@1} | ||
1485 | + set redir [list {2>@1}] | ||
1486 | |||
1487 | - if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} { | ||
1488 | + if {[catch { set mtool_fd [safe_open_command $cmdline $redir] } err]} { | ||
1489 | delete_temp_files $mtool_tmpfiles | ||
1490 | error_popup [mc "Could not start the merge tool:\n\n%s" $err] | ||
1491 | return | ||
1492 | diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl | ||
1493 | index ef77ed7..cf796d1 100644 | ||
1494 | --- a/git-gui/lib/remote.tcl | ||
1495 | +++ b/git-gui/lib/remote.tcl | ||
1496 | @@ -32,7 +32,7 @@ proc all_tracking_branches {} { | ||
1497 | } | ||
1498 | |||
1499 | if {$pat ne {}} { | ||
1500 | - set fd [eval git_read for-each-ref --format=%(refname) $cmd] | ||
1501 | + set fd [git_read [concat for-each-ref --format=%(refname) $cmd]] | ||
1502 | while {[gets $fd n] > 0} { | ||
1503 | foreach spec $pat { | ||
1504 | set dst [string range [lindex $spec 0] 0 end-2] | ||
1505 | @@ -75,7 +75,7 @@ proc load_all_remotes {} { | ||
1506 | |||
1507 | foreach name $all_remotes { | ||
1508 | catch { | ||
1509 | - set fd [open [file join $rm_dir $name] r] | ||
1510 | + set fd [safe_open_file [file join $rm_dir $name] r] | ||
1511 | while {[gets $fd line] >= 0} { | ||
1512 | if {[regexp {^URL:[ ]*(.+)$} $line line url]} { | ||
1513 | set remote_url($name) $url | ||
1514 | @@ -145,7 +145,7 @@ proc add_fetch_entry {r} { | ||
1515 | } | ||
1516 | } else { | ||
1517 | catch { | ||
1518 | - set fd [open [gitdir remotes $r] r] | ||
1519 | + set fd [safe_open_file [gitdir remotes $r] r] | ||
1520 | while {[gets $fd n] >= 0} { | ||
1521 | if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { | ||
1522 | set enable 1 | ||
1523 | @@ -182,7 +182,7 @@ proc add_push_entry {r} { | ||
1524 | } | ||
1525 | } else { | ||
1526 | catch { | ||
1527 | - set fd [open [gitdir remotes $r] r] | ||
1528 | + set fd [safe_open_file [gitdir remotes $r] r] | ||
1529 | while {[gets $fd n] >= 0} { | ||
1530 | if {[regexp {^Push:[ \t]*([^:]+):} $n]} { | ||
1531 | set enable 1 | ||
1532 | diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl | ||
1533 | index 5ba9fca..c8c99b1 100644 | ||
1534 | --- a/git-gui/lib/remote_branch_delete.tcl | ||
1535 | +++ b/git-gui/lib/remote_branch_delete.tcl | ||
1536 | @@ -308,7 +308,7 @@ method _load {cache uri} { | ||
1537 | set full_list [list] | ||
1538 | set head_cache($cache) [list] | ||
1539 | set full_cache($cache) [list] | ||
1540 | - set active_ls [git_read ls-remote $uri] | ||
1541 | + set active_ls [git_read [list ls-remote $uri]] | ||
1542 | fconfigure $active_ls \ | ||
1543 | -blocking 0 \ | ||
1544 | -translation lf \ | ||
1545 | diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl | ||
1546 | index 97d1d7a..d97be99 100644 | ||
1547 | --- a/git-gui/lib/shortcut.tcl | ||
1548 | +++ b/git-gui/lib/shortcut.tcl | ||
1549 | @@ -12,7 +12,7 @@ proc do_windows_shortcut {} { | ||
1550 | set fn ${fn}.lnk | ||
1551 | } | ||
1552 | # Use git-gui.exe if available (ie: git-for-windows) | ||
1553 | - set cmdLine [auto_execok git-gui.exe] | ||
1554 | + set cmdLine [list [_which git-gui]] | ||
1555 | if {$cmdLine eq {}} { | ||
1556 | set cmdLine [list [info nameofexecutable] \ | ||
1557 | [file normalize $::argv0]] | ||
1558 | @@ -30,7 +30,7 @@ proc do_cygwin_shortcut {} { | ||
1559 | global argv0 _gitworktree | ||
1560 | |||
1561 | if {[catch { | ||
1562 | - set desktop [exec cygpath \ | ||
1563 | + set desktop [safe_exec [list cygpath \ | ||
1564 | --windows \ | ||
1565 | --absolute \ | ||
1566 | --long-name \ | ||
1567 | @@ -48,14 +48,14 @@ proc do_cygwin_shortcut {} { | ||
1568 | set fn ${fn}.lnk | ||
1569 | } | ||
1570 | if {[catch { | ||
1571 | - set sh [exec cygpath \ | ||
1572 | + set sh [safe_exec [list cygpath \ | ||
1573 | --windows \ | ||
1574 | --absolute \ | ||
1575 | - /bin/sh.exe] | ||
1576 | - set me [exec cygpath \ | ||
1577 | + /bin/sh.exe]] | ||
1578 | + set me [safe_exec [list cygpath \ | ||
1579 | --unix \ | ||
1580 | --absolute \ | ||
1581 | - $argv0] | ||
1582 | + $argv0]] | ||
1583 | win32_create_lnk $fn [list \ | ||
1584 | $sh -c \ | ||
1585 | "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ | ||
1586 | @@ -86,7 +86,7 @@ proc do_macosx_app {} { | ||
1587 | |||
1588 | file mkdir $MacOS | ||
1589 | |||
1590 | - set fd [open [file join $Contents Info.plist] w] | ||
1591 | + set fd [safe_open_file [file join $Contents Info.plist] w] | ||
1592 | puts $fd {<?xml version="1.0" encoding="UTF-8"?> | ||
1593 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
1594 | <plist version="1.0"> | ||
1595 | @@ -111,7 +111,7 @@ proc do_macosx_app {} { | ||
1596 | </plist>} | ||
1597 | close $fd | ||
1598 | |||
1599 | - set fd [open $exe w] | ||
1600 | + set fd [safe_open_file $exe w] | ||
1601 | puts $fd "#!/bin/sh" | ||
1602 | foreach name [lsort [array names env]] { | ||
1603 | set value $env($name) | ||
1604 | diff --git a/git-gui/lib/sshkey.tcl b/git-gui/lib/sshkey.tcl | ||
1605 | index 589ff8f..c3e681b 100644 | ||
1606 | --- a/git-gui/lib/sshkey.tcl | ||
1607 | +++ b/git-gui/lib/sshkey.tcl | ||
1608 | @@ -7,7 +7,7 @@ proc find_ssh_key {} { | ||
1609 | ~/.ssh/id_rsa.pub ~/.ssh/identity.pub | ||
1610 | } { | ||
1611 | if {[file exists $name]} { | ||
1612 | - set fh [open $name r] | ||
1613 | + set fh [safe_open_file $name r] | ||
1614 | set cont [read $fh] | ||
1615 | close $fh | ||
1616 | return [list $name $cont] | ||
1617 | @@ -83,9 +83,10 @@ proc make_ssh_key {w} { | ||
1618 | set sshkey_title [mc "Generating..."] | ||
1619 | $w.header.gen configure -state disabled | ||
1620 | |||
1621 | - set cmdline [list sh -c {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}] | ||
1622 | + set cmdline [list [shellpath] -c \ | ||
1623 | + {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}] | ||
1624 | |||
1625 | - if {[catch { set sshkey_fd [_open_stdout_stderr $cmdline] } err]} { | ||
1626 | + if {[catch { set sshkey_fd [safe_open_command $cmdline] } err]} { | ||
1627 | error_popup [mc "Could not start ssh-keygen:\n\n%s" $err] | ||
1628 | return | ||
1629 | } | ||
1630 | diff --git a/git-gui/lib/tools.tcl b/git-gui/lib/tools.tcl | ||
1631 | index 413f1a1..48fddfd 100644 | ||
1632 | --- a/git-gui/lib/tools.tcl | ||
1633 | +++ b/git-gui/lib/tools.tcl | ||
1634 | @@ -110,14 +110,14 @@ proc tools_exec {fullname} { | ||
1635 | |||
1636 | set cmdline $repo_config(guitool.$fullname.cmd) | ||
1637 | if {[is_config_true "guitool.$fullname.noconsole"]} { | ||
1638 | - tools_run_silent [list sh -c $cmdline] \ | ||
1639 | + tools_run_silent [list [shellpath] -c $cmdline] \ | ||
1640 | [list tools_complete $fullname {}] | ||
1641 | } else { | ||
1642 | regsub {/} $fullname { / } title | ||
1643 | set w [console::new \ | ||
1644 | [mc "Tool: %s" $title] \ | ||
1645 | [mc "Running: %s" $cmdline]] | ||
1646 | - console::exec $w [list sh -c $cmdline] \ | ||
1647 | + console::exec $w [list [shellpath] -c $cmdline] \ | ||
1648 | [list tools_complete $fullname $w] | ||
1649 | } | ||
1650 | |||
1651 | @@ -130,8 +130,7 @@ proc tools_exec {fullname} { | ||
1652 | } | ||
1653 | |||
1654 | proc tools_run_silent {cmd after} { | ||
1655 | - lappend cmd 2>@1 | ||
1656 | - set fd [_open_stdout_stderr $cmd] | ||
1657 | + set fd [safe_open_command $cmd [list 2>@1]] | ||
1658 | |||
1659 | fconfigure $fd -blocking 0 -translation binary | ||
1660 | fileevent $fd readable [list tools_consume_input $fd $after] | ||
1661 | diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl | ||
1662 | index db91ab8..3aedae2 100644 | ||
1663 | --- a/git-gui/lib/win32.tcl | ||
1664 | +++ b/git-gui/lib/win32.tcl | ||
1665 | @@ -2,11 +2,11 @@ | ||
1666 | # Copyright (C) 2007 Shawn Pearce | ||
1667 | |||
1668 | proc win32_read_lnk {lnk_path} { | ||
1669 | - return [exec cscript.exe \ | ||
1670 | + return [safe_exec [list cscript.exe \ | ||
1671 | /E:jscript \ | ||
1672 | /nologo \ | ||
1673 | [file join $::oguilib win32_shortcut.js] \ | ||
1674 | - $lnk_path] | ||
1675 | + $lnk_path]] | ||
1676 | } | ||
1677 | |||
1678 | proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { | ||
1679 | @@ -15,12 +15,13 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { | ||
1680 | set lnk_args [lrange $lnk_exec 1 end] | ||
1681 | set lnk_exec [lindex $lnk_exec 0] | ||
1682 | |||
1683 | - eval [list exec wscript.exe \ | ||
1684 | + set cmd [list wscript.exe \ | ||
1685 | /E:jscript \ | ||
1686 | /nologo \ | ||
1687 | [file nativename [file join $oguilib win32_shortcut.js]] \ | ||
1688 | $lnk_path \ | ||
1689 | [file nativename [file join $oguilib git-gui.ico]] \ | ||
1690 | $lnk_dir \ | ||
1691 | - $lnk_exec] $lnk_args | ||
1692 | + $lnk_exec] | ||
1693 | + safe_exec [concat $cmd $lnk_args] | ||
1694 | } | ||
1695 | diff --git a/gitk-git/gitk b/gitk-git/gitk | ||
1696 | index 23d9dd1..1c8c9c0 100755 | ||
1697 | --- a/gitk-git/gitk | ||
1698 | +++ b/gitk-git/gitk | ||
1699 | @@ -9,6 +9,92 @@ exec wish "$0" -- "$@" | ||
1700 | |||
1701 | package require Tk | ||
1702 | |||
1703 | + | ||
1704 | +# Wrap exec/open to sanitize arguments | ||
1705 | + | ||
1706 | +# unsafe arguments begin with redirections or the pipe or background operators | ||
1707 | +proc is_arg_unsafe {arg} { | ||
1708 | + regexp {^([<|>&]|2>)} $arg | ||
1709 | +} | ||
1710 | + | ||
1711 | +proc make_arg_safe {arg} { | ||
1712 | + if {[is_arg_unsafe $arg]} { | ||
1713 | + set arg [file join . $arg] | ||
1714 | + } | ||
1715 | + return $arg | ||
1716 | +} | ||
1717 | + | ||
1718 | +proc make_arglist_safe {arglist} { | ||
1719 | + set res {} | ||
1720 | + foreach arg $arglist { | ||
1721 | + lappend res [make_arg_safe $arg] | ||
1722 | + } | ||
1723 | + return $res | ||
1724 | +} | ||
1725 | + | ||
1726 | +# executes one command | ||
1727 | +# no redirections or pipelines are possible | ||
1728 | +# cmd is a list that specifies the command and its arguments | ||
1729 | +# calls `exec` and returns its value | ||
1730 | +proc safe_exec {cmd} { | ||
1731 | + eval exec [make_arglist_safe $cmd] | ||
1732 | +} | ||
1733 | + | ||
1734 | +# executes one command with redirections | ||
1735 | +# no pipelines are possible | ||
1736 | +# cmd is a list that specifies the command and its arguments | ||
1737 | +# redir is a list that specifies redirections (output, background, constant(!) commands) | ||
1738 | +# calls `exec` and returns its value | ||
1739 | +proc safe_exec_redirect {cmd redir} { | ||
1740 | + eval exec [make_arglist_safe $cmd] $redir | ||
1741 | +} | ||
1742 | + | ||
1743 | +proc safe_open_file {filename flags} { | ||
1744 | + # a file name starting with "|" would attempt to run a process | ||
1745 | + # but such a file name must be treated as a relative path | ||
1746 | + # hide the "|" behind "./" | ||
1747 | + if {[string index $filename 0] eq "|"} { | ||
1748 | + set filename [file join . $filename] | ||
1749 | + } | ||
1750 | + open $filename $flags | ||
1751 | +} | ||
1752 | + | ||
1753 | +# opens a command pipeline for reading | ||
1754 | +# cmd is a list that specifies the command and its arguments | ||
1755 | +# calls `open` and returns the file id | ||
1756 | +proc safe_open_command {cmd} { | ||
1757 | + open |[make_arglist_safe $cmd] r | ||
1758 | +} | ||
1759 | + | ||
1760 | +# opens a command pipeline for reading and writing | ||
1761 | +# cmd is a list that specifies the command and its arguments | ||
1762 | +# calls `open` and returns the file id | ||
1763 | +proc safe_open_command_rw {cmd} { | ||
1764 | + open |[make_arglist_safe $cmd] r+ | ||
1765 | +} | ||
1766 | + | ||
1767 | +# opens a command pipeline for reading with redirections | ||
1768 | +# cmd is a list that specifies the command and its arguments | ||
1769 | +# redir is a list that specifies redirections | ||
1770 | +# calls `open` and returns the file id | ||
1771 | +proc safe_open_command_redirect {cmd redir} { | ||
1772 | + set cmd [make_arglist_safe $cmd] | ||
1773 | + open |[concat $cmd $redir] r | ||
1774 | +} | ||
1775 | + | ||
1776 | +# opens a pipeline with several commands for reading | ||
1777 | +# cmds is a list of lists, each of which specifies a command and its arguments | ||
1778 | +# calls `open` and returns the file id | ||
1779 | +proc safe_open_pipeline {cmds} { | ||
1780 | + set cmd {} | ||
1781 | + foreach subcmd $cmds { | ||
1782 | + set cmd [concat $cmd | [make_arglist_safe $subcmd]] | ||
1783 | + } | ||
1784 | + open $cmd r | ||
1785 | +} | ||
1786 | + | ||
1787 | +# End exec/open wrappers | ||
1788 | + | ||
1789 | proc hasworktree {} { | ||
1790 | return [expr {[exec git rev-parse --is-bare-repository] == "false" && | ||
1791 | [exec git rev-parse --is-inside-git-dir] == "false"}] | ||
1792 | @@ -134,7 +220,7 @@ proc unmerged_files {files} { | ||
1793 | set mlist {} | ||
1794 | set nr_unmerged 0 | ||
1795 | if {[catch { | ||
1796 | - set fd [open "| git ls-files -u" r] | ||
1797 | + set fd [safe_open_command {git ls-files -u}] | ||
1798 | } err]} { | ||
1799 | show_error {} . "[mc "Couldn't get list of unmerged files:"] $err" | ||
1800 | exit 1 | ||
1801 | @@ -296,7 +382,7 @@ proc parseviewrevs {view revs} { | ||
1802 | } elseif {[lsearch -exact $revs --all] >= 0} { | ||
1803 | lappend revs HEAD | ||
1804 | } | ||
1805 | - if {[catch {set ids [eval exec git rev-parse $revs]} err]} { | ||
1806 | + if {[catch {set ids [safe_exec [concat git rev-parse $revs]]} err]} { | ||
1807 | # we get stdout followed by stderr in $err | ||
1808 | # for an unknown rev, git rev-parse echoes it and then errors out | ||
1809 | set errlines [split $err "\n"] | ||
1810 | @@ -374,7 +460,7 @@ proc start_rev_list {view} { | ||
1811 | set args $viewargs($view) | ||
1812 | if {$viewargscmd($view) ne {}} { | ||
1813 | if {[catch { | ||
1814 | - set str [exec sh -c $viewargscmd($view)] | ||
1815 | + set str [safe_exec [list sh -c $viewargscmd($view)]] | ||
1816 | } err]} { | ||
1817 | error_popup "[mc "Error executing --argscmd command:"] $err" | ||
1818 | return 0 | ||
1819 | @@ -405,14 +491,16 @@ proc start_rev_list {view} { | ||
1820 | if {$revs eq {}} { | ||
1821 | return 0 | ||
1822 | } | ||
1823 | - set args [concat $vflags($view) $revs] | ||
1824 | + set args $vflags($view) | ||
1825 | } else { | ||
1826 | + set revs {} | ||
1827 | set args $vorigargs($view) | ||
1828 | } | ||
1829 | |||
1830 | if {[catch { | ||
1831 | - set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ | ||
1832 | - --parents --boundary $args "--" $files] r] | ||
1833 | + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ | ||
1834 | + --parents --boundary $args --stdin] \ | ||
1835 | + [list "<<[join [concat $revs "--" $files] "\n"]"]] | ||
1836 | } err]} { | ||
1837 | error_popup "[mc "Error executing git log:"] $err" | ||
1838 | return 0 | ||
1839 | @@ -446,9 +534,9 @@ proc stop_instance {inst} { | ||
1840 | set pid [pid $fd] | ||
1841 | |||
1842 | if {$::tcl_platform(platform) eq {windows}} { | ||
1843 | - exec taskkill /pid $pid | ||
1844 | + safe_exec [list taskkill /pid $pid] | ||
1845 | } else { | ||
1846 | - exec kill $pid | ||
1847 | + safe_exec [list kill $pid] | ||
1848 | } | ||
1849 | } | ||
1850 | catch {close $fd} | ||
1851 | @@ -554,13 +642,18 @@ proc updatecommits {} { | ||
1852 | set revs $newrevs | ||
1853 | set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]] | ||
1854 | } | ||
1855 | - set args [concat $vflags($view) $revs --not $oldpos] | ||
1856 | + set args $vflags($view) | ||
1857 | + foreach r $oldpos { | ||
1858 | + lappend revs "^$r" | ||
1859 | + } | ||
1860 | } else { | ||
1861 | + set revs {} | ||
1862 | set args $vorigargs($view) | ||
1863 | } | ||
1864 | if {[catch { | ||
1865 | - set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ | ||
1866 | - --parents --boundary $args "--" $vfilelimit($view)] r] | ||
1867 | + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ | ||
1868 | + --parents --boundary $args --stdin] \ | ||
1869 | + [list "<<[join [concat $revs "--" $vfilelimit($view)] "\n"]"]] | ||
1870 | } err]} { | ||
1871 | error_popup "[mc "Error executing git log:"] $err" | ||
1872 | return | ||
1873 | @@ -1527,8 +1620,8 @@ proc getcommitlines {fd inst view updating} { | ||
1874 | # and if we already know about it, using the rewritten | ||
1875 | # parent as a substitute parent for $id's children. | ||
1876 | if {![catch { | ||
1877 | - set rwid [exec git rev-list --first-parent --max-count=1 \ | ||
1878 | - $id -- $vfilelimit($view)] | ||
1879 | + set rwid [safe_exec [list git rev-list --first-parent --max-count=1 \ | ||
1880 | + $id -- $vfilelimit($view)]] | ||
1881 | }]} { | ||
1882 | if {$rwid ne {} && [info exists varcid($view,$rwid)]} { | ||
1883 | # use $rwid in place of $id | ||
1884 | @@ -1648,7 +1741,7 @@ proc do_readcommit {id} { | ||
1885 | global tclencoding | ||
1886 | |||
1887 | # Invoke git-log to handle automatic encoding conversion | ||
1888 | - set fd [open [concat | git log --no-color --pretty=raw -1 $id] r] | ||
1889 | + set fd [safe_open_command [concat git log --no-color --pretty=raw -1 $id]] | ||
1890 | # Read the results using i18n.logoutputencoding | ||
1891 | fconfigure $fd -translation lf -eofchar {} | ||
1892 | if {$tclencoding != {}} { | ||
1893 | @@ -1784,7 +1877,7 @@ proc readrefs {} { | ||
1894 | foreach v {tagids idtags headids idheads otherrefids idotherrefs} { | ||
1895 | unset -nocomplain $v | ||
1896 | } | ||
1897 | - set refd [open [list | git show-ref -d] r] | ||
1898 | + set refd [safe_open_command [list git show-ref -d]] | ||
1899 | if {$tclencoding != {}} { | ||
1900 | fconfigure $refd -encoding $tclencoding | ||
1901 | } | ||
1902 | @@ -1832,7 +1925,7 @@ proc readrefs {} { | ||
1903 | set selectheadid {} | ||
1904 | if {$selecthead ne {}} { | ||
1905 | catch { | ||
1906 | - set selectheadid [exec git rev-parse --verify $selecthead] | ||
1907 | + set selectheadid [safe_exec [list git rev-parse --verify $selecthead]] | ||
1908 | } | ||
1909 | } | ||
1910 | } | ||
1911 | @@ -2092,7 +2185,7 @@ proc makewindow {} { | ||
1912 | {mc "Reread re&ferences" command rereadrefs} | ||
1913 | {mc "&List references" command showrefs -accelerator F2} | ||
1914 | {xx "" separator} | ||
1915 | - {mc "Start git &gui" command {exec git gui &}} | ||
1916 | + {mc "Start git &gui" command {safe_exec_redirect [list git gui] [list &]}} | ||
1917 | {xx "" separator} | ||
1918 | {mc "&Quit" command doquit -accelerator Meta1-Q} | ||
1919 | }} | ||
1920 | @@ -2874,7 +2967,7 @@ proc savestuff {w} { | ||
1921 | set remove_tmp 0 | ||
1922 | if {[catch { | ||
1923 | set try_count 0 | ||
1924 | - while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} { | ||
1925 | + while {[catch {set f [safe_open_file $config_file_tmp {WRONLY CREAT EXCL}]}]} { | ||
1926 | if {[incr try_count] > 50} { | ||
1927 | error "Unable to write config file: $config_file_tmp exists" | ||
1928 | } | ||
1929 | @@ -2955,9 +3048,9 @@ proc savestuff {w} { | ||
1930 | proc resizeclistpanes {win w} { | ||
1931 | global oldwidth oldsash use_ttk | ||
1932 | if {[info exists oldwidth($win)]} { | ||
1933 | - if {[info exists oldsash($win)]} { | ||
1934 | - set s0 [lindex $oldsash($win) 0] | ||
1935 | - set s1 [lindex $oldsash($win) 1] | ||
1936 | + if {[info exists oldsash($win)]} { | ||
1937 | + set s0 [lindex $oldsash($win) 0] | ||
1938 | + set s1 [lindex $oldsash($win) 1] | ||
1939 | } elseif {$use_ttk} { | ||
1940 | set s0 [$win sashpos 0] | ||
1941 | set s1 [$win sashpos 1] | ||
1942 | @@ -2991,8 +3084,10 @@ proc resizeclistpanes {win w} { | ||
1943 | } else { | ||
1944 | $win sash place 0 $sash0 [lindex $s0 1] | ||
1945 | $win sash place 1 $sash1 [lindex $s1 1] | ||
1946 | + set sash0 [list $sash0 [lindex $s0 1]] | ||
1947 | + set sash1 [list $sash1 [lindex $s1 1]] | ||
1948 | } | ||
1949 | - set oldsash($win) [list $sash0 $sash1] | ||
1950 | + set oldsash($win) [list $sash0 $sash1] | ||
1951 | } | ||
1952 | set oldwidth($win) $w | ||
1953 | } | ||
1954 | @@ -3000,8 +3095,8 @@ proc resizeclistpanes {win w} { | ||
1955 | proc resizecdetpanes {win w} { | ||
1956 | global oldwidth oldsash use_ttk | ||
1957 | if {[info exists oldwidth($win)]} { | ||
1958 | - if {[info exists oldsash($win)]} { | ||
1959 | - set s0 $oldsash($win) | ||
1960 | + if {[info exists oldsash($win)]} { | ||
1961 | + set s0 $oldsash($win) | ||
1962 | } elseif {$use_ttk} { | ||
1963 | set s0 [$win sashpos 0] | ||
1964 | } else { | ||
1965 | @@ -3023,8 +3118,9 @@ proc resizecdetpanes {win w} { | ||
1966 | $win sashpos 0 $sash0 | ||
1967 | } else { | ||
1968 | $win sash place 0 $sash0 [lindex $s0 1] | ||
1969 | + set sash0 [list $sash0 [lindex $s0 1]] | ||
1970 | } | ||
1971 | - set oldsash($win) $sash0 | ||
1972 | + set oldsash($win) $sash0 | ||
1973 | } | ||
1974 | set oldwidth($win) $w | ||
1975 | } | ||
1976 | @@ -3587,7 +3683,7 @@ proc gitknewtmpdir {} { | ||
1977 | set tmpdir $gitdir | ||
1978 | } | ||
1979 | set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"] | ||
1980 | - if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} { | ||
1981 | + if {[catch {set gitktmpdir [safe_exec [list mktemp -d $gitktmpformat]]}]} { | ||
1982 | set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] | ||
1983 | } | ||
1984 | if {[catch {file mkdir $gitktmpdir} err]} { | ||
1985 | @@ -3609,7 +3705,7 @@ proc gitknewtmpdir {} { | ||
1986 | proc save_file_from_commit {filename output what} { | ||
1987 | global nullfile | ||
1988 | |||
1989 | - if {[catch {exec git show $filename -- > $output} err]} { | ||
1990 | + if {[catch {safe_exec_redirect [list git show $filename --] [list > $output]} err]} { | ||
1991 | if {[string match "fatal: bad revision *" $err]} { | ||
1992 | return $nullfile | ||
1993 | } | ||
1994 | @@ -3674,7 +3770,7 @@ proc external_diff {} { | ||
1995 | |||
1996 | if {$difffromfile ne {} && $difftofile ne {}} { | ||
1997 | set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] | ||
1998 | - if {[catch {set fl [open |$cmd r]} err]} { | ||
1999 | + if {[catch {set fl [safe_open_command $cmd]} err]} { | ||
2000 | file delete -force $diffdir | ||
2001 | error_popup "$extdifftool: [mc "command failed:"] $err" | ||
2002 | } else { | ||
2003 | @@ -3778,7 +3874,7 @@ proc external_blame_diff {} { | ||
2004 | # Find the SHA1 ID of the blob for file $fname in the index | ||
2005 | # at stage 0 or 2 | ||
2006 | proc index_sha1 {fname} { | ||
2007 | - set f [open [list | git ls-files -s $fname] r] | ||
2008 | + set f [safe_open_command [list git ls-files -s $fname]] | ||
2009 | while {[gets $f line] >= 0} { | ||
2010 | set info [lindex [split $line "\t"] 0] | ||
2011 | set stage [lindex $info 2] | ||
2012 | @@ -3838,7 +3934,7 @@ proc external_blame {parent_idx {line {}}} { | ||
2013 | # being given an absolute path... | ||
2014 | set f [make_relative $f] | ||
2015 | lappend cmdline $base_commit $f | ||
2016 | - if {[catch {eval exec $cmdline &} err]} { | ||
2017 | + if {[catch {safe_exec_redirect $cmdline [list &]} err]} { | ||
2018 | error_popup "[mc "git gui blame: command failed:"] $err" | ||
2019 | } | ||
2020 | } | ||
2021 | @@ -3866,7 +3962,7 @@ proc show_line_source {} { | ||
2022 | # must be a merge in progress... | ||
2023 | if {[catch { | ||
2024 | # get the last line from .git/MERGE_HEAD | ||
2025 | - set f [open [file join $gitdir MERGE_HEAD] r] | ||
2026 | + set f [safe_open_file [file join $gitdir MERGE_HEAD] r] | ||
2027 | set id [lindex [split [read $f] "\n"] end-1] | ||
2028 | close $f | ||
2029 | } err]} { | ||
2030 | @@ -3889,19 +3985,17 @@ proc show_line_source {} { | ||
2031 | } | ||
2032 | set line [lindex $h 1] | ||
2033 | } | ||
2034 | - set blameargs {} | ||
2035 | + set blamefile [file join $cdup $flist_menu_file] | ||
2036 | if {$from_index ne {}} { | ||
2037 | - lappend blameargs | git cat-file blob $from_index | ||
2038 | - } | ||
2039 | - lappend blameargs | git blame -p -L$line,+1 | ||
2040 | - if {$from_index ne {}} { | ||
2041 | - lappend blameargs --contents - | ||
2042 | + set blameargs [list \ | ||
2043 | + [list git cat-file blob $from_index] \ | ||
2044 | + [list git blame -p -L$line,+1 --contents - -- $blamefile]] | ||
2045 | } else { | ||
2046 | - lappend blameargs $id | ||
2047 | + set blameargs [list \ | ||
2048 | + [list git blame -p -L$line,+1 $id -- $blamefile]] | ||
2049 | } | ||
2050 | - lappend blameargs -- [file join $cdup $flist_menu_file] | ||
2051 | if {[catch { | ||
2052 | - set f [open $blameargs r] | ||
2053 | + set f [safe_open_pipeline $blameargs] | ||
2054 | } err]} { | ||
2055 | error_popup [mc "Couldn't start git blame: %s" $err] | ||
2056 | return | ||
2057 | @@ -4826,8 +4920,8 @@ proc do_file_hl {serial} { | ||
2058 | # must be "containing:", i.e. we're searching commit info | ||
2059 | return | ||
2060 | } | ||
2061 | - set cmd [concat | git diff-tree -r -s --stdin $gdtargs] | ||
2062 | - set filehighlight [open $cmd r+] | ||
2063 | + set cmd [concat git diff-tree -r -s --stdin $gdtargs] | ||
2064 | + set filehighlight [safe_open_command_rw $cmd] | ||
2065 | fconfigure $filehighlight -blocking 0 | ||
2066 | filerun $filehighlight readfhighlight | ||
2067 | set fhl_list {} | ||
2068 | @@ -5256,8 +5350,8 @@ proc get_viewmainhead {view} { | ||
2069 | global viewmainheadid vfilelimit viewinstances mainheadid | ||
2070 | |||
2071 | catch { | ||
2072 | - set rfd [open [concat | git rev-list -1 $mainheadid \ | ||
2073 | - -- $vfilelimit($view)] r] | ||
2074 | + set rfd [safe_open_command [concat git rev-list -1 $mainheadid \ | ||
2075 | + -- $vfilelimit($view)]] | ||
2076 | set j [reg_instance $rfd] | ||
2077 | lappend viewinstances($view) $j | ||
2078 | fconfigure $rfd -blocking 0 | ||
2079 | @@ -5322,14 +5416,14 @@ proc dodiffindex {} { | ||
2080 | if {!$showlocalchanges || !$hasworktree} return | ||
2081 | incr lserial | ||
2082 | if {[package vcompare $git_version "1.7.2"] >= 0} { | ||
2083 | - set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD" | ||
2084 | + set cmd "git diff-index --cached --ignore-submodules=dirty HEAD" | ||
2085 | } else { | ||
2086 | - set cmd "|git diff-index --cached HEAD" | ||
2087 | + set cmd "git diff-index --cached HEAD" | ||
2088 | } | ||
2089 | if {$vfilelimit($curview) ne {}} { | ||
2090 | set cmd [concat $cmd -- $vfilelimit($curview)] | ||
2091 | } | ||
2092 | - set fd [open $cmd r] | ||
2093 | + set fd [safe_open_command $cmd] | ||
2094 | fconfigure $fd -blocking 0 | ||
2095 | set i [reg_instance $fd] | ||
2096 | filerun $fd [list readdiffindex $fd $lserial $i] | ||
2097 | @@ -5354,11 +5448,11 @@ proc readdiffindex {fd serial inst} { | ||
2098 | } | ||
2099 | |||
2100 | # now see if there are any local changes not checked in to the index | ||
2101 | - set cmd "|git diff-files" | ||
2102 | + set cmd "git diff-files" | ||
2103 | if {$vfilelimit($curview) ne {}} { | ||
2104 | set cmd [concat $cmd -- $vfilelimit($curview)] | ||
2105 | } | ||
2106 | - set fd [open $cmd r] | ||
2107 | + set fd [safe_open_command $cmd] | ||
2108 | fconfigure $fd -blocking 0 | ||
2109 | set i [reg_instance $fd] | ||
2110 | filerun $fd [list readdifffiles $fd $serial $i] | ||
2111 | @@ -7147,8 +7241,8 @@ proc browseweb {url} { | ||
2112 | global web_browser | ||
2113 | |||
2114 | if {$web_browser eq {}} return | ||
2115 | - # Use eval here in case $web_browser is a command plus some arguments | ||
2116 | - if {[catch {eval exec $web_browser [list $url] &} err]} { | ||
2117 | + # Use concat here in case $web_browser is a command plus some arguments | ||
2118 | + if {[catch {safe_exec_redirect [concat $web_browser [list $url]] [list &]} err]} { | ||
2119 | error_popup "[mc "Error starting web browser:"] $err" | ||
2120 | } | ||
2121 | } | ||
2122 | @@ -7650,13 +7744,13 @@ proc gettree {id} { | ||
2123 | if {![info exists treefilelist($id)]} { | ||
2124 | if {![info exists treepending]} { | ||
2125 | if {$id eq $nullid} { | ||
2126 | - set cmd [list | git ls-files] | ||
2127 | + set cmd [list git ls-files] | ||
2128 | } elseif {$id eq $nullid2} { | ||
2129 | - set cmd [list | git ls-files --stage -t] | ||
2130 | + set cmd [list git ls-files --stage -t] | ||
2131 | } else { | ||
2132 | - set cmd [list | git ls-tree -r $id] | ||
2133 | + set cmd [list git ls-tree -r $id] | ||
2134 | } | ||
2135 | - if {[catch {set gtf [open $cmd r]}]} { | ||
2136 | + if {[catch {set gtf [safe_open_command $cmd]}]} { | ||
2137 | return | ||
2138 | } | ||
2139 | set treepending $id | ||
2140 | @@ -7720,13 +7814,13 @@ proc showfile {f} { | ||
2141 | return | ||
2142 | } | ||
2143 | if {$diffids eq $nullid} { | ||
2144 | - if {[catch {set bf [open $f r]} err]} { | ||
2145 | + if {[catch {set bf [safe_open_file $f r]} err]} { | ||
2146 | puts "oops, can't read $f: $err" | ||
2147 | return | ||
2148 | } | ||
2149 | } else { | ||
2150 | set blob [lindex $treeidlist($diffids) $i] | ||
2151 | - if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} { | ||
2152 | + if {[catch {set bf [safe_open_command [concat git cat-file blob $blob]]} err]} { | ||
2153 | puts "oops, error reading blob $blob: $err" | ||
2154 | return | ||
2155 | } | ||
2156 | @@ -7876,7 +7970,7 @@ proc diffcmd {ids flags} { | ||
2157 | if {$i >= 0} { | ||
2158 | if {[llength $ids] > 1 && $j < 0} { | ||
2159 | # comparing working directory with some specific revision | ||
2160 | - set cmd [concat | git diff-index $flags] | ||
2161 | + set cmd [concat git diff-index $flags] | ||
2162 | if {$i == 0} { | ||
2163 | lappend cmd -R [lindex $ids 1] | ||
2164 | } else { | ||
2165 | @@ -7884,7 +7978,7 @@ proc diffcmd {ids flags} { | ||
2166 | } | ||
2167 | } else { | ||
2168 | # comparing working directory with index | ||
2169 | - set cmd [concat | git diff-files $flags] | ||
2170 | + set cmd [concat git diff-files $flags] | ||
2171 | if {$j == 1} { | ||
2172 | lappend cmd -R | ||
2173 | } | ||
2174 | @@ -7893,7 +7987,7 @@ proc diffcmd {ids flags} { | ||
2175 | if {[package vcompare $git_version "1.7.2"] >= 0} { | ||
2176 | set flags "$flags --ignore-submodules=dirty" | ||
2177 | } | ||
2178 | - set cmd [concat | git diff-index --cached $flags] | ||
2179 | + set cmd [concat git diff-index --cached $flags] | ||
2180 | if {[llength $ids] > 1} { | ||
2181 | # comparing index with specific revision | ||
2182 | if {$j == 0} { | ||
2183 | @@ -7909,7 +8003,7 @@ proc diffcmd {ids flags} { | ||
2184 | if {$log_showroot} { | ||
2185 | lappend flags --root | ||
2186 | } | ||
2187 | - set cmd [concat | git diff-tree -r $flags $ids] | ||
2188 | + set cmd [concat git diff-tree -r $flags $ids] | ||
2189 | } | ||
2190 | return $cmd | ||
2191 | } | ||
2192 | @@ -7921,7 +8015,7 @@ proc gettreediffs {ids} { | ||
2193 | if {$limitdiffs && $vfilelimit($curview) ne {}} { | ||
2194 | set cmd [concat $cmd -- $vfilelimit($curview)] | ||
2195 | } | ||
2196 | - if {[catch {set gdtf [open $cmd r]}]} return | ||
2197 | + if {[catch {set gdtf [safe_open_command $cmd]}]} return | ||
2198 | |||
2199 | set treepending $ids | ||
2200 | set treediff {} | ||
2201 | @@ -8041,7 +8135,7 @@ proc getblobdiffs {ids} { | ||
2202 | if {$limitdiffs && $vfilelimit($curview) ne {}} { | ||
2203 | set cmd [concat $cmd -- $vfilelimit($curview)] | ||
2204 | } | ||
2205 | - if {[catch {set bdf [open $cmd r]} err]} { | ||
2206 | + if {[catch {set bdf [safe_open_command $cmd]} err]} { | ||
2207 | error_popup [mc "Error getting diffs: %s" $err] | ||
2208 | return | ||
2209 | } | ||
2210 | @@ -8758,7 +8852,7 @@ proc gotocommit {} { | ||
2211 | set id [lindex $matches 0] | ||
2212 | } | ||
2213 | } else { | ||
2214 | - if {[catch {set id [exec git rev-parse --verify $sha1string]}]} { | ||
2215 | + if {[catch {set id [safe_exec [list git rev-parse --verify $sha1string]]}]} { | ||
2216 | error_popup [mc "Revision %s is not known" $sha1string] | ||
2217 | return | ||
2218 | } | ||
2219 | @@ -9064,10 +9158,8 @@ proc getpatchid {id} { | ||
2220 | |||
2221 | if {![info exists patchids($id)]} { | ||
2222 | set cmd [diffcmd [list $id] {-p --root}] | ||
2223 | - # trim off the initial "|" | ||
2224 | - set cmd [lrange $cmd 1 end] | ||
2225 | if {[catch { | ||
2226 | - set x [eval exec $cmd | git patch-id] | ||
2227 | + set x [safe_exec_redirect $cmd [list | git patch-id]] | ||
2228 | set patchids($id) [lindex $x 0] | ||
2229 | }]} { | ||
2230 | set patchids($id) "error" | ||
2231 | @@ -9163,14 +9255,14 @@ proc diffcommits {a b} { | ||
2232 | set fna [file join $tmpdir "commit-[string range $a 0 7]"] | ||
2233 | set fnb [file join $tmpdir "commit-[string range $b 0 7]"] | ||
2234 | if {[catch { | ||
2235 | - exec git diff-tree -p --pretty $a >$fna | ||
2236 | - exec git diff-tree -p --pretty $b >$fnb | ||
2237 | + safe_exec_redirect [list git diff-tree -p --pretty $a] [list >$fna] | ||
2238 | + safe_exec_redirect [list git diff-tree -p --pretty $b] [list >$fnb] | ||
2239 | } err]} { | ||
2240 | error_popup [mc "Error writing commit to file: %s" $err] | ||
2241 | return | ||
2242 | } | ||
2243 | if {[catch { | ||
2244 | - set fd [open "| diff -U$diffcontext $fna $fnb" r] | ||
2245 | + set fd [safe_open_command "diff -U$diffcontext $fna $fnb"] | ||
2246 | } err]} { | ||
2247 | error_popup [mc "Error diffing commits: %s" $err] | ||
2248 | return | ||
2249 | @@ -9310,10 +9402,7 @@ proc mkpatchgo {} { | ||
2250 | set newid [$patchtop.tosha1 get] | ||
2251 | set fname [$patchtop.fname get] | ||
2252 | set cmd [diffcmd [list $oldid $newid] -p] | ||
2253 | - # trim off the initial "|" | ||
2254 | - set cmd [lrange $cmd 1 end] | ||
2255 | - lappend cmd >$fname & | ||
2256 | - if {[catch {eval exec $cmd} err]} { | ||
2257 | + if {[catch {safe_exec_redirect $cmd [list >$fname &]} err]} { | ||
2258 | error_popup "[mc "Error creating patch:"] $err" $patchtop | ||
2259 | } | ||
2260 | catch {destroy $patchtop} | ||
2261 | @@ -9382,9 +9471,9 @@ proc domktag {} { | ||
2262 | } | ||
2263 | if {[catch { | ||
2264 | if {$msg != {}} { | ||
2265 | - exec git tag -a -m $msg $tag $id | ||
2266 | + safe_exec [list git tag -a -m $msg $tag $id] | ||
2267 | } else { | ||
2268 | - exec git tag $tag $id | ||
2269 | + safe_exec [list git tag $tag $id] | ||
2270 | } | ||
2271 | } err]} { | ||
2272 | error_popup "[mc "Error creating tag:"] $err" $mktagtop | ||
2273 | @@ -9452,7 +9541,7 @@ proc copyreference {} { | ||
2274 | if {$autosellen < 40} { | ||
2275 | lappend cmd --abbrev=$autosellen | ||
2276 | } | ||
2277 | - set reference [eval exec $cmd $rowmenuid] | ||
2278 | + set reference [safe_exec [concat $cmd $rowmenuid]] | ||
2279 | |||
2280 | clipboard clear | ||
2281 | clipboard append $reference | ||
2282 | @@ -9502,7 +9591,7 @@ proc wrcomgo {} { | ||
2283 | set id [$wrcomtop.sha1 get] | ||
2284 | set cmd "echo $id | [$wrcomtop.cmd get]" | ||
2285 | set fname [$wrcomtop.fname get] | ||
2286 | - if {[catch {exec sh -c $cmd >$fname &} err]} { | ||
2287 | + if {[catch {safe_exec_redirect [list sh -c $cmd] [list >$fname &]} err]} { | ||
2288 | error_popup "[mc "Error writing commit:"] $err" $wrcomtop | ||
2289 | } | ||
2290 | catch {destroy $wrcomtop} | ||
2291 | @@ -9606,7 +9695,7 @@ proc mkbrgo {top} { | ||
2292 | nowbusy newbranch | ||
2293 | update | ||
2294 | if {[catch { | ||
2295 | - eval exec git branch $cmdargs | ||
2296 | + safe_exec [concat git branch $cmdargs] | ||
2297 | } err]} { | ||
2298 | notbusy newbranch | ||
2299 | error_popup $err | ||
2300 | @@ -9647,7 +9736,7 @@ proc mvbrgo {top prevname} { | ||
2301 | nowbusy renamebranch | ||
2302 | update | ||
2303 | if {[catch { | ||
2304 | - eval exec git branch $cmdargs | ||
2305 | + safe_exec [concat git branch $cmdargs] | ||
2306 | } err]} { | ||
2307 | notbusy renamebranch | ||
2308 | error_popup $err | ||
2309 | @@ -9688,7 +9777,7 @@ proc exec_citool {tool_args {baseid {}}} { | ||
2310 | } | ||
2311 | } | ||
2312 | |||
2313 | - eval exec git citool $tool_args & | ||
2314 | + safe_exec_redirect [concat git citool $tool_args] [list &] | ||
2315 | |||
2316 | array unset env GIT_AUTHOR_* | ||
2317 | array set env $save_env | ||
2318 | @@ -9711,7 +9800,7 @@ proc cherrypick {} { | ||
2319 | update | ||
2320 | # Unfortunately git-cherry-pick writes stuff to stderr even when | ||
2321 | # no error occurs, and exec takes that as an indication of error... | ||
2322 | - if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} { | ||
2323 | + if {[catch {safe_exec [list sh -c "git cherry-pick -r $rowmenuid 2>&1"]} err]} { | ||
2324 | notbusy cherrypick | ||
2325 | if {[regexp -line \ | ||
2326 | {Entry '(.*)' (would be overwritten by merge|not uptodate)} \ | ||
2327 | @@ -9773,7 +9862,7 @@ proc revert {} { | ||
2328 | nowbusy revert [mc "Reverting"] | ||
2329 | update | ||
2330 | |||
2331 | - if [catch {exec git revert --no-edit $rowmenuid} err] { | ||
2332 | + if [catch {safe_exec [list git revert --no-edit $rowmenuid]} err] { | ||
2333 | notbusy revert | ||
2334 | if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\ | ||
2335 | $err match files] { | ||
2336 | @@ -9849,8 +9938,8 @@ proc resethead {} { | ||
2337 | bind $w <Visibility> "grab $w; focus $w" | ||
2338 | tkwait window $w | ||
2339 | if {!$confirm_ok} return | ||
2340 | - if {[catch {set fd [open \ | ||
2341 | - [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} { | ||
2342 | + if {[catch {set fd [safe_open_command_redirect \ | ||
2343 | + [list git reset --$resettype $rowmenuid] [list 2>@1]]} err]} { | ||
2344 | error_popup $err | ||
2345 | } else { | ||
2346 | dohidelocalchanges | ||
2347 | @@ -9921,7 +10010,7 @@ proc cobranch {} { | ||
2348 | |||
2349 | # check the tree is clean first?? | ||
2350 | set newhead $headmenuhead | ||
2351 | - set command [list | git checkout] | ||
2352 | + set command [list git checkout] | ||
2353 | if {[string match "remotes/*" $newhead]} { | ||
2354 | set remote $newhead | ||
2355 | set newhead [string range $newhead [expr [string last / $newhead] + 1] end] | ||
2356 | @@ -9935,12 +10024,11 @@ proc cobranch {} { | ||
2357 | } else { | ||
2358 | lappend command $newhead | ||
2359 | } | ||
2360 | - lappend command 2>@1 | ||
2361 | nowbusy checkout [mc "Checking out"] | ||
2362 | update | ||
2363 | dohidelocalchanges | ||
2364 | if {[catch { | ||
2365 | - set fd [open $command r] | ||
2366 | + set fd [safe_open_command_redirect $command [list 2>@1]] | ||
2367 | } err]} { | ||
2368 | notbusy checkout | ||
2369 | error_popup $err | ||
2370 | @@ -10006,7 +10094,7 @@ proc rmbranch {} { | ||
2371 | } | ||
2372 | nowbusy rmbranch | ||
2373 | update | ||
2374 | - if {[catch {exec git branch -D $head} err]} { | ||
2375 | + if {[catch {safe_exec [list git branch -D $head]} err]} { | ||
2376 | notbusy rmbranch | ||
2377 | error_popup $err | ||
2378 | return | ||
2379 | @@ -10197,7 +10285,7 @@ proc getallcommits {} { | ||
2380 | set cachedarcs 0 | ||
2381 | set allccache [file join $gitdir "gitk.cache"] | ||
2382 | if {![catch { | ||
2383 | - set f [open $allccache r] | ||
2384 | + set f [safe_open_file $allccache r] | ||
2385 | set allcwait 1 | ||
2386 | getcache $f | ||
2387 | }]} return | ||
2388 | @@ -10206,7 +10294,7 @@ proc getallcommits {} { | ||
2389 | if {$allcwait} { | ||
2390 | return | ||
2391 | } | ||
2392 | - set cmd [list | git rev-list --parents] | ||
2393 | + set cmd [list git rev-list --parents] | ||
2394 | set allcupdate [expr {$seeds ne {}}] | ||
2395 | if {!$allcupdate} { | ||
2396 | set ids "--all" | ||
2397 | @@ -10228,10 +10316,17 @@ proc getallcommits {} { | ||
2398 | foreach id $seeds { | ||
2399 | lappend ids "^$id" | ||
2400 | } | ||
2401 | + lappend ids "--" | ||
2402 | } | ||
2403 | } | ||
2404 | if {$ids ne {}} { | ||
2405 | - set fd [open [concat $cmd $ids] r] | ||
2406 | + if {$ids eq "--all"} { | ||
2407 | + set cmd [concat $cmd "--all"] | ||
2408 | + set fd [safe_open_command $cmd] | ||
2409 | + } else { | ||
2410 | + set cmd [concat $cmd --stdin] | ||
2411 | + set fd [safe_open_command_redirect $cmd [list "<<[join $ids "\n"]"]] | ||
2412 | + } | ||
2413 | fconfigure $fd -blocking 0 | ||
2414 | incr allcommits | ||
2415 | nowbusy allcommits | ||
2416 | @@ -10621,7 +10716,7 @@ proc savecache {} { | ||
2417 | set cachearc 0 | ||
2418 | set cachedarcs $nextarc | ||
2419 | catch { | ||
2420 | - set f [open $allccache w] | ||
2421 | + set f [safe_open_file $allccache w] | ||
2422 | puts $f [list 1 $cachedarcs] | ||
2423 | run writecache $f | ||
2424 | } | ||
2425 | @@ -11324,7 +11419,7 @@ proc add_tag_ctext {tag} { | ||
2426 | |||
2427 | if {![info exists cached_tagcontent($tag)]} { | ||
2428 | catch { | ||
2429 | - set cached_tagcontent($tag) [exec git cat-file -p $tag] | ||
2430 | + set cached_tagcontent($tag) [safe_exec [list git cat-file -p $tag]] | ||
2431 | } | ||
2432 | } | ||
2433 | $ctext insert end "[mc "Tag"]: $tag\n" bold | ||
2434 | @@ -11927,7 +12022,7 @@ proc formatdate {d} { | ||
2435 | } | ||
2436 | |||
2437 | # This list of encoding names and aliases is distilled from | ||
2438 | -# http://www.iana.org/assignments/character-sets. | ||
2439 | +# https://www.iana.org/assignments/character-sets. | ||
2440 | # Not all of them are supported by Tcl. | ||
2441 | set encoding_aliases { | ||
2442 | { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII | ||
2443 | @@ -12210,7 +12305,7 @@ proc gitattr {path attr default} { | ||
2444 | set r $path_attr_cache($attr,$path) | ||
2445 | } else { | ||
2446 | set r "unspecified" | ||
2447 | - if {![catch {set line [exec git check-attr $attr -- $path]}]} { | ||
2448 | + if {![catch {set line [safe_exec [list git check-attr $attr -- $path]]}]} { | ||
2449 | regexp "(.*): $attr: (.*)" $line m f r | ||
2450 | } | ||
2451 | set path_attr_cache($attr,$path) $r | ||
2452 | @@ -12237,7 +12332,7 @@ proc cache_gitattr {attr pathlist} { | ||
2453 | while {$newlist ne {}} { | ||
2454 | set head [lrange $newlist 0 [expr {$lim - 1}]] | ||
2455 | set newlist [lrange $newlist $lim end] | ||
2456 | - if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} { | ||
2457 | + if {![catch {set rlist [safe_exec [concat git check-attr $attr -- $head]]}]} { | ||
2458 | foreach row [split $rlist "\n"] { | ||
2459 | if {[regexp "(.*): $attr: (.*)" $row m path value]} { | ||
2460 | if {[string index $path 0] eq "\""} { | ||
2461 | @@ -12290,11 +12385,11 @@ if {[catch {package require Tk 8.4} err]} { | ||
2462 | |||
2463 | # on OSX bring the current Wish process window to front | ||
2464 | if {[tk windowingsystem] eq "aqua"} { | ||
2465 | - exec osascript -e [format { | ||
2466 | + safe_exec [list osascript -e [format { | ||
2467 | tell application "System Events" | ||
2468 | set frontmost of processes whose unix id is %d to true | ||
2469 | end tell | ||
2470 | - } [pid] ] | ||
2471 | + } [pid] ]] | ||
2472 | } | ||
2473 | |||
2474 | # Unset GIT_TRACE var if set | ||
2475 | @@ -12443,7 +12538,7 @@ if {[tk windowingsystem] eq "aqua"} { | ||
2476 | |||
2477 | catch { | ||
2478 | # follow the XDG base directory specification by default. See | ||
2479 | - # http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
2480 | + # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
2481 | if {[info exists env(XDG_CONFIG_HOME)] && $env(XDG_CONFIG_HOME) ne ""} { | ||
2482 | # XDG_CONFIG_HOME environment variable is set | ||
2483 | set config_file [file join $env(XDG_CONFIG_HOME) git gitk] | ||
2484 | @@ -12539,7 +12634,7 @@ if {$selecthead eq "HEAD"} { | ||
2485 | if {$i >= [llength $argv] && $revtreeargs ne {}} { | ||
2486 | # no -- on command line, but some arguments (other than --argscmd) | ||
2487 | if {[catch { | ||
2488 | - set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs] | ||
2489 | + set f [safe_exec [concat git rev-parse --no-revs --no-flags $revtreeargs]] | ||
2490 | set cmdline_files [split $f "\n"] | ||
2491 | set n [llength $cmdline_files] | ||
2492 | set revtreeargs [lrange $revtreeargs 0 end-$n] | ||
2493 | @@ -12705,3 +12800,4 @@ getcommits {} | ||
2494 | # indent-tabs-mode: t | ||
2495 | # tab-width: 8 | ||
2496 | # End: | ||
2497 | + | ||
2498 | -- | ||
2499 | 2.50.1 | ||
2500 | |||
diff --git a/meta/recipes-devtools/git/git_2.35.7.bb b/meta/recipes-devtools/git/git_2.35.7.bb index 765180a38d..3520b4db90 100644 --- a/meta/recipes-devtools/git/git_2.35.7.bb +++ b/meta/recipes-devtools/git/git_2.35.7.bb | |||
@@ -26,6 +26,7 @@ SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \ | |||
26 | file://CVE-2024-50349-0001.patch \ | 26 | file://CVE-2024-50349-0001.patch \ |
27 | file://CVE-2024-50349-0002.patch \ | 27 | file://CVE-2024-50349-0002.patch \ |
28 | file://CVE-2024-52006.patch \ | 28 | file://CVE-2024-52006.patch \ |
29 | file://CVE-2025-27614-CVE-2025-27613-CVE-2025-46334-CVE-2025-46835.patch \ | ||
29 | " | 30 | " |
30 | 31 | ||
31 | S = "${WORKDIR}/git-${PV}" | 32 | S = "${WORKDIR}/git-${PV}" |