From ca9217f7fac4aa7cd47c1457221fb5a61760c7ae Mon Sep 17 00:00:00 2001 From: Simon Dassow Date: Thu, 24 Sep 2020 23:28:04 +0200 Subject: [PATCH 1/4] Implement support for optional file mode (fixes natefinch/atomic#7) --- atomic.go | 7 ++++++- atomic_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 atomic_test.go diff --git a/atomic.go b/atomic.go index 2335b77..94b334f 100644 --- a/atomic.go +++ b/atomic.go @@ -14,7 +14,7 @@ import ( // not written at all. WriteFile overwrites any file that exists at the // location (but only if the write fully succeeds, otherwise the existing file // is unmodified). -func WriteFile(filename string, r io.Reader) (err error) { +func WriteFile(filename string, r io.Reader, mode ...os.FileMode) (err error) { // write to a temp file first, then we'll atomically replace the target file // with the temp file. dir, file := filepath.Split(filename) @@ -39,6 +39,11 @@ func WriteFile(filename string, r io.Reader) (err error) { if _, err := io.Copy(f, r); err != nil { return fmt.Errorf("cannot write data to tempfile %q: %v", name, err) } + if len(mode) > 0 { + if err := f.Chmod(mode[0]); err != nil { + return fmt.Errorf("cannot change file mode %q: %v", name, err); + } + } if err := f.Close(); err != nil { return fmt.Errorf("can't close tempfile %q: %v", name, err) } diff --git a/atomic_test.go b/atomic_test.go new file mode 100644 index 0000000..05006ed --- /dev/null +++ b/atomic_test.go @@ -0,0 +1,39 @@ +package atomic + +import ( + "bytes" + "os" + "testing" +) + +func TestWriteFile(t *testing.T) { + file := "foo.txt" + content := bytes.NewBufferString("foo") + defer func() { _ = os.Remove(file) }() + if err := WriteFile(file, content); err != nil { + t.Errorf("Failed to write file: %q: %v", file, err) + } + fi, err := os.Stat(file) + if err != nil { + t.Errorf("Failed to stat file: %q: %v", file, err) + } + if fi.Mode() != 0600 { + t.Errorf("File mode not correct") + } +} + +func TestWriteFileMode(t *testing.T) { + file := "bar.txt" + content := bytes.NewBufferString("bar") + defer func() { _ = os.Remove(file) }() + if err := WriteFile(file, content, 0644); err != nil { + t.Errorf("Failed to write file: %q: %v", file, err) + } + fi, err := os.Stat(file) + if err != nil { + t.Errorf("Failed to stat file: %q: %v", file, err) + } + if fi.Mode() != 0644 { + t.Errorf("File mode not correct") + } +} From e7a73d980d835e1921d6a59857ffd584dd0bbe68 Mon Sep 17 00:00:00 2001 From: Simon Dassow <70379952+sdassow@users.noreply.github.com> Date: Sat, 3 Oct 2020 19:21:22 +0200 Subject: [PATCH 2/4] Comment on the file mode change --- atomic.go | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic.go b/atomic.go index 94b334f..ab96178 100644 --- a/atomic.go +++ b/atomic.go @@ -39,6 +39,7 @@ func WriteFile(filename string, r io.Reader, mode ...os.FileMode) (err error) { if _, err := io.Copy(f, r); err != nil { return fmt.Errorf("cannot write data to tempfile %q: %v", name, err) } + // when optional mode was given change default mode of temp file. if len(mode) > 0 { if err := f.Chmod(mode[0]); err != nil { return fmt.Errorf("cannot change file mode %q: %v", name, err); From b2b81f7426334c64dcadf806822843b5cface1f9 Mon Sep 17 00:00:00 2001 From: Simon Dassow <70379952+sdassow@users.noreply.github.com> Date: Sat, 3 Oct 2020 19:27:25 +0200 Subject: [PATCH 3/4] Add mode to WriteFile() documentation --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 37cd673..b05d75c 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,13 @@ change either file. ## func WriteFile ``` go -func WriteFile(filename string, r io.Reader) (err error) +func WriteFile(filename string, r io.Reader, mode ...os.FileMode) (err error) ``` WriteFile atomically writes the contents of r to the specified filepath. If an error occurs, the target file is guaranteed to be either fully written, or not written at all. WriteFile overwrites any file that exists at the location (but only if the write fully succeeds, otherwise the existing file -is unmodified). +is unmodified). Permissions are copied from an existing file or the optional +default file mode that can be given to be used instead of the default `0600` +from ioutil.TempFile(). From 352374068ed453d1eafa8688bc030ccd3c44ae8c Mon Sep 17 00:00:00 2001 From: Simon Dassow <70379952+sdassow@users.noreply.github.com> Date: Sat, 3 Oct 2020 19:29:52 +0200 Subject: [PATCH 4/4] Reflect documentation update --- atomic.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/atomic.go b/atomic.go index ab96178..28cbf38 100644 --- a/atomic.go +++ b/atomic.go @@ -13,7 +13,9 @@ import ( // an error occurs, the target file is guaranteed to be either fully written, or // not written at all. WriteFile overwrites any file that exists at the // location (but only if the write fully succeeds, otherwise the existing file -// is unmodified). +// is unmodified). Permissions are copied from an existing file or the optional +// default file mode that can be given to be used instead of the default `0600` +// from ioutil.TempFile(). func WriteFile(filename string, r io.Reader, mode ...os.FileMode) (err error) { // write to a temp file first, then we'll atomically replace the target file // with the temp file.