]> ruderich.org/simon Gitweb - nsscash/nsscash.git/commitdiff
Guarantee durability after renaming temporary files
authorSimon Ruderich <simon@ruderich.org>
Sat, 16 Jan 2021 10:34:59 +0000 (11:34 +0100)
committerSimon Ruderich <simon@ruderich.org>
Sat, 16 Jan 2021 10:34:59 +0000 (11:34 +0100)
file.go
main.go
misc.go
state.go

diff --git a/file.go b/file.go
index 1d102a4e09d0152547485da18c051d727d9510b2..3884bba8b6ae3c4f0e6d86f26d796fd5fcac0952 100644 (file)
--- a/file.go
+++ b/file.go
@@ -198,5 +198,9 @@ func deployFile(file *File) error {
        if err != nil {
                return err
        }
-       return f.CloseAtomicallyReplace()
+       err = f.CloseAtomicallyReplace()
+       if err != nil {
+               return err
+       }
+       return syncPath(filepath.Dir(file.Path))
 }
diff --git a/main.go b/main.go
index 9b127529178a9be4eb76d29e9f9ce6d0e2abc6d3..7a7d8b0da8e6855b8545c609f6169184819db7ae 100644 (file)
--- a/main.go
+++ b/main.go
@@ -151,5 +151,9 @@ func mainConvert(typ, srcPath, dstPath string) error {
                return err
        }
 
-       return f.CloseAtomicallyReplace()
+       err = f.CloseAtomicallyReplace()
+       if err != nil {
+               return err
+       }
+       return syncPath(filepath.Dir(dstPath))
 }
diff --git a/misc.go b/misc.go
index 897a764d6fcbb4ef5d009d388977342db772d3ff..3cbe90f277387eee2e04910852003138c981df84 100644 (file)
--- a/misc.go
+++ b/misc.go
@@ -20,6 +20,7 @@ package main
 import (
        "bytes"
        "fmt"
+       "os"
 )
 
 func alignBufferTo(b *bytes.Buffer, align int) {
@@ -35,3 +36,24 @@ func alignBufferTo(b *bytes.Buffer, align int) {
                b.WriteByte(0)
        }
 }
+
+// syncPath syncs path, which should be a directory. To guarantee durability
+// it must be called on a parent directory after adding, renaming or removing
+// files therein.
+//
+// Calling sync on the files itself is not enough according to POSIX; man 2
+// fsync: "Calling fsync() does not necessarily ensure that the entry in the
+// directory containing the file has also reached disk. For that an explicit
+// fsync() on a file descriptor for the directory is also needed."
+func syncPath(path string) error {
+       x, err := os.Open(path)
+       if err != nil {
+               return err
+       }
+       err = x.Sync()
+       closeErr := x.Close()
+       if err != nil {
+               return err
+       }
+       return closeErr
+}
index be08e7279ab0641f9fe43c940ee498003107014a..59c885ae9cf17c9a15a2e980702926a24cf26339 100644 (file)
--- a/state.go
+++ b/state.go
@@ -80,5 +80,9 @@ func WriteState(path string, state *State) error {
        if err != nil {
                return err
        }
-       return f.CloseAtomicallyReplace()
+       err = f.CloseAtomicallyReplace()
+       if err != nil {
+               return err
+       }
+       return syncPath(filepath.Dir(path))
 }