rclone/fs/limited.go
klauspost ef06371c93 Create separate interface for object information.
Take out read-only information about a Fs in a separate struct to limit access.

See discussion at #282.
2016-02-19 13:31:09 +00:00

150 lines
3.5 KiB
Go

package fs
import (
"fmt"
"io"
"time"
)
// Limited defines a Fs which can only return the Objects passed in
// from the Fs passed in
type Limited struct {
objects []Object
fs Fs
}
// NewLimited maks a limited Fs limited to the objects passed in
func NewLimited(fs Fs, objects ...Object) Fs {
f := &Limited{
objects: objects,
fs: fs,
}
return f
}
// Name is name of the remote (as passed into NewFs)
func (f *Limited) Name() string {
return f.fs.Name() // return name of underlying remote
}
// Root is the root of the remote (as passed into NewFs)
func (f *Limited) Root() string {
return f.fs.Root() // return root of underlying remote
}
// String returns a description of the FS
func (f *Limited) String() string {
return fmt.Sprintf("%s limited to %d objects", f.fs.String(), len(f.objects))
}
// List the Fs into a channel
func (f *Limited) List() ObjectsChan {
out := make(ObjectsChan, Config.Checkers)
go func() {
for _, obj := range f.objects {
out <- obj
}
close(out)
}()
return out
}
// ListDir lists the Fs directories/buckets/containers into a channel
func (f *Limited) ListDir() DirChan {
out := make(DirChan, Config.Checkers)
close(out)
return out
}
// NewFsObject finds the Object at remote. Returns nil if can't be found
func (f *Limited) NewFsObject(remote string) Object {
for _, obj := range f.objects {
if obj.Remote() == remote {
return obj
}
}
return nil
}
// Put in to the remote path with the modTime given of the given size
//
// May create the object even if it returns an error - if so
// will return the object and the error, otherwise will return
// nil and the error
func (f *Limited) Put(in io.Reader, src ObjectInfo) (Object, error) {
remote := src.Remote()
obj := f.NewFsObject(remote)
if obj == nil {
return nil, fmt.Errorf("Can't create %q in limited fs", remote)
}
return obj, obj.Update(in, src)
}
// Mkdir make the directory (container, bucket)
func (f *Limited) Mkdir() error {
// All directories are already made - just ignore
return nil
}
// Rmdir removes the directory (container, bucket) if empty
func (f *Limited) Rmdir() error {
// Ignore this in a limited fs
return nil
}
// Precision of the ModTimes in this Fs
func (f *Limited) Precision() time.Duration {
return f.fs.Precision()
}
// Hashes returns the supported hash sets.
func (f *Limited) Hashes() HashSet {
return f.fs.Hashes()
}
// Copy src to this remote using server side copy operations.
//
// This is stored with the remote path given
//
// It returns the destination Object and a possible error
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantCopy
func (f *Limited) Copy(src Object, remote string) (Object, error) {
fCopy, ok := f.fs.(Copier)
if !ok {
return nil, ErrorCantCopy
}
return fCopy.Copy(src, remote)
}
// Move src to this remote using server side move operations.
//
// This is stored with the remote path given
//
// It returns the destination Object and a possible error
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
func (f *Limited) Move(src Object, remote string) (Object, error) {
fMove, ok := f.fs.(Mover)
if !ok {
return nil, ErrorCantMove
}
return fMove.Move(src, remote)
}
// UnWrap returns the Fs that this Fs is wrapping
func (f *Limited) UnWrap() Fs {
return f.fs
}
// Check the interfaces are satisfied
var (
_ Fs = (*Limited)(nil)
_ Copier = (*Limited)(nil)
_ Mover = (*Limited)(nil)
_ UnWrapper = (*Limited)(nil)
)