diff --git a/cmd/format-fs.go b/cmd/format-fs.go index 78f0873d7..ad20701c8 100644 --- a/cmd/format-fs.go +++ b/cmd/format-fs.go @@ -17,7 +17,6 @@ package cmd import ( - "encoding/json" "fmt" "io" "os" @@ -74,30 +73,11 @@ func newFormatFSV2() (format *formatFSV2) { return f } -// Save to fs format.json -func formatFSSave(f *os.File, data interface{}) error { - b, err := json.Marshal(data) - if err != nil { - return errors2.Trace(err) - } - if err = f.Truncate(0); err != nil { - return errors2.Trace(err) - } - if _, err = f.Seek(0, io.SeekStart); err != nil { - return err - } - _, err = f.Write(b) - if err != nil { - return errors2.Trace(err) - } - return nil -} - // Returns the field formatMetaV1.Format i.e the string "fs" which is never likely to change. // We do not use this function in XL to get the format as the file is not fcntl-locked on XL. func formatMetaGetFormatBackendFS(r io.ReadSeeker) (string, error) { format := &formatMetaV1{} - if err := jsonLoadFromSeeker(r, format); err != nil { + if err := jsonLoad(r, format); err != nil { return "", err } if format.Version == formatMetaVersionV1 { @@ -109,7 +89,7 @@ func formatMetaGetFormatBackendFS(r io.ReadSeeker) (string, error) { // Returns formatFS.FS.Version func formatFSGetVersion(r io.ReadSeeker) (string, error) { format := &formatFSVersionDetect{} - if err := jsonLoadFromSeeker(r, format); err != nil { + if err := jsonLoad(r, format); err != nil { return "", err } return format.FS.Version, nil @@ -135,7 +115,7 @@ func formatFSMigrateV1ToV2(wlk *lock.LockedFile, fsPath string) error { return err } - return formatFSSave(wlk.File, newFormatFSV2()) + return jsonSave(wlk.File, newFormatFSV2()) } // Migrate the "fs" backend. @@ -190,7 +170,7 @@ func createFormatFS(fsFormatPath string) error { return nil } - return formatFSSave(lk.File, newFormatFSV1()) + return jsonSave(lk.File, newFormatFSV1()) } // This function returns a read-locked format.json reference to the caller. diff --git a/cmd/fs-v1-metadata.go b/cmd/fs-v1-metadata.go index 9a7390eb4..55eb515f4 100644 --- a/cmd/fs-v1-metadata.go +++ b/cmd/fs-v1-metadata.go @@ -17,7 +17,6 @@ package cmd import ( - "encoding/json" "io" "io/ioutil" "os" @@ -127,22 +126,14 @@ func (m fsMetaV1) ToObjectInfo(bucket, object string, fi os.FileInfo) ObjectInfo } func (m *fsMetaV1) WriteTo(lk *lock.LockedFile) (n int64, err error) { - var metadataBytes []byte - metadataBytes, err = json.Marshal(m) + if err = jsonSave(lk, m); err != nil { + return 0, err + } + fi, err := lk.Stat() if err != nil { - return 0, errors.Trace(err) + return 0, err } - - if err = lk.Truncate(0); err != nil { - return 0, errors.Trace(err) - } - - if _, err = lk.Write(metadataBytes); err != nil { - return 0, errors.Trace(err) - } - - // Success. - return int64(len(metadataBytes)), nil + return fi.Size(), nil } func parseFSVersion(fsMetaBuf []byte) string { diff --git a/cmd/object-api-multipart-common.go b/cmd/object-api-multipart-common.go index 4b706fda3..fe6768200 100644 --- a/cmd/object-api-multipart-common.go +++ b/cmd/object-api-multipart-common.go @@ -84,20 +84,14 @@ func (u *uploadsV1) IsEmpty() bool { } func (u *uploadsV1) WriteTo(lk *lock.LockedFile) (n int64, err error) { - // Serialize to prepare to write to disk. - var uplBytes []byte - uplBytes, err = json.Marshal(u) + if err = jsonSave(lk, u); err != nil { + return 0, err + } + fi, err := lk.Stat() if err != nil { - return 0, errors.Trace(err) + return 0, err } - if err = lk.Truncate(0); err != nil { - return 0, errors.Trace(err) - } - _, err = lk.Write(uplBytes) - if err != nil { - return 0, errors.Trace(err) - } - return int64(len(uplBytes)), nil + return fi.Size(), nil } func (u *uploadsV1) ReadFrom(lk *lock.LockedFile) (n int64, err error) { diff --git a/cmd/utils.go b/cmd/utils.go index ca5ef5436..410fa23ac 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -265,9 +265,31 @@ func NewCustomHTTPTransport() http.RoundTripper { } // Load the json (typically from disk file). -func jsonLoadFromSeeker(r io.ReadSeeker, data interface{}) error { +func jsonLoad(r io.ReadSeeker, data interface{}) error { if _, err := r.Seek(0, io.SeekStart); err != nil { return err } return json.NewDecoder(r).Decode(data) } + +// Save to disk file in json format. +func jsonSave(f interface { + io.WriteSeeker + Truncate(int64) error +}, data interface{}) error { + b, err := json.Marshal(data) + if err != nil { + return err + } + if err = f.Truncate(0); err != nil { + return err + } + if _, err = f.Seek(0, io.SeekStart); err != nil { + return err + } + _, err = f.Write(b) + if err != nil { + return err + } + return nil +} diff --git a/cmd/utils_test.go b/cmd/utils_test.go index 41fa1a763..a09ffe68e 100644 --- a/cmd/utils_test.go +++ b/cmd/utils_test.go @@ -365,18 +365,47 @@ func TestContains(t *testing.T) { } } -// Test jsonLoadFromSeeker. -func TestJSONLoadFromSeeker(t *testing.T) { +// Test jsonLoad. +func TestJSONLoad(t *testing.T) { format := newFormatFSV1() b, err := json.Marshal(format) if err != nil { t.Fatal(err) } var gotFormat formatFSV1 - if err = jsonLoadFromSeeker(bytes.NewReader(b), &gotFormat); err != nil { + if err = jsonLoad(bytes.NewReader(b), &gotFormat); err != nil { t.Fatal(err) } if *format != gotFormat { - t.Fatal("jsonLoadFromSeeker() failed to decode json") + t.Fatal("jsonLoad() failed to decode json") + } +} + +// Test jsonSave. +func TestJSONSave(t *testing.T) { + f, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + + // Test to make sure formatFSSave overwrites and does not append. + format := newFormatFSV1() + if err = jsonSave(f, format); err != nil { + t.Fatal(err) + } + fi1, err := f.Stat() + if err != nil { + t.Fatal(err) + } + if err = jsonSave(f, format); err != nil { + t.Fatal(err) + } + fi2, err := f.Stat() + if err != nil { + t.Fatal(err) + } + if fi1.Size() != fi2.Size() { + t.Fatal("Size should not differ after jsonSave()", fi1.Size(), fi2.Size(), f.Name()) } }