From: Simon Ruderich Date: Fri, 14 Jun 2019 18:28:29 +0000 (+0200) Subject: nsscash: convert: create file atomically X-Git-Tag: 0.1~47 X-Git-Url: https://ruderich.org/simon/gitweb/?p=nsscash%2Fnsscash.git;a=commitdiff_plain;h=73d81832a59ada7f3713bd8ab5ea6c3bca54f01b nsscash: convert: create file atomically Previously the file was first truncated or created and then written to. Although "convert" is not designed to be used for deployment, it is a unexpected behavior. --- diff --git a/main.go b/main.go index a563b51..5455dfe 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ import ( "io/ioutil" "log" "os" + "path/filepath" ) func main() { @@ -129,21 +130,29 @@ func mainConvert(typ, srcPath, dstPath string) error { return fmt.Errorf("unsupported file type %v", t) } - // We must create the file first or deployFile() will abort - f, err := os.Create(dstPath) + dstDir := filepath.Dir(dstPath) + dstName := filepath.Base(dstPath) + + // We must create the file first or deployFile() will abort; this is + // ugly because deployFile() already performs an atomic replacement + // but the simplest solution with the least duplicate code + f, err := ioutil.TempFile(dstDir, "tmp-"+dstName+"-") if err != nil { return err } + tmpPath := f.Name() + defer os.Remove(tmpPath) f.Close() err = deployFile(&File{ Type: t, Url: srcPath, - Path: dstPath, + Path: tmpPath, body: x.Bytes(), }) if err != nil { return err } - return nil + + return os.Rename(tmpPath, dstPath) }