mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-31 12:11:58 +00:00
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
This commit is contained in:
40
common/os.go
40
common/os.go
@@ -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)
|
||||
}
|
||||
}
|
||||
// Write newBytes to filePath.new
|
||||
err := ioutil.WriteFile(filePath+".new", newBytes, mode)
|
||||
f, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not write file %v. %v", filePath+".new", err)
|
||||
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)
|
||||
}
|
||||
// any err should result in full cleanup
|
||||
if err != nil {
|
||||
os.Remove(f.Name())
|
||||
}
|
||||
// Move filePath.new to filePath
|
||||
err = os.Rename(filePath+".new", filePath)
|
||||
return err
|
||||
}
|
||||
|
||||
|
29
common/os_test.go
Normal file
29
common/os_test.go
Normal 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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user