aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2016-11-09 15:29:41 -0800
committerRobert Griesemer <gri@golang.org>2016-11-10 00:30:18 +0000
commitb188b4cc110261a004674df5a4e209cc4894d314 (patch)
tree16bd2be699531114409a1fb7199f2bf709671b27
parentadd8028eb9925db0ec9d3d0f95dec65c8cab1d96 (diff)
downloadgo-b188b4cc110261a004674df5a4e209cc4894d314.tar.gz
go-b188b4cc110261a004674df5a4e209cc4894d314.zip
cmd/gofmt: don't eat source if -w fails
Write output to a temp file first and only upon success rename that file to source file name. Fixes #8984. Change-Id: Ie40e49d2a4eb3c9462fe769ccbf055b4366eceb0 Reviewed-on: https://go-review.googlesource.com/33018 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
-rw-r--r--src/cmd/gofmt/gofmt.go34
1 files changed, 33 insertions, 1 deletions
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index f29b6cb83d..4cf91336a3 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -116,7 +116,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
- err = ioutil.WriteFile(filename, res, 0644)
+ err = writeFile(filename, res, 0644)
if err != nil {
return err
}
@@ -235,3 +235,35 @@ func diff(b1, b2 []byte) (data []byte, err error) {
return
}
+
+// writeFile is a drop-in replacement for ioutil.WriteFile;
+// but writeFile writes data to a temporary file first and
+// only upon success renames that file to filename.
+// TODO(gri) This can be removed if #17869 is accepted and
+// implemented.
+func writeFile(filename string, data []byte, perm os.FileMode) error {
+ // open temp file
+ f, err := ioutil.TempFile(filepath.Dir(filename), "tmp")
+ if err != nil {
+ return err
+ }
+ err = f.Chmod(perm)
+ if err != nil {
+ return err
+ }
+ tmpname := f.Name()
+
+ // write data to temp file
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+ if err != nil {
+ return err
+ }
+
+ return os.Rename(tmpname, filename)
+}