mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-25 04:06:03 +00:00
162 lines
3.6 KiB
Go
162 lines
3.6 KiB
Go
// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// blame: jnml, labs.nic.cz
|
|
|
|
package storage
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math"
|
|
"os"
|
|
)
|
|
|
|
//TODO -> exported type w/ exported fields
|
|
type memaccessor struct {
|
|
f *os.File
|
|
fi *FileInfo
|
|
b []byte
|
|
}
|
|
|
|
// Implementation of Accessor.
|
|
func (m *memaccessor) BeginUpdate() error { return nil }
|
|
|
|
// Implementation of Accessor.
|
|
func (f *memaccessor) EndUpdate() error { return nil }
|
|
|
|
// NewMem returns a new Accessor backed by an os.File. The returned Accessor
|
|
// keeps all of the store content in memory. The memory and file images are
|
|
// synced only by Sync and Close. Recomended for small amounts of data only
|
|
// and content which may be lost on process kill/crash. NewMem return the
|
|
// Accessor or an error of any.
|
|
//
|
|
// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op.
|
|
func NewMem(f *os.File) (store Accessor, err error) {
|
|
a := &memaccessor{f: f}
|
|
if err = f.Truncate(0); err != nil {
|
|
return
|
|
}
|
|
|
|
var fi os.FileInfo
|
|
if fi, err = a.f.Stat(); err != nil {
|
|
return
|
|
}
|
|
|
|
a.fi = NewFileInfo(fi, a)
|
|
store = a
|
|
return
|
|
}
|
|
|
|
// OpenMem return a new Accessor backed by an os.File. The store content is
|
|
// loaded from f. The returned Accessor keeps all of the store content in
|
|
// memory. The memory and file images are synced only Sync and Close.
|
|
// Recomended for small amounts of data only and content which may be lost on
|
|
// process kill/crash. OpenMem return the Accessor or an error of any.
|
|
//
|
|
// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op.
|
|
func OpenMem(f *os.File) (store Accessor, err error) {
|
|
a := &memaccessor{f: f}
|
|
if a.b, err = ioutil.ReadAll(a.f); err != nil {
|
|
a.f.Close()
|
|
return
|
|
}
|
|
|
|
var fi os.FileInfo
|
|
if fi, err = a.f.Stat(); err != nil {
|
|
a.f.Close()
|
|
return
|
|
}
|
|
|
|
a.fi = NewFileInfo(fi, a)
|
|
store = a
|
|
return
|
|
}
|
|
|
|
// Close implements Accessor. Specifically it synchronizes the memory and file images.
|
|
func (a *memaccessor) Close() (err error) {
|
|
defer func() {
|
|
a.b = nil
|
|
if a.f != nil {
|
|
if e := a.f.Close(); e != nil && err == nil {
|
|
err = e
|
|
}
|
|
}
|
|
a.f = nil
|
|
}()
|
|
|
|
return a.Sync()
|
|
}
|
|
|
|
func (a *memaccessor) Name() string {
|
|
return a.f.Name()
|
|
}
|
|
|
|
func (a *memaccessor) ReadAt(b []byte, off int64) (n int, err error) {
|
|
if off < 0 || off > math.MaxInt32 {
|
|
return -1, fmt.Errorf("ReadAt: illegal offset %#x", off)
|
|
}
|
|
|
|
rq, fp := len(b), int(off)
|
|
if fp+rq > len(a.b) {
|
|
return -1, fmt.Errorf("ReadAt: illegal rq %#x @ offset %#x, len %#x", rq, fp, len(a.b))
|
|
}
|
|
|
|
copy(b, a.b[fp:])
|
|
return
|
|
}
|
|
|
|
func (a *memaccessor) Stat() (fi os.FileInfo, err error) {
|
|
i := a.fi
|
|
i.FSize = int64(len(a.b))
|
|
fi = i
|
|
return
|
|
}
|
|
|
|
// Sync implements Accessor. Specifically it synchronizes the memory and file images.
|
|
func (a *memaccessor) Sync() (err error) {
|
|
var n int
|
|
if n, err = a.f.WriteAt(a.b, 0); n != len(a.b) {
|
|
return
|
|
}
|
|
|
|
return a.f.Truncate(int64(len(a.b)))
|
|
}
|
|
|
|
func (a *memaccessor) Truncate(size int64) (err error) {
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
err = e.(error)
|
|
}
|
|
}()
|
|
|
|
if size > math.MaxInt32 {
|
|
panic(errors.New("truncate: illegal size"))
|
|
}
|
|
|
|
a.b = a.b[:int(size)]
|
|
return
|
|
}
|
|
|
|
func (a *memaccessor) WriteAt(b []byte, off int64) (n int, err error) {
|
|
if off < 0 || off > math.MaxInt32 {
|
|
return -1, errors.New("WriteAt: illegal offset")
|
|
}
|
|
|
|
rq, fp, size := len(b), int(off), len(a.b)
|
|
if need := rq + fp; need > size {
|
|
if need <= cap(a.b) {
|
|
a.b = a.b[:need]
|
|
} else {
|
|
nb := make([]byte, need, 2*need)
|
|
copy(nb, a.b)
|
|
a.b = nb
|
|
}
|
|
}
|
|
|
|
copy(a.b[int(off):], b)
|
|
return
|
|
}
|