Repository: rclone/rclone
File: fs/sync/sync.go (Go)

Code before:
	s.modifiedDirs[dir] = struct{}{}
}

// like markDirModified, but accepts an Object instead of a string.
// the marked dir will be this object's parent.
func (s *syncCopyMove) markDirModifiedObject(o fs.Object) {
	dir := path.Dir(o.Remote())
	if dir == "." {
		dir = ""
	}
	s.markDirModified(dir)
}

// copyDirMetadata copies the src directory modTime or Metadata to dst
// or f if nil. If dst is nil then it uses dir as the name of the new
// directory.
//
// It returns the destination directory if possible.  Note that this may
// be nil.
func (s *syncCopyMove) copyDirMetadata(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, src fs.Directory) (newDst fs.Directory) {
	var err error
	equal := operations.DirsEqual(ctx, src, dst, operations.DirsEqualOpt{ModifyWindow: s.modifyWindow, SetDirModtime: s.setDirModTime, SetDirMetadata: s.setDirMetadata})
	if !s.setDirModTimeAfter && equal {
		return nil
	}
	newDst = dst
	if !equal {
		if s.setDirMetadata && s.copyEmptySrcDirs {
			newDst, err = operations.CopyDirMetadata(ctx, f, dst, dir, src)
		} else {
			if dst == nil && s.setDirModTime && s.copyEmptySrcDirs {
				newDst, err = operations.MkdirModTime(ctx, f, dir, src.ModTime(ctx))
			} else if dst == nil && s.copyEmptySrcDirs {
				err = operations.Mkdir(ctx, f, dir)
			} else if s.setDirModTime {
				newDst, _ = operations.SetDirModTime(ctx, f, dst, dir, src.ModTime(ctx))
			}
		}
	}
	// If we need to set modtime after and we created a dir, then save it for later
	if s.setDirModTime && s.setDirModTimeAfter && err == nil {
		if newDst != nil {
			dir = newDst.Remote()
		}
		level := strings.Count(dir, "/") + 1
		// The root directory "" is at the top level
		if dir == "" {
			level = 0
		}
		s.setDirModTimeMu.Lock()
		// Keep track of the maximum level inserted

Review comment (suggestion):
I note that we used to assign `newDst` here only if `s.setDirModTimeAfter && equal`, and now we are doing it regardless...but I'm struggling to think of what problem this would cause, and all the tests seem to be passing. Maybe it's fine? I think we were relying on `newDst` to track whether or not we created a dir. But maybe that is still the case as `dst` could be `nil` here and then would get overwritten as necessary.

Code after:
	s.modifiedDirs[dir] = struct{}{}
}

// like markDirModified, but accepts an Object instead of a string.
// the marked dir will be this object's parent.
func (s *syncCopyMove) markDirModifiedObject(o fs.Object) {
	dir := path.Dir(o.Remote())
	if dir == "." {
		dir = ""
	}
	s.markDirModified(dir)
}

// copyDirMetadata copies the src directory modTime or Metadata to dst
// or f if nil. If dst is nil then it uses dir as the name of the new
// directory.
//
// It returns the destination directory if possible.  Note that this may
// be nil.
func (s *syncCopyMove) copyDirMetadata(ctx context.Context, f fs.Fs, dst fs.Directory, dir string, src fs.Directory) (newDst fs.Directory) {
	var err error
	equal := operations.DirsEqual(ctx, src, dst, operations.DirsEqualOpt{ModifyWindow: s.modifyWindow, SetDirModtime: s.setDirModTime, SetDirMetadata: s.setDirMetadata})
	if !s.setDirModTimeAfter && equal {
		return nil
	}
	newDst = dst
	if !equal {
		if s.setDirMetadata && s.copyEmptySrcDirs {
			newDst, err = operations.CopyDirMetadata(ctx, f, dst, dir, src)
		} else if dst == nil && s.setDirModTime && s.copyEmptySrcDirs {
			newDst, err = operations.MkdirModTime(ctx, f, dir, src.ModTime(ctx))
		} else if dst == nil && s.copyEmptySrcDirs {
			err = operations.Mkdir(ctx, f, dir)
		} else if dst != nil && s.setDirModTime {
			newDst, err = operations.SetDirModTime(ctx, f, dst, dir, src.ModTime(ctx))
		}
	}
	// If we need to set modtime after and we created a dir, then save it for later
	if s.setDirModTime && s.setDirModTimeAfter && err == nil {
		if newDst != nil {
			dir = newDst.Remote()
		}
		level := strings.Count(dir, "/") + 1
		// The root directory "" is at the top level
		if dir == "" {
			level = 0
		}
		s.setDirModTimeMu.Lock()
		// Keep track of the maximum level inserted
		if level > s.setDirModTimesMaxLevel {
			s.setDirModTimesMaxLevel = level