Browse Source

Merge pull request #32 from tendermint/bugfix/write-file-atomic

Fix rename /root/.tendermint_test/consensus_replay_test/priv_validator.json.new /root/.tendermint_test/consensus_replay_test/priv_validator.json: no such file or directory
pull/1842/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
271145ee72
2 changed files with 49 additions and 18 deletions
  1. +20
    -18
      common/os.go
  2. +29
    -0
      common/os_test.go

+ 20
- 18
common/os.go View File

@ -93,28 +93,30 @@ func MustWriteFile(filePath string, contents []byte, mode os.FileMode) {
}
}
// Writes to newBytes to filePath.
// Guaranteed not to lose *both* oldBytes and newBytes,
// (assuming that the OS is perfect)
// WriteFileAtomic writes newBytes to temp and atomically moves to filePath
// when everything else succeeds.
func WriteFileAtomic(filePath string, newBytes []byte, mode os.FileMode) error {
// If a file already exists there, copy to filePath+".bak" (overwrite anything)
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("Could not read file %v. %v", filePath, err)
}
err = ioutil.WriteFile(filePath+".bak", fileBytes, mode)
if err != nil {
return fmt.Errorf("Could not write file %v. %v", filePath+".bak", err)
}
f, err := ioutil.TempFile("", "")
if err != nil {
return err
}
_, err = f.Write(newBytes)
if err == nil {
err = f.Sync()
}
if closeErr := f.Close(); err == nil {
err = closeErr
}
if permErr := os.Chmod(f.Name(), mode); err == nil {
err = permErr
}
if err == nil {
err = os.Rename(f.Name(), filePath)
}
// Write newBytes to filePath.new
err := ioutil.WriteFile(filePath+".new", newBytes, mode)
// any err should result in full cleanup
if err != nil {
return fmt.Errorf("Could not write file %v. %v", filePath+".new", err)
os.Remove(f.Name())
}
// Move filePath.new to filePath
err = os.Rename(filePath+".new", filePath)
return err
}


+ 29
- 0
common/os_test.go View File

@ -0,0 +1,29 @@
package common
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
)
func TestWriteFileAtomic(t *testing.T) {
data := []byte("Becatron")
fname := fmt.Sprintf("/tmp/write-file-atomic-test-%v.txt", time.Now().UnixNano())
err := WriteFileAtomic(fname, data, 0664)
if err != nil {
t.Fatal(err)
}
rData, err := ioutil.ReadFile(fname)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(data, rData) {
t.Fatalf("data mismatch: %v != %v", data, rData)
}
if err := os.Remove(fname); err != nil {
t.Fatal(err)
}
}

Loading…
Cancel
Save