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 )