aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--skate/atomic/file.go63
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
+}