fs: Implement --no-update-dir-modtime to disable setting modification times on dirs

This commit is contained in:
Nick Craig-Wood 2024-03-07 16:13:36 +00:00
parent 99acee7ba0
commit 4e07a72dc7
7 changed files with 62 additions and 4 deletions

View File

@ -1809,6 +1809,11 @@ files if they are incorrect as it would normally.
This can be used if the remote is being synced with another tool also
(e.g. the Google Drive client).
### --no-update-dir-modtime ###
When using this flag, rclone won't update modification times of remote
directories if they are incorrect as it would normally.
### --order-by string ###
The `--order-by` flag controls the order in which files in the backlog

View File

@ -89,6 +89,7 @@ type ConfigInfo struct {
NoCheckDest bool
NoUnicodeNormalization bool
NoUpdateModTime bool
NoUpdateDirModTime bool
DataRateUnit string
CompareDest []string
CopyDest []string

View File

@ -91,6 +91,7 @@ func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) {
flags.BoolVarP(flagSet, &ci.NoCheckDest, "no-check-dest", "", ci.NoCheckDest, "Don't check the destination, copy regardless", "Copy")
flags.BoolVarP(flagSet, &ci.NoUnicodeNormalization, "no-unicode-normalization", "", ci.NoUnicodeNormalization, "Don't normalize unicode characters in filenames", "Config")
flags.BoolVarP(flagSet, &ci.NoUpdateModTime, "no-update-modtime", "", ci.NoUpdateModTime, "Don't update destination modtime if files identical", "Copy")
flags.BoolVarP(flagSet, &ci.NoUpdateDirModTime, "no-update-dir-modtime", "", ci.NoUpdateModTime, "Don't update directory modification times", "Copy")
flags.StringArrayVarP(flagSet, &ci.CompareDest, "compare-dest", "", nil, "Include additional comma separated server-side paths during comparison", "Copy")
flags.StringArrayVarP(flagSet, &ci.CopyDest, "copy-dest", "", nil, "Implies --compare-dest but also copies files from paths into destination", "Copy")
flags.StringVarP(flagSet, &ci.BackupDir, "backup-dir", "", ci.BackupDir, "Make backups into hierarchy based in DIR", "Sync")

View File

@ -2612,6 +2612,11 @@ func CopyDirMetadata(ctx context.Context, f fs.Fs, dst fs.Directory, dir string,
// It does not create the directory.
func SetDirModTime(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, modTime time.Time) (newDst fs.Directory, err error) {
logName := dirName(f, dst, dir)
ci := fs.GetConfig(ctx)
if ci.NoUpdateDirModTime {
fs.Debugf(logName, "Skipping set directory modification time as --no-update-dir-modtime is set")
return nil, nil
}
if SkipDestructive(ctx, logName, "set directory modification time") {
return nil, nil
}

View File

@ -1755,14 +1755,21 @@ func TestCopyDirMetadata(t *testing.T) {
func TestSetDirModTime(t *testing.T) {
const name = "set modtime on existing directory"
ctx := context.Background()
ctx, ci := fs.AddConfig(context.Background())
r := fstest.NewRun(t)
if r.Fremote.Features().DirSetModTime == nil && !r.Fremote.Features().WriteDirSetModTime {
t.Skip("Skipping test as remote does not support DirSetModTime or WriteDirSetModTime")
}
// First try with the directory not existing - should return an error
// Check that we obey --no-update-dir-modtime - this should return nil, nil
ci.NoUpdateDirModTime = true
newDst, err := operations.SetDirModTime(ctx, r.Fremote, nil, "set modtime on non existent directory", t2)
require.NoError(t, err)
require.Nil(t, newDst)
ci.NoUpdateDirModTime = false
// First try with the directory not existing - should return an error
newDst, err = operations.SetDirModTime(ctx, r.Fremote, nil, "set modtime on non existent directory", t2)
require.Error(t, err)
require.Nil(t, newDst)

View File

@ -154,8 +154,8 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
trackRenamesCh: make(chan fs.Object, ci.Checkers),
checkFirst: ci.CheckFirst,
setDirMetadata: ci.Metadata && fsrc.Features().ReadDirMetadata && fdst.Features().WriteDirMetadata,
setDirModTime: fdst.Features().WriteDirSetModTime || fdst.Features().MkdirMetadata != nil || fdst.Features().DirSetModTime != nil,
setDirModTimeAfter: fdst.Features().DirModTimeUpdatesOnWrite,
setDirModTime: !ci.NoUpdateDirModTime && (fdst.Features().WriteDirSetModTime || fdst.Features().MkdirMetadata != nil || fdst.Features().DirSetModTime != nil),
setDirModTimeAfter: !ci.NoUpdateDirModTime && fdst.Features().DirModTimeUpdatesOnWrite,
modifiedDirs: make(map[string]struct{}),
}

View File

@ -344,6 +344,45 @@ func TestMoveEmptyDirectories(t *testing.T) {
fstest.CheckDirModTime(ctx, t, r.Fremote, got, subDirT)
}
// Test that --no-update-dir-modtime is working
func TestSyncNoUpdateDirModtime(t *testing.T) {
r := fstest.NewRun(t)
if r.Fremote.Features().DirSetModTime == nil {
t.Skip("Skipping test as backend does not support DirSetModTime")
}
ctx, ci := fs.AddConfig(context.Background())
ci.NoUpdateDirModTime = true
const name = "sub dir no update dir modtime"
// Set the modtime on name to something specific
_, err := operations.MkdirModTime(ctx, r.Flocal, name, t1)
require.NoError(t, err)
// Create the remote directory with the current time
require.NoError(t, r.Fremote.Mkdir(ctx, name))
// Read its modification time
wantT := fstest.NewDirectory(ctx, t, r.Fremote, name).ModTime(ctx)
ctx = predictDstFromLogger(ctx)
err = Sync(ctx, r.Fremote, r.Flocal, true)
require.NoError(t, err)
testLoggerVsLsf(ctx, r.Fremote, operations.GetLoggerOpt(ctx).JSON, t)
r.CheckRemoteListing(
t,
[]fstest.Item{},
[]string{
name,
},
)
// Read the new directory modification time - it should not have changed
gotT := fstest.NewDirectory(ctx, t, r.Fremote, name).ModTime(ctx)
fstest.AssertTimeEqualWithPrecision(t, name, wantT, gotT, r.Fremote.Precision())
}
// Test sync empty directories
func TestSyncEmptyDirectories(t *testing.T) {
ctx := context.Background()