b2: implement SetModTime #3210

SetModTime() is implemented by copying an object onto itself and
updating the metadata in the process.
This commit is contained in:
Nick Craig-Wood 2019-05-24 16:07:22 +01:00
parent a5bed67016
commit 22368b997c
2 changed files with 52 additions and 22 deletions

View File

@ -1206,17 +1206,8 @@ func (o *Object) decodeMetaDataFileInfo(info *api.FileInfo) (err error) {
return o.decodeMetaDataRaw(info.ID, info.SHA1, info.Size, info.UploadTimestamp, info.Info, info.ContentType)
}
// readMetaData gets the metadata if it hasn't already been fetched
//
// Sets
// o.id
// o.modTime
// o.size
// o.sha1
func (o *Object) readMetaData() (err error) {
if o.id != "" {
return nil
}
// getMetaData gets the metadata from the object unconditionally
func (o *Object) getMetaData() (info *api.File, err error) {
maxSearched := 1
var timestamp api.Timestamp
baseRemote := o.remote
@ -1224,7 +1215,6 @@ func (o *Object) readMetaData() (err error) {
timestamp, baseRemote = api.RemoveVersion(baseRemote)
maxSearched = maxVersions
}
var info *api.File
err = o.fs.list("", true, baseRemote, maxSearched, o.fs.opt.Versions, func(remote string, object *api.File, isDirectory bool) error {
if isDirectory {
return nil
@ -1239,12 +1229,30 @@ func (o *Object) readMetaData() (err error) {
})
if err != nil {
if err == fs.ErrorDirNotFound {
return fs.ErrorObjectNotFound
return nil, fs.ErrorObjectNotFound
}
return err
return nil, err
}
if info == nil {
return fs.ErrorObjectNotFound
return nil, fs.ErrorObjectNotFound
}
return info, nil
}
// readMetaData gets the metadata if it hasn't already been fetched
//
// Sets
// o.id
// o.modTime
// o.size
// o.sha1
func (o *Object) readMetaData() (err error) {
if o.id != "" {
return nil
}
info, err := o.getMetaData()
if err != nil {
return err
}
return o.decodeMetaData(info)
}
@ -1283,10 +1291,33 @@ func (o *Object) ModTime() (result time.Time) {
return o.modTime
}
// SetModTime sets the modification time of the local fs object
// SetModTime sets the modification time of the Object
func (o *Object) SetModTime(modTime time.Time) error {
// Not possible with B2
return fs.ErrorCantSetModTime
info, err := o.getMetaData()
if err != nil {
return err
}
info.Info[timeKey] = timeString(modTime)
opts := rest.Opts{
Method: "POST",
Path: "/b2_copy_file",
}
var request = api.CopyFileRequest{
SourceID: o.id,
Name: o.fs.root + o.remote, // copy to same name
MetadataDirective: "REPLACE",
ContentType: info.ContentType,
Info: info.Info,
}
var response api.FileInfo
err = o.fs.pacer.Call(func() (bool, error) {
resp, err := o.fs.srv.CallJSON(&opts, &request, &response)
return o.fs.shouldRetry(resp, err)
})
if err != nil {
return err
}
return o.decodeMetaDataFileInfo(&response)
}
// Storable returns if this object is storable

View File

@ -124,10 +124,9 @@ The modified time is stored as metadata on the object as
in the Backblaze standard. Other tools should be able to use this as
a modified time.
Modified times are used in syncing and are fully supported except in
the case of updating a modification time on an existing object. In
this case the object will be uploaded again as B2 doesn't have an API
method to set the modification time independent of doing an upload.
Modified times are used in syncing and are fully supported. Note that
if a modification time needs to be updated on an object then it will
create a new version of the object.
### SHA1 checksums ###