mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-26 04:17:35 +00:00
142 lines
4.6 KiB
Go
142 lines
4.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
|
|
|
|
// WIP: Package storage defines and implements storage providers and store accessors.
|
|
package storage
|
|
|
|
import (
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// FileInfo is a type implementing os.FileInfo which has setable fields, like
|
|
// the older os.FileInfo used to have. It is used wehere e.g. the Size is
|
|
// needed to be faked (encapsulated/memory only file, file cache, etc.).
|
|
type FileInfo struct {
|
|
FName string // base name of the file
|
|
FSize int64 // length in bytes
|
|
FMode os.FileMode // file mode bits
|
|
FModTime time.Time // modification time
|
|
FIsDir bool // abbreviation for Mode().IsDir()
|
|
sys interface{} // underlying data source (can be nil)
|
|
}
|
|
|
|
// NewFileInfo creates FileInfo from os.FileInfo fi.
|
|
func NewFileInfo(fi os.FileInfo, sys interface{}) *FileInfo {
|
|
return &FileInfo{fi.Name(), fi.Size(), fi.Mode(), fi.ModTime(), fi.IsDir(), sys}
|
|
}
|
|
|
|
// Implementation of os.FileInfo
|
|
func (fi *FileInfo) Name() string {
|
|
return fi.FName
|
|
}
|
|
|
|
// Implementation of os.FileInfo
|
|
func (fi *FileInfo) Size() int64 {
|
|
return fi.FSize
|
|
}
|
|
|
|
// Implementation of os.FileInfo
|
|
func (fi *FileInfo) Mode() os.FileMode {
|
|
return fi.FMode
|
|
}
|
|
|
|
// Implementation of os.FileInfo
|
|
func (fi *FileInfo) ModTime() time.Time {
|
|
return fi.FModTime
|
|
}
|
|
|
|
// Implementation of os.FileInfo
|
|
func (fi *FileInfo) IsDir() bool {
|
|
return fi.FIsDir
|
|
}
|
|
|
|
func (fi *FileInfo) Sys() interface{} {
|
|
return fi.sys
|
|
}
|
|
|
|
// Accessor provides I/O methods to access a store.
|
|
type Accessor interface {
|
|
|
|
// Close closes the store, rendering it unusable for I/O. It returns an
|
|
// error, if any.
|
|
Close() error
|
|
|
|
// Name returns the name of the file as presented to Open.
|
|
Name() string
|
|
|
|
// ReadAt reads len(b) bytes from the store starting at byte offset off.
|
|
// It returns the number of bytes read and the error, if any.
|
|
// EOF is signaled by a zero count with err set to os.EOF.
|
|
// ReadAt always returns a non-nil Error when n != len(b).
|
|
ReadAt(b []byte, off int64) (n int, err error)
|
|
|
|
// Stat returns the FileInfo structure describing the store. It returns
|
|
// the os.FileInfo and an error, if any.
|
|
Stat() (fi os.FileInfo, err error)
|
|
|
|
// Sync commits the current contents of the store to stable storage.
|
|
// Typically, this means flushing the file system's in-memory copy of
|
|
// recently written data to disk.
|
|
Sync() (err error)
|
|
|
|
// Truncate changes the size of the store. It does not change the I/O
|
|
// offset.
|
|
Truncate(size int64) error
|
|
|
|
// WriteAt writes len(b) bytes to the store starting at byte offset off.
|
|
// It returns the number of bytes written and an error, if any.
|
|
// WriteAt returns a non-nil Error when n != len(b).
|
|
WriteAt(b []byte, off int64) (n int, err error)
|
|
|
|
// Before every [structural] change of a store the BeginUpdate is to be
|
|
// called and paired with EndUpdate after the change makes the store's
|
|
// state consistent again. Invocations of BeginUpdate may nest. On
|
|
// invoking the last non nested EndUpdate an implicit "commit" should
|
|
// be performed by the store/provider. The concrete mechanism is
|
|
// unspecified. It could be for example a write-ahead log. Stores may
|
|
// implement BeginUpdate and EndUpdate as a (documented) no op.
|
|
BeginUpdate() error
|
|
EndUpdate() error
|
|
}
|
|
|
|
// Mutate is a helper/wrapper for executing f in between a.BeginUpdate and
|
|
// a.EndUpdate. Any parameters and/or return values except an error should be
|
|
// captured by a function literal passed as f. The returned err is either nil
|
|
// or the first non nil error returned from the sequence of execution:
|
|
// BeginUpdate, [f,] EndUpdate. The pair BeginUpdate/EndUpdate *is* invoked
|
|
// always regardles of any possible errors produced. Mutate doesn't handle
|
|
// panic, it should be used only with a function [literal] which doesn't panic.
|
|
// Otherwise the pairing of BeginUpdate/EndUpdate is not guaranteed.
|
|
//
|
|
// NOTE: If BeginUpdate, which is invoked before f, returns a non-nil error,
|
|
// then f is not invoked at all (but EndUpdate still is).
|
|
func Mutate(a Accessor, f func() error) (err error) {
|
|
defer func() {
|
|
if e := a.EndUpdate(); e != nil && err == nil {
|
|
err = e
|
|
}
|
|
}()
|
|
|
|
if err = a.BeginUpdate(); err != nil {
|
|
return
|
|
}
|
|
|
|
return f()
|
|
}
|
|
|
|
// LockedMutate wraps Mutate in yet another layer consisting of a
|
|
// l.Lock/l.Unlock pair. All other limitations apply as in Mutate, e.g. no
|
|
// panics are allowed to happen - otherwise no guarantees can be made about
|
|
// Unlock matching the Lock.
|
|
func LockedMutate(a Accessor, l sync.Locker, f func() error) (err error) {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
|
|
return Mutate(a, f)
|
|
}
|