diff --git a/backend/pixeldrain/api_client.go b/backend/pixeldrain/api_client.go index e422f61c4..3c0b31a37 100644 --- a/backend/pixeldrain/api_client.go +++ b/backend/pixeldrain/api_client.go @@ -179,6 +179,11 @@ func (f *Fs) nodeToObject(node FilesystemNode) (o *Object) { // operations. Saving it here would confuse rclone a lot. So instead we // strip it here and add it back for every API request we need to perform node.Path = strings.TrimPrefix(node.Path, f.pathPrefix) + // The server stores modtimes with millisecond precision, but + // write responses echo back the full precision time which was + // sent, so truncate to make the object identical to the one a + // fresh listing returns. + node.Modified = node.Modified.Truncate(time.Millisecond) return &Object{fs: f, base: node} } diff --git a/backend/pixeldrain/pixeldrain.go b/backend/pixeldrain/pixeldrain.go index abf6c1f57..375110497 100644 --- a/backend/pixeldrain/pixeldrain.go +++ b/backend/pixeldrain/pixeldrain.go @@ -459,7 +459,10 @@ func (f *Fs) About(ctx context.Context) (usage *fs.Usage, err error) { func (o *Object) SetModTime(ctx context.Context, modTime time.Time) (err error) { _, err = o.fs.update(ctx, o.base.Path, fs.Metadata{"mtime": modTime.Format(timeFormat)}) if err == nil { - o.base.Modified = modTime + // The server stores modtimes with millisecond precision so + // truncate here too to keep the in-memory modtime identical + // to the one a fresh listing returns. + o.base.Modified = modTime.Truncate(time.Millisecond) } return err } @@ -475,12 +478,19 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read // // The new object may have been created if an error is returned. func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) { - // Copy the parameters and update the object - o.base.Modified = src.ModTime(ctx) + // Copy the parameters and update the object, truncating the + // modtime to the millisecond precision the server stores it with + o.base.Modified = src.ModTime(ctx).Truncate(time.Millisecond) o.base.FileSize = src.Size() o.base.SHA256Sum, _ = src.Hash(ctx, hash.SHA256) - _, err = o.fs.Put(ctx, in, o, options...) - return err + newObject, err := o.fs.Put(ctx, in, o, options...) + if err != nil { + return err + } + // Keep the metadata from the upload response so the object has + // the hash the server computed. + o.base = newObject.(*Object).base + return nil } // Remove an object