diff options
-rw-r--r-- | skate/atomic/file.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/skate/atomic/file.go b/skate/atomic/file.go new file mode 100644 index 0000000..1b9bf25 --- /dev/null +++ b/skate/atomic/file.go @@ -0,0 +1,63 @@ +package atomic + +import ( + "io" + "io/ioutil" + "os" + "path" +) + +// WriteFileReader writes data from a reader atomically into filename. +func WriteFileReader(filename string, r io.Reader, perm os.FileMode) error { + dir, name := path.Split(filename) + f, err := ioutil.TempFile(dir, name) + if err != nil { + return err + } + _, err = io.Copy(f, r) + if err == nil { + err = f.Sync() + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + if permErr := os.Chmod(f.Name(), perm); err == nil { + err = permErr + } + if err == nil { + err = os.Rename(f.Name(), filename) + } + // Any err should result in full cleanup. + if err != nil { + os.Remove(f.Name()) + } + return err +} + +// WriteFileAtomic writes the data to a temp file and atomically move if +// everything else succeeds. +func WriteFile(filename string, data []byte, perm os.FileMode) error { + dir, name := path.Split(filename) + f, err := ioutil.TempFile(dir, name) + if err != nil { + return err + } + _, err = f.Write(data) + if err == nil { + err = f.Sync() + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + if permErr := os.Chmod(f.Name(), perm); err == nil { + err = permErr + } + if err == nil { + err = os.Rename(f.Name(), filename) + } + // Any err should result in full cleanup. + if err != nil { + os.Remove(f.Name()) + } + return err +} |