@cryptotaxi247 / kubo / commits / 9700d2f94

use atomicfile for safer writes

for now, allow daemon and client to both hit config

Brian Tiger Chow committed Jan 13, 2015 at 06:27 UTC 9700d2f94bf3f2ae6e0e031d282fc7ad6068a367
8 files changed +227 -1
Godeps/Godeps.json
+4
@@ -68,6 +68,10 @@
68 "ImportPath": "github.com/dustin/go-humanize",
69 "Rev": "b198514c204f20799b91c93b6ffd8b26be04c2c9"
70 },
71 + {
72 + "ImportPath": "github.com/facebookgo/atomicfile",
73 + "Rev": "6f117f2e7f224fb03eb5e5fba370eade6e2b90c8"
74 + },
75 {
76 "ImportPath": "github.com/facebookgo/stack",
77 "Rev": "4da6d991fc3c389efa512151354d643eb5fae4e2"
Godeps/_workspace/src/github.com/facebookgo/atomicfile/.travis.yml new
+24
@@ -0,0 +1,24 @@
1 +language: go
2 +
3 +go:
4 + - 1.2
5 + - 1.3
6 +
7 +matrix:
8 + fast_finish: true
9 +
10 +before_install:
11 + - go get -v code.google.com/p/go.tools/cmd/vet
12 + - go get -v github.com/golang/lint/golint
13 + - go get -v code.google.com/p/go.tools/cmd/cover
14 +
15 +install:
16 + - go install -race -v std
17 + - go get -race -t -v ./...
18 + - go install -race -v ./...
19 +
20 +script:
21 + - go vet ./...
22 + - $HOME/gopath/bin/golint .
23 + - go test -cpu=2 -race -v ./...
24 + - go test -cpu=2 -covermode=atomic ./...
Godeps/_workspace/src/github.com/facebookgo/atomicfile/atomicfile.go new
+54
@@ -0,0 +1,54 @@
1 +// Package atomicfile provides the ability to write a file with an eventual
2 +// rename on Close. This allows for a file to always be in a consistent state
3 +// and never represent an in-progress write.
4 +package atomicfile
5 +
6 +import (
7 + "io/ioutil"
8 + "os"
9 + "path/filepath"
10 +)
11 +
12 +// File behaves like os.File, but does an atomic rename operation at Close.
13 +type File struct {
14 + *os.File
15 + path string
16 +}
17 +
18 +// New creates a new temporary file that will replace the file at the given
19 +// path when Closed.
20 +func New(path string, mode os.FileMode) (*File, error) {
21 + f, err := ioutil.TempFile(filepath.Dir(path), filepath.Base(path))
22 + if err != nil {
23 + return nil, err
24 + }
25 + if err := os.Chmod(f.Name(), mode); err != nil {
26 + os.Remove(f.Name())
27 + return nil, err
28 + }
29 + return &File{File: f, path: path}, nil
30 +}
31 +
32 +// Close the file replacing the configured file.
33 +func (f *File) Close() error {
34 + if err := f.File.Close(); err != nil {
35 + return err
36 + }
37 + if err := os.Rename(f.Name(), f.path); err != nil {
38 + return err
39 + }
40 + return nil
41 +}
42 +
43 +// Abort closes the file and removes it instead of replacing the configured
44 +// file. This is useful if after starting to write to the file you decide you
45 +// don't want it anymore.
46 +func (f *File) Abort() error {
47 + if err := f.File.Close(); err != nil {
48 + return err
49 + }
50 + if err := os.Remove(f.Name()); err != nil {
51 + return err
52 + }
53 + return nil
54 +}
Godeps/_workspace/src/github.com/facebookgo/atomicfile/atomicfile_test.go new
+86
@@ -0,0 +1,86 @@
1 +package atomicfile_test
2 +
3 +import (
4 + "bytes"
5 + "io/ioutil"
6 + "os"
7 + "testing"
8 +
9 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/atomicfile"
10 +)
11 +
12 +func test(t *testing.T, dir, prefix string) {
13 + t.Parallel()
14 +
15 + tmpfile, err := ioutil.TempFile(dir, prefix)
16 + if err != nil {
17 + t.Fatal(err)
18 + }
19 + name := tmpfile.Name()
20 +
21 + if err := os.Remove(name); err != nil {
22 + t.Fatal(err)
23 + }
24 +
25 + defer os.Remove(name)
26 + f, err := atomicfile.New(name, os.FileMode(0666))
27 + if err != nil {
28 + t.Fatal(err)
29 + }
30 + f.Write([]byte("foo"))
31 + if _, err := os.Stat(name); !os.IsNotExist(err) {
32 + t.Fatal("did not expect file to exist")
33 + }
34 + if err := f.Close(); err != nil {
35 + t.Fatal(err)
36 + }
37 + if _, err := os.Stat(name); err != nil {
38 + t.Fatalf("expected file to exist: %s", err)
39 + }
40 +}
41 +
42 +func TestCurrentDir(t *testing.T) {
43 + cwd, _ := os.Getwd()
44 + test(t, cwd, "atomicfile-current-dir-")
45 +}
46 +
47 +func TestRootTmpDir(t *testing.T) {
48 + test(t, "/tmp", "atomicfile-root-tmp-dir-")
49 +}
50 +
51 +func TestDefaultTmpDir(t *testing.T) {
52 + test(t, "", "atomicfile-default-tmp-dir-")
53 +}
54 +
55 +func TestAbort(t *testing.T) {
56 + contents := []byte("the answer is 42")
57 + t.Parallel()
58 + tmpfile, err := ioutil.TempFile("", "atomicfile-abort-")
59 + if err != nil {
60 + t.Fatal(err)
61 + }
62 + name := tmpfile.Name()
63 + if _, err := tmpfile.Write(contents); err != nil {
64 + t.Fatal(err)
65 + }
66 + defer os.Remove(name)
67 +
68 + f, err := atomicfile.New(name, os.FileMode(0666))
69 + if err != nil {
70 + t.Fatal(err)
71 + }
72 + f.Write([]byte("foo"))
73 + if err := f.Abort(); err != nil {
74 + t.Fatal(err)
75 + }
76 + if _, err := os.Stat(name); err != nil {
77 + t.Fatalf("expected file to exist: %s", err)
78 + }
79 + actual, err := ioutil.ReadFile(name)
80 + if err != nil {
81 + t.Fatal(err)
82 + }
83 + if !bytes.Equal(contents, actual) {
84 + t.Fatalf(`did not find expected "%s" instead found "%s"`, contents, actual)
85 + }
86 +}
Godeps/_workspace/src/github.com/facebookgo/atomicfile/license new
+30
@@ -0,0 +1,30 @@
1 +BSD License
2 +
3 +For atomicfile software
4 +
5 +Copyright (c) 2014, Facebook, Inc. All rights reserved.
6 +
7 +Redistribution and use in source and binary forms, with or without modification,
8 +are permitted provided that the following conditions are met:
9 +
10 + * Redistributions of source code must retain the above copyright notice, this
11 + list of conditions and the following disclaimer.
12 +
13 + * Redistributions in binary form must reproduce the above copyright notice,
14 + this list of conditions and the following disclaimer in the documentation
15 + and/or other materials provided with the distribution.
16 +
17 + * Neither the name Facebook nor the names of its contributors may be used to
18 + endorse or promote products derived from this software without specific
19 + prior written permission.
20 +
21 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Godeps/_workspace/src/github.com/facebookgo/atomicfile/patents new
+23
@@ -0,0 +1,23 @@
1 +Additional Grant of Patent Rights
2 +
3 +"Software" means the atomicfile software distributed by Facebook, Inc.
4 +
5 +Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive,
6 +irrevocable (subject to the termination provision below) license under any
7 +rights in any patent claims owned by Facebook, to make, have made, use, sell,
8 +offer to sell, import, and otherwise transfer the Software. For avoidance of
9 +doubt, no license is granted under Facebook’s rights in any patent claims that
10 +are infringed by (i) modifications to the Software made by you or a third party,
11 +or (ii) the Software in combination with any software or other technology
12 +provided by you or a third party.
13 +
14 +The license granted hereunder will terminate, automatically and without notice,
15 +for anyone that makes any claim (including by filing any lawsuit, assertion or
16 +other action) alleging (a) direct, indirect, or contributory infringement or
17 +inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or
18 +affiliates, whether or not such claim is related to the Software, (ii) by any
19 +party if such claim arises in whole or in part from any software, product or
20 +service of Facebook or any of its subsidiaries or affiliates, whether or not
21 +such claim is related to the Software, or (iii) by any party relating to the
22 +Software; or (b) that any right in any patent claim of Facebook is invalid or
23 +unenforceable.
Godeps/_workspace/src/github.com/facebookgo/atomicfile/readme.md new
+4
@@ -0,0 +1,4 @@
1 +atomicfile [![Build Status](https://secure.travis-ci.org/facebookgo/atomicfile.png)](http://travis-ci.org/facebookgo/atomicfile)
2 +==========
3 +
4 +Documentation: http://godoc.org/github.com/facebookgo/atomicfile
repo/fsrepo/serialize.go
+2 -1
@@ -7,6 +7,7 @@ import (
7 "os"
8 "path/filepath"
9
10 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/atomicfile"
11 "github.com/jbenet/go-ipfs/repo/config"
12 "github.com/jbenet/go-ipfs/util"
13 "github.com/jbenet/go-ipfs/util/debugerror"
@@ -34,7 +35,7 @@ func writeConfigFile(filename string, cfg interface{}) error {
35 return err
36 }
37
37 - f, err := os.Create(filename)
38 + f, err := atomicfile.New(filename, 0775)
39 if err != nil {
40 return err
41 }