if fi.IsDir() {
return fmt.Errorf("build output %q already exists and is a directory", dst)
}
- if !force && !isObject(dst) {
+ if !force && fi.Mode().IsRegular() && !isObject(dst) {
return fmt.Errorf("build output %q already exists and is not an object file", dst)
}
}
}
}
- os.Remove(dst)
+ mayberemovefile(dst)
df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil && toolIsWindows {
// Windows does not allow deletion of a binary file
_, err = io.Copy(df, sf)
df.Close()
if err != nil {
- os.Remove(dst)
+ mayberemovefile(dst)
return fmt.Errorf("copying %s to %s: %v", src, dst, err)
}
return nil
return false
}
+// mayberemovefile removes a file only if it is a regular file
+// When running as a user with sufficient privileges, we may delete
+// even device files, for example, which is not intended.
+func mayberemovefile(s string) {
+ if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
+ return
+ }
+ os.Remove(s)
+}
+
// fmtcmd formats a command in the manner of fmt.Sprintf but also:
//
// If dir is non-empty and the script is not in dir right now,
tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
}
+// Issue 12407
+func TestBuildOutputToDevNull(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("build", "-o", os.DevNull, "go-cmd-test")
+}
+
func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()