aboutsummaryrefslogtreecommitdiffstats
path: root/skate/atomic
diff options
context:
space:
mode:
authorMartin Czygan <martin.czygan@gmail.com>2021-05-20 11:38:47 +0200
committerMartin Czygan <martin.czygan@gmail.com>2021-05-20 11:38:47 +0200
commit8d4347ce602d51e17c3113edf940ee4d0d78a938 (patch)
treee9000da17776ab1e7ee44416d1542db542373738 /skate/atomic
parentc0157eb8e09a0d078038df21be2650f0a915250b (diff)
downloadrefcat-8d4347ce602d51e17c3113edf940ee4d0d78a938.tar.gz
refcat-8d4347ce602d51e17c3113edf940ee4d0d78a938.zip
add atomic file ops
Diffstat (limited to 'skate/atomic')
-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
+}