From 2eaaf91b83fb8acfd37469cee8ef1cb6e2113af8 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 13 Jul 2026 11:22:04 +0100 Subject: [PATCH] filen: fix incorrect modtime after updating a file or setting its modtime Object.Update and SetModTime left the in-memory modtime at the source's nanosecond precision, while the server stores milliseconds. Afterwards the in-memory state did not match what a fresh List would report, which broke wrappers that compare modtimes (e.g. the hasher backend's fingerprint, which made it lose track of hashes whenever a file was replaced). The SDK serializes modtimes as UnixMilli and NewIncompleteFile already rounds to milliseconds, so Put and the chunked upload path are unaffected. Round the modtime to milliseconds in Update and SetModTime too, so every path holds the same value the server returns, without needing to re-read the metadata from the server after upload. Fixes #9308 --- backend/filen/filen.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/filen/filen.go b/backend/filen/filen.go index 783ad45b1..ef1b0f1f6 100644 --- a/backend/filen/filen.go +++ b/backend/filen/filen.go @@ -710,7 +710,10 @@ func (o *Object) Storable() bool { // SetModTime sets the metadata on the object to set the modification date func (o *Object) SetModTime(ctx context.Context, t time.Time) error { - o.file.LastModified = t + // The server stores modtimes with millisecond precision so round + // here too to keep the in-memory modtime identical to the one a + // fresh listing returns. + o.file.LastModified = t.Round(time.Millisecond) return o.fs.filen.UpdateMeta(ctx, o.file) } @@ -752,7 +755,10 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op fs.Logf(option, "Unsupported mandatory option: %v", option) } } - newModTime := src.ModTime(ctx) + // The server stores modtimes with millisecond precision so round + // here too to keep the in-memory modtime identical to the one a + // fresh listing returns. + newModTime := src.ModTime(ctx).Round(time.Millisecond) newIncomplete, err := o.file.NewFromBase(o.fs.filen.FileEncryptionVersion) if err != nil { return err