github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fs/object/object.go (about)

     1  // Package object defines some useful Objects
     2  package object
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"errors"
     8  	"io"
     9  	"io/ioutil"
    10  	"time"
    11  
    12  	"github.com/rclone/rclone/fs"
    13  	"github.com/rclone/rclone/fs/hash"
    14  )
    15  
    16  // NewStaticObjectInfo returns a static ObjectInfo
    17  // If hashes is nil and fs is not nil, the hash map will be replaced with
    18  // empty hashes of the types supported by the fs.
    19  func NewStaticObjectInfo(remote string, modTime time.Time, size int64, storable bool, hashes map[hash.Type]string, fs fs.Info) fs.ObjectInfo {
    20  	info := &staticObjectInfo{
    21  		remote:   remote,
    22  		modTime:  modTime,
    23  		size:     size,
    24  		storable: storable,
    25  		hashes:   hashes,
    26  		fs:       fs,
    27  	}
    28  	if fs != nil && hashes == nil {
    29  		set := fs.Hashes().Array()
    30  		info.hashes = make(map[hash.Type]string)
    31  		for _, ht := range set {
    32  			info.hashes[ht] = ""
    33  		}
    34  	}
    35  	return info
    36  }
    37  
    38  type staticObjectInfo struct {
    39  	remote   string
    40  	modTime  time.Time
    41  	size     int64
    42  	storable bool
    43  	hashes   map[hash.Type]string
    44  	fs       fs.Info
    45  }
    46  
    47  func (i *staticObjectInfo) Fs() fs.Info                           { return i.fs }
    48  func (i *staticObjectInfo) Remote() string                        { return i.remote }
    49  func (i *staticObjectInfo) String() string                        { return i.remote }
    50  func (i *staticObjectInfo) ModTime(ctx context.Context) time.Time { return i.modTime }
    51  func (i *staticObjectInfo) Size() int64                           { return i.size }
    52  func (i *staticObjectInfo) Storable() bool                        { return i.storable }
    53  func (i *staticObjectInfo) Hash(ctx context.Context, h hash.Type) (string, error) {
    54  	if len(i.hashes) == 0 {
    55  		return "", hash.ErrUnsupported
    56  	}
    57  	if hash, ok := i.hashes[h]; ok {
    58  		return hash, nil
    59  	}
    60  	return "", hash.ErrUnsupported
    61  }
    62  
    63  // MemoryFs is an in memory Fs, it only supports FsInfo and Put
    64  var MemoryFs memoryFs
    65  
    66  // memoryFs is an in memory fs
    67  type memoryFs struct{}
    68  
    69  // Name of the remote (as passed into NewFs)
    70  func (memoryFs) Name() string { return "memory" }
    71  
    72  // Root of the remote (as passed into NewFs)
    73  func (memoryFs) Root() string { return "" }
    74  
    75  // String returns a description of the FS
    76  func (memoryFs) String() string { return "memory" }
    77  
    78  // Precision of the ModTimes in this Fs
    79  func (memoryFs) Precision() time.Duration { return time.Nanosecond }
    80  
    81  // Returns the supported hash types of the filesystem
    82  func (memoryFs) Hashes() hash.Set { return hash.Supported() }
    83  
    84  // Features returns the optional features of this Fs
    85  func (memoryFs) Features() *fs.Features { return &fs.Features{} }
    86  
    87  // List the objects and directories in dir into entries.  The
    88  // entries can be returned in any order but should be for a
    89  // complete directory.
    90  //
    91  // dir should be "" to list the root, and should not have
    92  // trailing slashes.
    93  //
    94  // This should return ErrDirNotFound if the directory isn't
    95  // found.
    96  func (memoryFs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
    97  	return nil, nil
    98  }
    99  
   100  // NewObject finds the Object at remote.  If it can't be found
   101  // it returns the error ErrorObjectNotFound.
   102  func (memoryFs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
   103  	return nil, fs.ErrorObjectNotFound
   104  }
   105  
   106  // Put in to the remote path with the modTime given of the given size
   107  //
   108  // May create the object even if it returns an error - if so
   109  // will return the object and the error, otherwise will return
   110  // nil and the error
   111  func (memoryFs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
   112  	o := NewMemoryObject(src.Remote(), src.ModTime(ctx), nil)
   113  	return o, o.Update(ctx, in, src, options...)
   114  }
   115  
   116  // Mkdir makes the directory (container, bucket)
   117  //
   118  // Shouldn't return an error if it already exists
   119  func (memoryFs) Mkdir(ctx context.Context, dir string) error {
   120  	return errors.New("memoryFs: can't make directory")
   121  }
   122  
   123  // Rmdir removes the directory (container, bucket) if empty
   124  //
   125  // Return an error if it doesn't exist or isn't empty
   126  func (memoryFs) Rmdir(ctx context.Context, dir string) error {
   127  	return fs.ErrorDirNotFound
   128  }
   129  
   130  var _ fs.Fs = MemoryFs
   131  
   132  // MemoryObject is an in memory object
   133  type MemoryObject struct {
   134  	remote  string
   135  	modTime time.Time
   136  	content []byte
   137  }
   138  
   139  // NewMemoryObject returns an in memory Object with the modTime and content passed in
   140  func NewMemoryObject(remote string, modTime time.Time, content []byte) *MemoryObject {
   141  	return &MemoryObject{
   142  		remote:  remote,
   143  		modTime: modTime,
   144  		content: content,
   145  	}
   146  }
   147  
   148  // Content returns the underlying buffer
   149  func (o *MemoryObject) Content() []byte {
   150  	return o.content
   151  }
   152  
   153  // Fs returns read only access to the Fs that this object is part of
   154  func (o *MemoryObject) Fs() fs.Info {
   155  	return MemoryFs
   156  }
   157  
   158  // Remote returns the remote path
   159  func (o *MemoryObject) Remote() string {
   160  	return o.remote
   161  }
   162  
   163  // String returns a description of the Object
   164  func (o *MemoryObject) String() string {
   165  	return o.remote
   166  }
   167  
   168  // ModTime returns the modification date of the file
   169  func (o *MemoryObject) ModTime(ctx context.Context) time.Time {
   170  	return o.modTime
   171  }
   172  
   173  // Size returns the size of the file
   174  func (o *MemoryObject) Size() int64 {
   175  	return int64(len(o.content))
   176  }
   177  
   178  // Storable says whether this object can be stored
   179  func (o *MemoryObject) Storable() bool {
   180  	return true
   181  }
   182  
   183  // Hash returns the requested hash of the contents
   184  func (o *MemoryObject) Hash(ctx context.Context, h hash.Type) (string, error) {
   185  	hash, err := hash.NewMultiHasherTypes(hash.Set(h))
   186  	if err != nil {
   187  		return "", err
   188  	}
   189  	_, err = hash.Write(o.content)
   190  	if err != nil {
   191  		return "", err
   192  	}
   193  	return hash.Sums()[h], nil
   194  }
   195  
   196  // SetModTime sets the metadata on the object to set the modification date
   197  func (o *MemoryObject) SetModTime(ctx context.Context, modTime time.Time) error {
   198  	o.modTime = modTime
   199  	return nil
   200  }
   201  
   202  // Open opens the file for read.  Call Close() on the returned io.ReadCloser
   203  func (o *MemoryObject) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
   204  	content := o.content
   205  	for _, option := range options {
   206  		switch x := option.(type) {
   207  		case *fs.RangeOption:
   208  			content = o.content[x.Start:x.End]
   209  		case *fs.SeekOption:
   210  			content = o.content[x.Offset:]
   211  		default:
   212  			if option.Mandatory() {
   213  				fs.Logf(o, "Unsupported mandatory option: %v", option)
   214  			}
   215  		}
   216  	}
   217  	return ioutil.NopCloser(bytes.NewBuffer(content)), nil
   218  }
   219  
   220  // Update in to the object with the modTime given of the given size
   221  //
   222  // This re-uses the internal buffer if at all possible.
   223  func (o *MemoryObject) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
   224  	size := src.Size()
   225  	if size == 0 {
   226  		o.content = nil
   227  	} else if size < 0 || int64(cap(o.content)) < size {
   228  		o.content, err = ioutil.ReadAll(in)
   229  	} else {
   230  		o.content = o.content[:size]
   231  		_, err = io.ReadFull(in, o.content)
   232  	}
   233  	o.modTime = src.ModTime(ctx)
   234  	return err
   235  }
   236  
   237  // Remove this object
   238  func (o *MemoryObject) Remove(ctx context.Context) error {
   239  	return errors.New("memoryObject.Remove not supported")
   240  }