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