File CVE-2025-46835.patch of Package git.37096
From 4774c704d20e50ad710f65756099c3eedbfbe789 Mon Sep 17 00:00:00 2001
From: Mark Levedahl <mlevedahl@gmail.com>
Date: Wed, 20 Sep 2023 17:56:14 -0400
Subject: [PATCH 01/15] git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
Since b792230 ("git-gui: Show a progress meter for checking out files",
2007-07-08), git-gui includes a workaround for Tcl that does not support
using 2>@1 to redirect stderr to stdout. Tcl added such support in
8.4.7, released in 2004, and this is fully supported in all 8.5
releases.
As git-gui has a hard-coded requirement for Tcl >= 8.5, the workaround
is no longer needed. Delete it.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
git-gui.sh | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
Index: b/git-gui/git-gui.sh
===================================================================
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -44,6 +44,56 @@ if {[catch {package require Tcl 8.5} err
catch {rename send {}} ; # What an evil concept...
+# Wrap exec/open to sanitize arguments
+
+# unsafe arguments begin with redirections or the pipe or background operators
+proc is_arg_unsafe {arg} {
+ regexp {^([<|>&]|2>)} $arg
+}
+
+proc make_arg_safe {arg} {
+ if {[is_arg_unsafe $arg]} {
+ set arg [file join . $arg]
+ }
+ return $arg
+}
+
+proc make_arglist_safe {arglist} {
+ set res {}
+ foreach arg $arglist {
+ lappend res [make_arg_safe $arg]
+ }
+ return $res
+}
+
+# executes one command
+# no redirections or pipelines are possible
+# cmd is a list that specifies the command and its arguments
+# calls `exec` and returns its value
+proc safe_exec {cmd} {
+ eval exec [make_arglist_safe $cmd]
+}
+
+# executes one command in the background
+# no redirections or pipelines are possible
+# cmd is a list that specifies the command and its arguments
+# calls `exec` and returns its value
+proc safe_exec_bg {cmd} {
+ eval exec [make_arglist_safe $cmd] &
+}
+
+proc safe_open_file {filename flags} {
+ # a file name starting with "|" would attempt to run a process
+ # but such a file name must be treated as a relative path
+ # hide the "|" behind "./"
+ if {[string index $filename 0] eq "|"} {
+ set filename [file join . $filename]
+ }
+ open $filename $flags
+}
+
+# End exec/open wrappers
+
######################################################################
##
## locate our library
@@ -144,11 +194,11 @@ unset oguimsg
if {[tk windowingsystem] eq "aqua"} {
catch {
- exec osascript -e [format {
+ safe_exec [list osascript -e [format {
tell application "System Events"
set frontmost of processes whose unix id is %d to true
end tell
- } [pid]]
+ } [pid]]]
}
}
@@ -418,7 +468,7 @@ proc _git_cmd {name} {
# Tcl on Windows doesn't know it.
#
set p [gitexec git-$name]
- set f [open $p r]
+ set f [safe_open_file $p r]
set s [gets $f]
close $f
@@ -489,7 +539,7 @@ proc _which {what args} {
# Test a file for a hashbang to identify executable scripts on Windows.
proc is_shellscript {filename} {
if {![file exists $filename]} {return 0}
- set f [open $filename r]
+ set f [safe_open_file $filename r]
fconfigure $f -encoding binary
set magic [read $f 2]
close $f
@@ -512,6 +562,7 @@ proc open_cmd_pipe {cmd path} {
} else {
set run [list [shellpath] -c "$cmd \"\$0\"" $path]
}
+ set run [make_arglist_safe $run]
return [open |$run r]
}
@@ -521,7 +572,7 @@ proc _lappend_nice {cmd_var} {
if {![info exists _nice]} {
set _nice [_which nice]
- if {[catch {exec $_nice git version}]} {
+ if {[catch {safe_exec [list $_nice git version]}]} {
set _nice {}
} elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} {
set _nice {}
@@ -533,7 +584,11 @@ proc _lappend_nice {cmd_var} {
}
proc git {args} {
- set fd [eval [list git_read] $args]
+ git_redir $args {}
+}
+
+proc git_redir {cmd redir} {
+ set fd [git_read $cmd $redir]
fconfigure $fd -translation binary -encoding utf-8
set result [string trimright [read $fd] "\n"]
close $fd
@@ -543,88 +598,47 @@ proc git {args} {
return $result
}
-proc _open_stdout_stderr {cmd} {
- _trace_exec $cmd
+proc safe_open_command {cmd {redir {}}} {
+ set cmd [make_arglist_safe $cmd]
+ _trace_exec [concat $cmd $redir]
if {[catch {
- set fd [open [concat [list | ] $cmd] r]
- } err]} {
- if { [lindex $cmd end] eq {2>@1}
- && $err eq {can not find channel named "1"}
- } {
- # Older versions of Tcl 8.4 don't have this 2>@1 IO
- # redirect operator. Fallback to |& cat for those.
- # The command was not actually started, so its safe
- # to try to start it a second time.
- #
- set fd [open [concat \
- [list | ] \
- [lrange $cmd 0 end-1] \
- [list |& cat] \
- ] r]
- } else {
- error $err
- }
+ set fd [open [concat [list | ] $cmd $redir] r]
+ } err]} {
+ error $err
}
fconfigure $fd -eofchar {}
return $fd
}
-proc git_read {args} {
- set opt [list]
-
- while {1} {
- switch -- [lindex $args 0] {
- --nice {
- _lappend_nice opt
- }
-
- --stderr {
- lappend args 2>@1
- }
+proc git_read {cmd {redir {}}} {
+ set cmdp [_git_cmd [lindex $cmd 0]]
+ set cmd [lrange $cmd 1 end]
- default {
- break
- }
-
- }
-
- set args [lrange $args 1 end]
- }
-
- set cmdp [_git_cmd [lindex $args 0]]
- set args [lrange $args 1 end]
-
- return [_open_stdout_stderr [concat $opt $cmdp $args]]
+ return [safe_open_command [concat $cmdp $cmd] $redir]
}
-proc git_write {args} {
+proc git_read_nice {cmd} {
set opt [list]
- while {1} {
- switch -- [lindex $args 0] {
- --nice {
- _lappend_nice opt
- }
+ _lappend_nice opt
- default {
- break
- }
+ set cmdp [_git_cmd [lindex $cmd 0]]
+ set cmd [lrange $cmd 1 end]
- }
-
- set args [lrange $args 1 end]
- }
+ return [safe_open_command [concat $opt $cmdp $cmd]]
+}
- set cmdp [_git_cmd [lindex $args 0]]
- set args [lrange $args 1 end]
+proc git_write {cmd} {
+ set cmd [make_arglist_safe $cmd]
+ set cmdp [_git_cmd [lindex $cmd 0]]
+ set cmd [lrange $cmd 1 end]
- _trace_exec [concat $opt $cmdp $args]
- return [open [concat [list | ] $opt $cmdp $args] w]
+ _trace_exec [concat $cmdp $cmd]
+ return [open [concat [list | ] $cmdp $cmd] w]
}
proc githook_read {hook_name args} {
set pchook [gitdir hooks $hook_name]
- lappend args 2>@1
# On Windows [file executable] might lie so we need to ask
# the shell if the hook is executable. Yes that's annoying.
@@ -640,11 +654,11 @@ proc githook_read {hook_name args} {
set scr {if test -x "$1";then exec "$@";fi}
set sh_c [list $interp -c $scr $interp $pchook]
- return [_open_stdout_stderr [concat $sh_c $args]]
+ return [safe_open_command [concat $sh_c $args] [list 2>@1]]
}
if {[file executable $pchook]} {
- return [_open_stdout_stderr [concat [list $pchook] $args]]
+ return [safe_open_command [concat [list $pchook] $args] [list 2>@1]]
}
return {}
@@ -655,9 +669,9 @@ proc kill_file_process {fd} {
catch {
if {[is_Windows]} {
- exec taskkill /pid $process
+ safe_exec [list taskkill /pid $process]
} else {
- exec kill $process
+ safe_exec [list kill $process]
}
}
}
@@ -683,7 +697,7 @@ proc sq {value} {
proc load_current_branch {} {
global current_branch is_detached
- set fd [open [gitdir HEAD] r]
+ set fd [safe_open_file [gitdir HEAD] r]
fconfigure $fd -translation binary -encoding utf-8
if {[gets $fd ref] < 1} {
set ref {}
@@ -1045,7 +1059,7 @@ You are using [git-version]:
## configure our library
set idx [file join $oguilib tclIndex]
-if {[catch {set fd [open $idx r]} err]} {
+if {[catch {set fd [safe_open_file $idx r]} err]} {
catch {wm withdraw .}
tk_messageBox \
-icon error \
@@ -1083,53 +1097,30 @@ unset -nocomplain idx fd
##
## config file parsing
-git-version proc _parse_config {arr_name args} {
- >= 1.5.3 {
- upvar $arr_name arr
- array unset arr
- set buf {}
- catch {
- set fd_rc [eval \
- [list git_read config] \
- $args \
- [list --null --list]]
- fconfigure $fd_rc -translation binary -encoding utf-8
- set buf [read $fd_rc]
- close $fd_rc
- }
- foreach line [split $buf "\0"] {
- if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
- if {[is_many_config $name]} {
- lappend arr($name) $value
- } else {
- set arr($name) $value
- }
- } elseif {[regexp {^([^\n]+)$} $line line name]} {
- # no value given, but interpreting them as
- # boolean will be handled as true
- set arr($name) {}
- }
- }
- }
- default {
- upvar $arr_name arr
- array unset arr
- catch {
- set fd_rc [eval [list git_read config --list] $args]
- while {[gets $fd_rc line] >= 0} {
- if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
- if {[is_many_config $name]} {
- lappend arr($name) $value
- } else {
- set arr($name) $value
- }
- } elseif {[regexp {^([^=]+)$} $line line name]} {
- # no value given, but interpreting them as
- # boolean will be handled as true
- set arr($name) {}
- }
+proc _parse_config {arr_name args} {
+ upvar $arr_name arr
+ array unset arr
+ set buf {}
+ catch {
+ set fd_rc [eval \
+ [list git_read config] \
+ $args \
+ [list --null --list]]
+ fconfigure $fd_rc -translation binary -encoding utf-8
+ set buf [read $fd_rc]
+ close $fd_rc
+ }
+ foreach line [split $buf "\0"] {
+ if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
+ if {[is_many_config $name]} {
+ lappend arr($name) $value
+ } else {
+ set arr($name) $value
}
- close $fd_rc
+ } elseif {[regexp {^([^\n]+)$} $line line name]} {
+ # no value given, but interpreting them as
+ # boolean will be handled as true
+ set arr($name) {}
}
}
}
@@ -1412,7 +1403,7 @@ proc repository_state {ctvar hdvar mhvar
set merge_head [gitdir MERGE_HEAD]
if {[file exists $merge_head]} {
set ct merge
- set fd_mh [open $merge_head r]
+ set fd_mh [safe_open_file $merge_head r]
while {[gets $fd_mh line] >= 0} {
lappend mh $line
}
@@ -1431,7 +1422,7 @@ proc PARENT {} {
return $p
}
if {$empty_tree eq {}} {
- set empty_tree [git mktree << {}]
+ set empty_tree [git_redir [list mktree] [list << {}]]
}
return $empty_tree
}
@@ -1575,7 +1566,7 @@ proc load_message {file {encoding {}}} {
set f [gitdir $file]
if {[file isfile $f]} {
- if {[catch {set fd [open $f r]}]} {
+ if {[catch {set fd [safe_open_file $f r]}]} {
return 0
}
fconfigure $fd -eofchar {}
@@ -1599,17 +1590,17 @@ proc run_prepare_commit_msg_hook {} {
# it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
# empty file but existent file.
- set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
+ set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a]
if {[file isfile [gitdir MERGE_MSG]]} {
set pcm_source "merge"
- set fd_mm [open [gitdir MERGE_MSG] r]
+ set fd_mm [safe_open_file [gitdir MERGE_MSG] r]
fconfigure $fd_mm -encoding utf-8
puts -nonewline $fd_pcm [read $fd_mm]
close $fd_mm
} elseif {[file isfile [gitdir SQUASH_MSG]]} {
set pcm_source "squash"
- set fd_sm [open [gitdir SQUASH_MSG] r]
+ set fd_sm [safe_open_file [gitdir SQUASH_MSG] r]
fconfigure $fd_sm -encoding utf-8
puts -nonewline $fd_pcm [read $fd_sm]
close $fd_sm
@@ -2199,7 +2190,7 @@ proc do_gitk {revs {is_submodule false}}
unset env(GIT_DIR)
unset env(GIT_WORK_TREE)
}
- eval exec $cmd $revs "--" "--" &
+ safe_exec_bg [concat $cmd $revs "--" "--"]
set env(GIT_DIR) $_gitdir
set env(GIT_WORK_TREE) $_gitworktree
@@ -2236,7 +2227,7 @@ proc do_git_gui {} {
set pwd [pwd]
cd $current_diff_path
- eval exec $exe gui &
+ safe_exec_bg [concat $exe gui]
set env(GIT_DIR) $_gitdir
set env(GIT_WORK_TREE) $_gitworktree
@@ -2265,16 +2256,18 @@ proc get_explorer {} {
proc do_explore {} {
global _gitworktree
- set explorer [get_explorer]
- eval exec $explorer [list [file nativename $_gitworktree]] &
+ set cmd [get_explorer]
+ lappend cmd [file nativename $_gitworktree]
+ safe_exec_bg $cmd
}
# Open file relative to the working tree by the default associated app.
proc do_file_open {file} {
global _gitworktree
- set explorer [get_explorer]
+ set cmd [get_explorer]
set full_file_path [file join $_gitworktree $file]
- exec $explorer [file nativename $full_file_path] &
+ lappend cmd [file nativename $full_file_path]
+ safe_exec_bg $cmd
}
set is_quitting 0
@@ -2757,13 +2750,13 @@ if {[is_Windows]} {
regsub "/mingw../libexec/git-core/git-gui$" \
$normalized "/git-bash.exe" cmdLine
if {$cmdLine != $normalized && [file exists $cmdLine]} {
- set cmdLine [list "Git Bash" $cmdLine &]
+ set cmdLine [list "Git Bash" $cmdLine]
} else {
- set cmdLine [list "Git Bash" bash --login -l &]
+ set cmdLine [list "Git Bash" bash --login -l]
}
.mbar.repository add command \
-label [mc "Git Bash"] \
- -command {eval exec [auto_execok start] $cmdLine}
+ -command {safe_exec_bg [concat [list [auto_execok start]] $cmdLine]}
}
if {[is_Windows] || ![is_bare]} {
Index: b/git-gui/lib/checkout_op.tcl
===================================================================
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -304,12 +304,12 @@ The rescan will be automatically started
_readtree $this
} else {
ui_status [mc "Refreshing file status..."]
- set fd [git_read update-index \
+ set fd [git_read [list update-index \
-q \
--unmerged \
--ignore-missing \
--refresh \
- ]
+ ]]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _refresh_wait $fd]
}
@@ -345,14 +345,15 @@ method _readtree {} {
[mc "Updating working directory to '%s'..." [_name $this]] \
[mc "files checked out"]]
- set fd [git_read --stderr read-tree \
+ set fd [git_read [list read-tree \
-m \
-u \
-v \
--exclude-per-directory=.gitignore \
$HEAD \
$new_hash \
- ]
+ ] \
+ [list 2>@1]]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation]
}
@@ -510,18 +511,8 @@ method _update_repo_state {} {
delete_this
}
-git-version proc _detach_HEAD {log new} {
- >= 1.5.3 {
- git update-ref --no-deref -m $log HEAD $new
- }
- default {
- set p [gitdir HEAD]
- file delete $p
- set fd [open $p w]
- fconfigure $fd -translation lf -encoding utf-8
- puts $fd $new
- close $fd
- }
+proc _detach_HEAD {log new} {
+ git update-ref --no-deref -m $log HEAD $new
}
method _confirm_reset {cur} {
@@ -582,7 +573,7 @@ method _confirm_reset {cur} {
pack $w.buttons.cancel -side right -padx 5
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
- set fd [git_read rev-list --pretty=oneline $cur ^$new_hash]
+ set fd [git_read [list rev-list --pretty=oneline $cur ^$new_hash]]
while {[gets $fd line] > 0} {
set abbr [string range $line 0 7]
set subj [string range $line 41 end]
Index: b/git-gui/lib/blame.tcl
===================================================================
--- a/git-gui/lib/blame.tcl
+++ b/git-gui/lib/blame.tcl
@@ -480,14 +480,14 @@ method _load {jump} {
if {$do_textconv ne 0} {
set fd [open_cmd_pipe $textconv $path]
} else {
- set fd [open $path r]
+ set fd [safe_open_file $path r]
}
fconfigure $fd -eofchar {}
} else {
if {$do_textconv ne 0} {
- set fd [git_read cat-file --textconv "$commit:$path"]
+ set fd [git_read [list cat-file --textconv "$commit:$path"]]
} else {
- set fd [git_read cat-file blob "$commit:$path"]
+ set fd [git_read [list cat-file blob "$commit:$path"]]
}
}
fconfigure $fd \
@@ -616,7 +616,7 @@ method _exec_blame {cur_w cur_d options
}
lappend options -- $path
- set fd [eval git_read --nice blame $options]
+ set fd [git_read_nice [concat blame $options]]
fconfigure $fd -blocking 0 -translation lf -encoding utf-8
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
set current_fd $fd
@@ -985,7 +985,7 @@ method _showcommit {cur_w lno} {
if {[catch {set msg $header($cmit,message)}]} {
set msg {}
catch {
- set fd [git_read cat-file commit $cmit]
+ set fd [git_read [list cat-file commit $cmit]]
fconfigure $fd -encoding binary -translation lf
# By default commits are assumed to be in utf-8
set enc utf-8
@@ -1133,7 +1133,7 @@ method _blameparent {} {
} else {
set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
}
- if {[catch {set fd [eval git_read $diffcmd]} err]} {
+ if {[catch {set fd [git_read $diffcmd]} err]} {
$status_operation stop [mc "Unable to display parent"]
error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
return
Index: b/git-gui/lib/choose_repository.tcl
===================================================================
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -683,8 +683,8 @@ method _do_clone2 {} {
set pwd [pwd]
if {[catch {
file mkdir [gitdir objects info]
- set f_in [open [file join $objdir info alternates] r]
- set f_cp [open [gitdir objects info alternates] w]
+ set f_in [safe_open_file [file join $objdir info alternates] r]
+ set f_cp [safe_open_file [gitdir objects info alternates] w]
fconfigure $f_in -translation binary -encoding binary
fconfigure $f_cp -translation binary -encoding binary
cd $objdir
@@ -773,7 +773,7 @@ method _do_clone2 {} {
[cb _do_clone_tags]
}
shared {
- set fd [open [gitdir objects info alternates] w]
+ set fd [safe_open_file [gitdir objects info alternates] w]
fconfigure $fd -translation binary
puts $fd $objdir
close $fd
@@ -806,8 +806,8 @@ method _copy_files {objdir tocopy} {
}
foreach p $tocopy {
if {[catch {
- set f_in [open [file join $objdir $p] r]
- set f_cp [open [file join .git objects $p] w]
+ set f_in [safe_open_file [file join $objdir $p] r]
+ set f_cp [safe_open_file [file join .git objects $p] w]
fconfigure $f_in -translation binary -encoding binary
fconfigure $f_cp -translation binary -encoding binary
@@ -864,12 +864,12 @@ method _clone_refs {} {
error_popup [mc "Not a Git repository: %s" [file tail $origin_url]]
return 0
}
- set fd_in [git_read for-each-ref \
+ set fd_in [git_read [list for-each-ref \
--tcl \
- {--format=list %(refname) %(objectname) %(*objectname)}]
+ {--format=list %(refname) %(objectname) %(*objectname)}]]
cd $pwd
- set fd [open [gitdir packed-refs] w]
+ set fd [safe_open_file [gitdir packed-refs] w]
fconfigure $fd -translation binary
puts $fd "# pack-refs with: peeled"
while {[gets $fd_in line] >= 0} {
@@ -923,7 +923,7 @@ method _do_clone_full_end {ok} {
set HEAD {}
if {[file exists [gitdir FETCH_HEAD]]} {
- set fd [open [gitdir FETCH_HEAD] r]
+ set fd [safe_open_file [gitdir FETCH_HEAD] r]
while {[gets $fd line] >= 0} {
if {[regexp "^(.{40})\t\t" $line line HEAD]} {
break
@@ -999,13 +999,14 @@ method _do_clone_checkout {HEAD} {
[mc "files"]]
set readtree_err {}
- set fd [git_read --stderr read-tree \
+ set fd [git_read [list read-tree \
-m \
-u \
-v \
HEAD \
HEAD \
- ]
+ ] \
+ [list 2>@1]]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _readtree_wait $fd]
}
Index: b/git-gui/lib/choose_rev.tcl
===================================================================
--- a/git-gui/lib/choose_rev.tcl
+++ b/git-gui/lib/choose_rev.tcl
@@ -146,14 +146,14 @@ constructor _new {path unmerged_only tit
append fmt { %(*subject)}
append fmt {]}
set all_refn [list]
- set fr_fd [git_read for-each-ref \
+ set fr_fd [git_read [list for-each-ref \
--tcl \
--sort=-taggerdate \
--format=$fmt \
refs/heads \
refs/remotes \
refs/tags \
- ]
+ ]]
fconfigure $fr_fd -translation lf -encoding utf-8
while {[gets $fr_fd line] > 0} {
set line [eval $line]
@@ -176,7 +176,7 @@ constructor _new {path unmerged_only tit
close $fr_fd
if {$unmerged_only} {
- set fr_fd [git_read rev-list --all ^$::HEAD]
+ set fr_fd [git_read [list rev-list --all ^$::HEAD]]
while {[gets $fr_fd sha1] > 0} {
if {[catch {set rlst $cmt_refn($sha1)}]} continue
foreach refn $rlst {
@@ -579,7 +579,7 @@ method _reflog_last {name} {
set last {}
if {[catch {set last [file mtime [gitdir $name]]}]
- && ![catch {set g [open [gitdir logs $name] r]}]} {
+ && ![catch {set g [safe_open_file [gitdir logs $name] r]}]} {
fconfigure $g -translation binary
while {[gets $g line] >= 0} {
if {[regexp {> ([1-9][0-9]*) } $line line when]} {
Index: b/git-gui/lib/commit.tcl
===================================================================
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -27,7 +27,7 @@ You are currently in the middle of a mer
if {[catch {
set name ""
set email ""
- set fd [git_read cat-file commit $curHEAD]
+ set fd [git_read [list cat-file commit $curHEAD]]
fconfigure $fd -encoding binary -translation lf
# By default commits are assumed to be in utf-8
set enc utf-8
@@ -225,7 +225,7 @@ A good commit message has the following
# -- Build the message file.
#
set msg_p [gitdir GITGUI_EDITMSG]
- set msg_wt [open $msg_p w]
+ set msg_wt [safe_open_file $msg_p w]
fconfigure $msg_wt -translation lf
setup_commit_encoding $msg_wt
puts $msg_wt $msg
@@ -325,7 +325,7 @@ proc commit_commitmsg_wait {fd_ph curHEA
proc commit_writetree {curHEAD msg_p} {
ui_status [mc "Committing changes..."]
- set fd_wt [git_read write-tree]
+ set fd_wt [git_read [list write-tree]]
fileevent $fd_wt readable \
[list commit_committree $fd_wt $curHEAD $msg_p]
}
@@ -350,7 +350,7 @@ proc commit_committree {fd_wt curHEAD ms
# -- Verify this wasn't an empty change.
#
if {$commit_type eq {normal}} {
- set fd_ot [git_read cat-file commit $PARENT]
+ set fd_ot [git_read [list cat-file commit $PARENT]]
fconfigure $fd_ot -encoding binary -translation lf
set old_tree [gets $fd_ot]
close $fd_ot
@@ -388,8 +388,8 @@ A rescan will be automatically started n
foreach p [concat $PARENT $MERGE_HEAD] {
lappend cmd -p $p
}
- lappend cmd <$msg_p
- if {[catch {set cmt_id [eval git $cmd]} err]} {
+ set msgtxt [list <$msg_p]
+ if {[catch {set cmt_id [git_redir $cmd $msgtxt]} err]} {
catch {file delete $msg_p}
error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
ui_status [mc "Commit failed."]
@@ -409,7 +409,7 @@ A rescan will be automatically started n
if {$commit_type ne {normal}} {
append reflogm " ($commit_type)"
}
- set msg_fd [open $msg_p r]
+ set msg_fd [safe_open_file $msg_p r]
setup_commit_encoding $msg_fd 1
gets $msg_fd subject
close $msg_fd
Index: b/git-gui/lib/diff.tcl
===================================================================
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -202,7 +202,7 @@ proc show_other_diff {path w m cont_info
set sz [string length $content]
}
file {
- set fd [open $path r]
+ set fd [safe_open_file $path r]
fconfigure $fd \
-eofchar {} \
-encoding [get_path_encoding $path]
@@ -226,7 +226,7 @@ proc show_other_diff {path w m cont_info
$ui_diff insert end \
"* [mc "Git Repository (subproject)"]\n" \
d_info
- } elseif {![catch {set type [exec file $path]}]} {
+ } elseif {![catch {set type [safe_exec [list file $path]]}]} {
set n [string length $path]
if {[string equal -length $n $path $type]} {
set type [string range $type $n end]
@@ -338,7 +338,7 @@ proc start_show_diff {cont_info {add_opt
}
}
- if {[catch {set fd [eval git_read --nice $cmd]} err]} {
+ if {[catch {set fd [git_read_nice $cmd]} err]} {
set diff_active 0
unlock_index
ui_status [mc "Unable to display %s" [escape_path $path]]
@@ -617,7 +617,7 @@ proc apply_or_revert_hunk {x y revert} {
if {[catch {
set enc [get_path_encoding $current_diff_path]
- set p [eval git_write $apply_cmd]
+ set p [git_write $apply_cmd]
fconfigure $p -translation binary -encoding $enc
puts -nonewline $p $wholepatch
close $p} err]} {
@@ -853,7 +853,7 @@ proc apply_or_revert_range_or_line {x y
if {[catch {
set enc [get_path_encoding $current_diff_path]
- set p [eval git_write $apply_cmd]
+ set p [git_write $apply_cmd]
fconfigure $p -translation binary -encoding $enc
puts -nonewline $p $current_diff_header
puts -nonewline $p $wholepatch
@@ -890,7 +890,7 @@ proc undo_last_revert {} {
if {[catch {
set enc $last_revert_enc
- set p [eval git_write $apply_cmd]
+ set p [git_write $apply_cmd]
fconfigure $p -translation binary -encoding $enc
puts -nonewline $p $last_revert
close $p} err]} {
Index: b/git-gui/lib/merge.tcl
===================================================================
--- a/git-gui/lib/merge.tcl
+++ b/git-gui/lib/merge.tcl
@@ -93,7 +93,7 @@ method _start {} {
set spec [$w_rev get_tracking_branch]
set cmit [$w_rev get_commit]
- set fh [open [gitdir FETCH_HEAD] w]
+ set fh [safe_open_file [gitdir FETCH_HEAD] w]
fconfigure $fh -translation lf
if {$spec eq {}} {
set remote .
@@ -118,7 +118,7 @@ method _start {} {
set cmd [list git]
lappend cmd merge
lappend cmd --strategy=recursive
- lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]]
+ lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]]
lappend cmd HEAD
lappend cmd $name
}
@@ -239,7 +239,7 @@ Continue with resetting the current chan
}
if {[ask_popup $op_question] eq {yes}} {
- set fd [git_read --stderr read-tree --reset -u -v HEAD]
+ set fd [git_read [list read-tree --reset -u -v HEAD] [list 2>@1]]
fconfigure $fd -blocking 0 -translation binary
set status_bar_operation [$::main_status \
start \
Index: b/git-gui/lib/mergetool.tcl
===================================================================
--- a/git-gui/lib/mergetool.tcl
+++ b/git-gui/lib/mergetool.tcl
@@ -88,7 +88,7 @@ proc merge_load_stages {path cont} {
set merge_stages(3) {}
set merge_stages_buf {}
- set merge_stages_fd [eval git_read ls-files -u -z -- {$path}]
+ set merge_stages_fd [git_read [list ls-files -u -z -- $path]]
fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
@@ -293,7 +293,7 @@ proc merge_tool_get_stages {target stage
foreach fname $stages {
if {$merge_stages($i) eq {}} {
file delete $fname
- catch { close [open $fname w] }
+ catch { close [safe_open_file $fname w] }
} else {
# A hack to support autocrlf properly
git checkout-index -f --stage=$i -- $target
@@ -343,9 +343,9 @@ proc merge_tool_start {cmdline target ba
# Force redirection to avoid interpreting output on stderr
# as an error, and launch the tool
- lappend cmdline {2>@1}
+ set redir [list {2>@1}]
- if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} {
+ if {[catch { set mtool_fd [safe_open_command $cmdline $redir] } err]} {
delete_temp_files $mtool_tmpfiles
error_popup [mc "Could not start the merge tool:\n\n%s" $err]
return
Index: b/git-gui/lib/remote.tcl
===================================================================
--- a/git-gui/lib/remote.tcl
+++ b/git-gui/lib/remote.tcl
@@ -32,7 +32,7 @@ proc all_tracking_branches {} {
}
if {$pat ne {}} {
- set fd [eval git_read for-each-ref --format=%(refname) $cmd]
+ set fd [git_read [concat for-each-ref --format=%(refname) $cmd]]
while {[gets $fd n] > 0} {
foreach spec $pat {
set dst [string range [lindex $spec 0] 0 end-2]
@@ -75,7 +75,7 @@ proc load_all_remotes {} {
foreach name $all_remotes {
catch {
- set fd [open [file join $rm_dir $name] r]
+ set fd [safe_open_file [file join $rm_dir $name] r]
while {[gets $fd line] >= 0} {
if {[regexp {^URL:[ ]*(.+)$} $line line url]} {
set remote_url($name) $url
@@ -145,7 +145,7 @@ proc add_fetch_entry {r} {
}
} else {
catch {
- set fd [open [gitdir remotes $r] r]
+ set fd [safe_open_file [gitdir remotes $r] r]
while {[gets $fd n] >= 0} {
if {[regexp {^Pull:[ \t]*([^:]+):} $n]} {
set enable 1
@@ -182,7 +182,7 @@ proc add_push_entry {r} {
}
} else {
catch {
- set fd [open [gitdir remotes $r] r]
+ set fd [safe_open_file [gitdir remotes $r] r]
while {[gets $fd n] >= 0} {
if {[regexp {^Push:[ \t]*([^:]+):} $n]} {
set enable 1
Index: b/git-gui/lib/shortcut.tcl
===================================================================
--- a/git-gui/lib/shortcut.tcl
+++ b/git-gui/lib/shortcut.tcl
@@ -30,11 +30,11 @@ proc do_cygwin_shortcut {} {
global argv0 _gitworktree
if {[catch {
- set desktop [exec cygpath \
+ set desktop [safe_exec [list cygpath \
--windows \
--absolute \
--long-name \
- --desktop]
+ --desktop]]
}]} {
set desktop .
}
@@ -48,14 +48,14 @@ proc do_cygwin_shortcut {} {
set fn ${fn}.lnk
}
if {[catch {
- set sh [exec cygpath \
+ set sh [safe_exec [list cygpath \
--windows \
--absolute \
- /bin/sh.exe]
- set me [exec cygpath \
+ /bin/sh.exe]]
+ set me [safe_exec [list cygpath \
--unix \
--absolute \
- $argv0]
+ $argv0]]
win32_create_lnk $fn [list \
$sh -c \
"CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \
@@ -86,7 +86,7 @@ proc do_macosx_app {} {
file mkdir $MacOS
- set fd [open [file join $Contents Info.plist] w]
+ set fd [safe_open_file [file join $Contents Info.plist] w]
puts $fd {<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
@@ -111,7 +111,7 @@ proc do_macosx_app {} {
</plist>}
close $fd
- set fd [open $exe w]
+ set fd [safe_open_file $exe w]
puts $fd "#!/bin/sh"
foreach name [lsort [array names env]] {
set value $env($name)
Index: b/git-gui/lib/sshkey.tcl
===================================================================
--- a/git-gui/lib/sshkey.tcl
+++ b/git-gui/lib/sshkey.tcl
@@ -7,7 +7,7 @@ proc find_ssh_key {} {
~/.ssh/id_rsa.pub ~/.ssh/identity.pub
} {
if {[file exists $name]} {
- set fh [open $name r]
+ set fh [safe_open_file $name r]
set cont [read $fh]
close $fh
return [list $name $cont]
@@ -85,7 +85,7 @@ proc make_ssh_key {w} {
set cmdline [list sh -c {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}]
- if {[catch { set sshkey_fd [_open_stdout_stderr $cmdline] } err]} {
+ if {[catch { set sshkey_fd [safe_open_command $cmdline] } err]} {
error_popup [mc "Could not start ssh-keygen:\n\n%s" $err]
return
}
Index: b/git-gui/lib/win32.tcl
===================================================================
--- a/git-gui/lib/win32.tcl
+++ b/git-gui/lib/win32.tcl
@@ -2,11 +2,11 @@
# Copyright (C) 2007 Shawn Pearce
proc win32_read_lnk {lnk_path} {
- return [exec cscript.exe \
+ return [safe_exec [list cscript.exe \
/E:jscript \
/nologo \
[file join $::oguilib win32_shortcut.js] \
- $lnk_path]
+ $lnk_path]]
}
proc win32_create_lnk {lnk_path lnk_exec lnk_dir} {
@@ -15,12 +15,13 @@ proc win32_create_lnk {lnk_path lnk_exec
set lnk_args [lrange $lnk_exec 1 end]
set lnk_exec [lindex $lnk_exec 0]
- eval [list exec wscript.exe \
+ set cmd [list wscript.exe \
/E:jscript \
/nologo \
[file nativename [file join $oguilib win32_shortcut.js]] \
$lnk_path \
[file nativename [file join $oguilib git-gui.ico]] \
$lnk_dir \
- $lnk_exec] $lnk_args
+ $lnk_exec]
+ safe_exec [concat $cmd $lnk_args]
}
Index: b/git-gui/lib/console.tcl
===================================================================
--- a/git-gui/lib/console.tcl
+++ b/git-gui/lib/console.tcl
@@ -92,10 +92,9 @@ method _init {} {
method exec {cmd {after {}}} {
if {[lindex $cmd 0] eq {git}} {
- set fd_f [eval git_read --stderr [lrange $cmd 1 end]]
+ set fd_f [git_read [lrange $cmd 1 end] [list 2>@1]]
} else {
- lappend cmd 2>@1
- set fd_f [_open_stdout_stderr $cmd]
+ set fd_f [safe_open_command $cmd [list 2>@1]]
}
fconfigure $fd_f -blocking 0 -translation binary
fileevent $fd_f readable [cb _read $fd_f $after]
Index: b/git-gui/lib/branch.tcl
===================================================================
--- a/git-gui/lib/branch.tcl
+++ b/git-gui/lib/branch.tcl
@@ -7,7 +7,7 @@ proc load_all_heads {} {
set rh refs/heads
set rh_len [expr {[string length $rh] + 1}]
set all_heads [list]
- set fd [git_read for-each-ref --format=%(refname) $rh]
+ set fd [git_read [list for-each-ref --format=%(refname) $rh]]
fconfigure $fd -translation binary -encoding utf-8
while {[gets $fd line] > 0} {
if {!$some_heads_tracking || ![is_tracking_branch $line]} {
@@ -21,10 +21,10 @@ proc load_all_heads {} {
proc load_all_tags {} {
set all_tags [list]
- set fd [git_read for-each-ref \
+ set fd [git_read [list for-each-ref \
--sort=-taggerdate \
--format=%(refname) \
- refs/tags]
+ refs/tags]]
fconfigure $fd -translation binary -encoding utf-8
while {[gets $fd line] > 0} {
if {![regsub ^refs/tags/ $line {} name]} continue
Index: b/git-gui/lib/browser.tcl
===================================================================
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -196,7 +196,7 @@ method _ls {tree_id {name {}}} {
lappend browser_stack [list $tree_id $name]
$w conf -state disabled
- set fd [git_read ls-tree -z $tree_id]
+ set fd [git_read [list ls-tree -z $tree_id]]
fconfigure $fd -blocking 0 -translation binary -encoding utf-8
fileevent $fd readable [cb _read $fd]
}
Index: b/git-gui/lib/database.tcl
===================================================================
--- a/git-gui/lib/database.tcl
+++ b/git-gui/lib/database.tcl
@@ -3,7 +3,7 @@
proc do_stats {} {
global use_ttk NS
- set fd [git_read count-objects -v]
+ set fd [git_read [list count-objects -v]]
while {[gets $fd line] > 0} {
if {[regexp {^([^:]+): (\d+)$} $line _ name value]} {
set stats($name) $value
Index: b/git-gui/lib/index.tcl
===================================================================
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -75,7 +75,7 @@ proc update_indexinfo {msg path_list aft
if {$batch > 25} {set batch 25}
set status_bar_operation [$::main_status start $msg [mc "files"]]
- set fd [git_write update-index -z --index-info]
+ set fd [git_write [list update-index -z --index-info]]
fconfigure $fd \
-blocking 0 \
-buffering full \
@@ -144,7 +144,7 @@ proc update_index {msg path_list after}
if {$batch > 25} {set batch 25}
set status_bar_operation [$::main_status start $msg [mc "files"]]
- set fd [git_write update-index --add --remove -z --stdin]
+ set fd [git_write [list update-index --add --remove -z --stdin]]
fconfigure $fd \
-blocking 0 \
-buffering full \
@@ -218,13 +218,13 @@ proc checkout_index {msg path_list after
if {$batch > 25} {set batch 25}
set status_bar_operation [$::main_status start $msg [mc "files"]]
- set fd [git_write checkout-index \
+ set fd [git_write [list checkout-index \
--index \
--quiet \
--force \
-z \
--stdin \
- ]
+ ]]
fconfigure $fd \
-blocking 0 \
-buffering full \
Index: b/git-gui/lib/remote_branch_delete.tcl
===================================================================
--- a/git-gui/lib/remote_branch_delete.tcl
+++ b/git-gui/lib/remote_branch_delete.tcl
@@ -308,7 +308,7 @@ method _load {cache uri} {
set full_list [list]
set head_cache($cache) [list]
set full_cache($cache) [list]
- set active_ls [git_read ls-remote $uri]
+ set active_ls [git_read [list ls-remote $uri]]
fconfigure $active_ls \
-blocking 0 \
-translation lf \
Index: b/git-gui/lib/tools.tcl
===================================================================
--- a/git-gui/lib/tools.tcl
+++ b/git-gui/lib/tools.tcl
@@ -130,8 +130,7 @@ proc tools_exec {fullname} {
}
proc tools_run_silent {cmd after} {
- lappend cmd 2>@1
- set fd [_open_stdout_stderr $cmd]
+ set fd [safe_open_command $cmd [list 2>@1]]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [list tools_consume_input $fd $after]