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 }