From: Simon Ruderich Date: Sat, 16 Jan 2021 10:34:59 +0000 (+0100) Subject: Guarantee durability after renaming temporary files X-Git-Tag: 0.2~2 X-Git-Url: https://ruderich.org/simon/gitweb/?p=nsscash%2Fnsscash.git;a=commitdiff_plain;h=f00fb4706c4c2459d528fb5f8ad0fa112b00bdd0 Guarantee durability after renaming temporary files --- diff --git a/file.go b/file.go index 1d102a4..3884bba 100644 --- 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 9b12752..7a7d8b0 100644 --- 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 897a764..3cbe90f 100644 --- 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 +} diff --git a/state.go b/state.go index be08e72..59c885a 100644 --- 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)) }