Skip to content

Commit 7c9fa4d

Browse files
committed
cmd/go: check if build output should overwrite files with renames
CopyFile has a check to ensure that only object files are overwritten. Extend this to moveOrCopyFile, so the check also happens when the source and destination file are on the same filesystem (when renames are a valid way of moving files). Fixes #75970 Change-Id: Ie667301f1c9c00b114cfd91cdf8053ac20fd817b Reviewed-on: https://go-review.googlesource.com/c/go/+/712960 Reviewed-by: Laurent Demailly <ldemailly@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Matloob <matloob@google.com> Reviewed-by: Ian Alexander <jitsu@google.com> Reviewed-by: Michael Matloob <matloob@golang.org>
1 parent 557b4d6 commit 7c9fa4d

File tree

2 files changed

+43
-10
lines changed

2 files changed

+43
-10
lines changed

src/cmd/go/internal/work/shell.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ func (sh *Shell) moveOrCopyFile(dst, src string, perm fs.FileMode, force bool) e
123123
return nil
124124
}
125125

126+
err := checkDstOverwrite(dst, force)
127+
if err != nil {
128+
return err
129+
}
130+
126131
// If we can update the mode and rename to the dst, do it.
127132
// Otherwise fall back to standard copy.
128133

@@ -193,16 +198,9 @@ func (sh *Shell) CopyFile(dst, src string, perm fs.FileMode, force bool) error {
193198
}
194199
defer sf.Close()
195200

196-
// Be careful about removing/overwriting dst.
197-
// Do not remove/overwrite if dst exists and is a directory
198-
// or a non-empty non-object file.
199-
if fi, err := os.Stat(dst); err == nil {
200-
if fi.IsDir() {
201-
return fmt.Errorf("build output %q already exists and is a directory", dst)
202-
}
203-
if !force && fi.Mode().IsRegular() && fi.Size() != 0 && !isObject(dst) {
204-
return fmt.Errorf("build output %q already exists and is not an object file", dst)
205-
}
201+
err = checkDstOverwrite(dst, force)
202+
if err != nil {
203+
return err
206204
}
207205

208206
// On Windows, remove lingering ~ file from last attempt.
@@ -247,6 +245,21 @@ func mayberemovefile(s string) {
247245
os.Remove(s)
248246
}
249247

248+
// Be careful about removing/overwriting dst.
249+
// Do not remove/overwrite if dst exists and is a directory
250+
// or a non-empty non-object file.
251+
func checkDstOverwrite(dst string, force bool) error {
252+
if fi, err := os.Stat(dst); err == nil {
253+
if fi.IsDir() {
254+
return fmt.Errorf("build output %q already exists and is a directory", dst)
255+
}
256+
if !force && fi.Mode().IsRegular() && fi.Size() != 0 && !isObject(dst) {
257+
return fmt.Errorf("build output %q already exists and is not an object file", dst)
258+
}
259+
}
260+
return nil
261+
}
262+
250263
// writeFile writes the text to file.
251264
func (sh *Shell) writeFile(file string, text []byte) error {
252265
if cfg.BuildN || cfg.BuildX {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# windows executables have the .exe extension and won't overwrite source files
2+
[GOOS:windows] skip
3+
4+
mkdir out
5+
env GOTMPDIR=$PWD/out
6+
7+
grep 'this should still exist' foo.go
8+
9+
! go build
10+
stderr 'already exists and is not an object file'
11+
12+
grep 'this should still exist' foo.go
13+
14+
-- go.mod --
15+
module foo.go
16+
17+
-- foo.go --
18+
package main // this should still exist
19+
20+
func main() {}

0 commit comments

Comments
 (0)