opendrive: fix uploaded objects returning the wrong hash and modtime
Objects looked up by name used the /folder/itembyname.json endpoint which does not return the file's MD5 hash, so NewObject returned objects with no hash. Read the metadata with /file/info.json (which does return the hash) instead, using itembyname only to find the file id when it isn't known. Copy and Move returned objects with only the id and size filled in, leaving the modtime and hash empty, and SetModTime kept nanosecond precision in memory while the server stores seconds. These made the returned objects differ from a fresh listing of the same objects.
This commit is contained in:
@@ -413,9 +413,14 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size, _ := strconv.ParseInt(response.Size, 10, 64)
|
||||
dstObj.id = response.FileID
|
||||
dstObj.size = size
|
||||
|
||||
// Read the metadata back so the object returned matches what a
|
||||
// fresh listing would return, in particular modtime and hash
|
||||
err = dstObj.readMetaData(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dstObj, nil
|
||||
}
|
||||
@@ -520,9 +525,14 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
size, _ := strconv.ParseInt(response.Size, 10, 64)
|
||||
dstObj.id = response.FileID
|
||||
dstObj.size = size
|
||||
|
||||
// Read the metadata back so the object returned matches what a
|
||||
// fresh listing would return, in particular modtime and hash
|
||||
err = dstObj.readMetaData(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dstObj, nil
|
||||
}
|
||||
@@ -963,7 +973,8 @@ func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
|
||||
o.modTime = modTime
|
||||
// The server only stores second precision modtimes
|
||||
o.modTime = time.Unix(modTime.Unix(), 0)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -1138,46 +1149,44 @@ func (o *Object) readMetaData(ctx context.Context) (err error) {
|
||||
var resp *http.Response
|
||||
fileInfo := File{}
|
||||
|
||||
// If we know the object id perform a direct lookup
|
||||
// because the /folder/itembyname.json endpoint is unreliable:
|
||||
// newly created objects take an arbitrary amount of time to show up
|
||||
if o.id != "" {
|
||||
// Find the object id with /folder/itembyname.json if we don't
|
||||
// know it already. Note that this endpoint is unreliable:
|
||||
// newly created objects take an arbitrary amount of time to show up.
|
||||
if o.id == "" {
|
||||
folderList := FolderList{}
|
||||
opts := rest.Opts{
|
||||
Method: "GET",
|
||||
Path: fmt.Sprintf("/file/info.json/%s?session_id=%s",
|
||||
o.id, o.fs.session.SessionID),
|
||||
Path: fmt.Sprintf("/folder/itembyname.json/%s/%s?name=%s",
|
||||
o.fs.session.SessionID, directoryID, url.QueryEscape(o.fs.opt.Enc.FromStandardName(leaf))),
|
||||
}
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
resp, err = o.fs.srv.CallJSON(ctx, &opts, nil, &fileInfo)
|
||||
resp, err = o.fs.srv.CallJSON(ctx, &opts, nil, &folderList)
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get fileinfo: %w", err)
|
||||
return fmt.Errorf("failed to get folder list: %w", err)
|
||||
}
|
||||
|
||||
o.id = fileInfo.FileID
|
||||
o.modTime = time.Unix(fileInfo.DateModified, 0)
|
||||
o.md5 = fileInfo.FileHash
|
||||
o.size = fileInfo.Size
|
||||
return nil
|
||||
if len(folderList.Files) == 0 {
|
||||
return fs.ErrorObjectNotFound
|
||||
}
|
||||
o.id = folderList.Files[0].FileID
|
||||
}
|
||||
folderList := FolderList{}
|
||||
|
||||
// Read the metadata using a direct lookup as, unlike
|
||||
// /folder/itembyname.json, it returns the FileHash
|
||||
opts := rest.Opts{
|
||||
Method: "GET",
|
||||
Path: fmt.Sprintf("/folder/itembyname.json/%s/%s?name=%s",
|
||||
o.fs.session.SessionID, directoryID, url.QueryEscape(o.fs.opt.Enc.FromStandardName(leaf))),
|
||||
Path: fmt.Sprintf("/file/info.json/%s?session_id=%s",
|
||||
o.id, o.fs.session.SessionID),
|
||||
}
|
||||
err = o.fs.pacer.Call(func() (bool, error) {
|
||||
resp, err = o.fs.srv.CallJSON(ctx, &opts, nil, &folderList)
|
||||
resp, err = o.fs.srv.CallJSON(ctx, &opts, nil, &fileInfo)
|
||||
return o.fs.shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get folder list: %w", err)
|
||||
return fmt.Errorf("failed to get fileinfo: %w", err)
|
||||
}
|
||||
if len(folderList.Files) == 0 {
|
||||
return fs.ErrorObjectNotFound
|
||||
}
|
||||
fileInfo = folderList.Files[0]
|
||||
|
||||
o.id = fileInfo.FileID
|
||||
o.modTime = time.Unix(fileInfo.DateModified, 0)
|
||||
o.md5 = fileInfo.FileHash
|
||||
|
||||
Reference in New Issue
Block a user