diff --git a/backend/chunker/chunker.go b/backend/chunker/chunker.go index baf4656ed..1867dfc4a 100644 --- a/backend/chunker/chunker.go +++ b/backend/chunker/chunker.go @@ -1888,6 +1888,14 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string return do(ctx, srcFs.base, srcRemote, dstRemote) } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + if do := f.base.Features().DirSetModTime; do != nil { + return do(ctx, dir, modTime) + } + return fs.ErrorNotImplemented +} + // CleanUp the trash in the Fs // // Implement this if you have a way of emptying the trash or @@ -2548,6 +2556,7 @@ var ( _ fs.Copier = (*Fs)(nil) _ fs.Mover = (*Fs)(nil) _ fs.DirMover = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.PutUncheckeder = (*Fs)(nil) _ fs.PutStreamer = (*Fs)(nil) _ fs.CleanUpper = (*Fs)(nil) diff --git a/backend/combine/combine.go b/backend/combine/combine.go index 74384fb48..a6f61de77 100644 --- a/backend/combine/combine.go +++ b/backend/combine/combine.go @@ -965,6 +965,22 @@ func (f *Fs) MergeDirs(ctx context.Context, dirs []fs.Directory) error { return do(ctx, uDirs) } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + u, uDir, err := f.findUpstream(dir) + if err != nil { + return err + } + if uDir == "" { + fs.Debugf(dir, "can't set modtime on upstream root. skipping.") + return nil + } + if do := u.f.Features().DirSetModTime; do != nil { + return do(ctx, uDir, modTime) + } + return fs.ErrorNotImplemented +} + // CleanUp the trash in the Fs // // Implement this if you have a way of emptying the trash or @@ -1099,6 +1115,7 @@ var ( _ fs.PublicLinker = (*Fs)(nil) _ fs.PutUncheckeder = (*Fs)(nil) _ fs.MergeDirser = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.CleanUpper = (*Fs)(nil) _ fs.OpenWriterAter = (*Fs)(nil) _ fs.FullObject = (*Object)(nil) diff --git a/backend/compress/compress.go b/backend/compress/compress.go index b477512e7..aab41c6e3 100644 --- a/backend/compress/compress.go +++ b/backend/compress/compress.go @@ -927,6 +927,14 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string return do(ctx, srcFs.Fs, srcRemote, dstRemote) } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + if do := f.Fs.Features().DirSetModTime; do != nil { + return do(ctx, dir, modTime) + } + return fs.ErrorNotImplemented +} + // CleanUp the trash in the Fs // // Implement this if you have a way of emptying the trash or @@ -1497,6 +1505,7 @@ var ( _ fs.Copier = (*Fs)(nil) _ fs.Mover = (*Fs)(nil) _ fs.DirMover = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.PutStreamer = (*Fs)(nil) _ fs.CleanUpper = (*Fs)(nil) _ fs.UnWrapper = (*Fs)(nil) diff --git a/backend/crypt/crypt.go b/backend/crypt/crypt.go index 54b1335dc..270e9ff6b 100644 --- a/backend/crypt/crypt.go +++ b/backend/crypt/crypt.go @@ -520,6 +520,15 @@ func (f *Fs) Mkdir(ctx context.Context, dir string) error { return f.Fs.Mkdir(ctx, f.cipher.EncryptDirName(dir)) } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + do := f.Fs.Features().DirSetModTime + if do == nil { + return fs.ErrorNotImplemented + } + return do(ctx, f.cipher.EncryptDirName(dir), modTime) +} + // Rmdir removes the directory (container, bucket) if empty // // Return an error if it doesn't exist or isn't empty @@ -1207,6 +1216,7 @@ var ( _ fs.Abouter = (*Fs)(nil) _ fs.Wrapper = (*Fs)(nil) _ fs.MergeDirser = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.DirCacheFlusher = (*Fs)(nil) _ fs.ChangeNotifier = (*Fs)(nil) _ fs.PublicLinker = (*Fs)(nil) diff --git a/backend/hasher/hasher.go b/backend/hasher/hasher.go index a6e83039f..da320bdd0 100644 --- a/backend/hasher/hasher.go +++ b/backend/hasher/hasher.go @@ -341,6 +341,14 @@ func (f *Fs) MergeDirs(ctx context.Context, dirs []fs.Directory) error { return errors.New("MergeDirs not supported") } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + if do := f.Fs.Features().DirSetModTime; do != nil { + return do(ctx, dir, modTime) + } + return fs.ErrorNotImplemented +} + // DirCacheFlush resets the directory cache - used in testing // as an optional interface func (f *Fs) DirCacheFlush() { @@ -530,6 +538,7 @@ var ( _ fs.Abouter = (*Fs)(nil) _ fs.Wrapper = (*Fs)(nil) _ fs.MergeDirser = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.DirCacheFlusher = (*Fs)(nil) _ fs.ChangeNotifier = (*Fs)(nil) _ fs.PublicLinker = (*Fs)(nil) diff --git a/backend/union/union.go b/backend/union/union.go index 5854afc11..a3cb1ce80 100644 --- a/backend/union/union.go +++ b/backend/union/union.go @@ -386,6 +386,26 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string return fs.ErrorDirExists } +// DirSetModTime sets the directory modtime for dir +func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { + upstreams, err := f.action(ctx, dir) + if err != nil { + return err + } + errs := Errors(make([]error, len(upstreams))) + multithread(len(upstreams), func(i int) { + u := upstreams[i] + // ignore DirSetModTime on upstreams which don't support it + if do := u.Features().DirSetModTime; do != nil { + err := do(ctx, dir, modTime) + if err != nil { + errs[i] = fmt.Errorf("%s: %w", upstreams[i].Name(), err) + } + } + }) + return errs.Err() +} + // ChangeNotify calls the passed function with a path // that has had changes. If the implementation // uses polling, it should adhere to the given interval. @@ -988,6 +1008,7 @@ var ( _ fs.Copier = (*Fs)(nil) _ fs.Mover = (*Fs)(nil) _ fs.DirMover = (*Fs)(nil) + _ fs.DirSetModTimer = (*Fs)(nil) _ fs.DirCacheFlusher = (*Fs)(nil) _ fs.ChangeNotifier = (*Fs)(nil) _ fs.Abouter = (*Fs)(nil)