mirror of
https://github.com/rclone/rclone.git
synced 2024-12-01 13:04:21 +08:00
bisync: don't convert modtime precision in listings - fixes #8025
Some checks are pending
Docker beta build / Build image job (push) Waiting to run
Some checks are pending
Docker beta build / Build image job (push) Waiting to run
Before this change, bisync proactively converted modtime precision when greater than what the destination backend supported. This dates back to a time before bisync considered the modifyWindow for same-side comparisons. Back then, it was problematic to save a listing with 12:54:49.7 for a backend that can't handle that precision, as on the next run the backend would report the time as 12:54:50 and bisync would think the file had changed. So the truncation was a workaround to anticipate this and proactively record the time with the precision we expect to receive next time. However, this caused problems for backends (such as dropbox) that round instead of truncating as bisync expected. After this change, bisync preserves the original precision in the listing (without conversion), even when greater than what the backend supports, to avoid rounding error. On the next run, bisync will compare it to the rounded time reported by the backend, and if it's within the modifyWindow, it will treat them as equivalent.
This commit is contained in:
parent
146562975b
commit
956c2963fd
|
@ -43,8 +43,10 @@ var lineRegex = regexp.MustCompile(`^(\S) +(-?\d+) (\S+) (\S+) (\d{4}-\d\d-\d\dT
|
||||||
const timeFormat = "2006-01-02T15:04:05.000000000-0700"
|
const timeFormat = "2006-01-02T15:04:05.000000000-0700"
|
||||||
|
|
||||||
// TZ defines time zone used in listings
|
// TZ defines time zone used in listings
|
||||||
var TZ = time.UTC
|
var (
|
||||||
var tzLocal = false
|
TZ = time.UTC
|
||||||
|
tzLocal = false
|
||||||
|
)
|
||||||
|
|
||||||
// fileInfo describes a file
|
// fileInfo describes a file
|
||||||
type fileInfo struct {
|
type fileInfo struct {
|
||||||
|
@ -83,7 +85,7 @@ func (ls *fileList) has(file string) bool {
|
||||||
}
|
}
|
||||||
_, found := ls.info[file]
|
_, found := ls.info[file]
|
||||||
if !found {
|
if !found {
|
||||||
//try unquoting
|
// try unquoting
|
||||||
file, _ = strconv.Unquote(`"` + file + `"`)
|
file, _ = strconv.Unquote(`"` + file + `"`)
|
||||||
_, found = ls.info[file]
|
_, found = ls.info[file]
|
||||||
}
|
}
|
||||||
|
@ -93,7 +95,7 @@ func (ls *fileList) has(file string) bool {
|
||||||
func (ls *fileList) get(file string) *fileInfo {
|
func (ls *fileList) get(file string) *fileInfo {
|
||||||
info, found := ls.info[file]
|
info, found := ls.info[file]
|
||||||
if !found {
|
if !found {
|
||||||
//try unquoting
|
// try unquoting
|
||||||
file, _ = strconv.Unquote(`"` + file + `"`)
|
file, _ = strconv.Unquote(`"` + file + `"`)
|
||||||
info = ls.info[fmt.Sprint(file)]
|
info = ls.info[fmt.Sprint(file)]
|
||||||
}
|
}
|
||||||
|
@ -420,7 +422,7 @@ func (b *bisyncRun) loadListingNum(listingNum int) (*fileList, error) {
|
||||||
|
|
||||||
func (b *bisyncRun) listDirsOnly(listingNum int) (*fileList, error) {
|
func (b *bisyncRun) listDirsOnly(listingNum int) (*fileList, error) {
|
||||||
var fulllisting *fileList
|
var fulllisting *fileList
|
||||||
var dirsonly = newFileList()
|
dirsonly := newFileList()
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if !b.opt.CreateEmptySrcDirs {
|
if !b.opt.CreateEmptySrcDirs {
|
||||||
|
@ -450,24 +452,6 @@ func (b *bisyncRun) listDirsOnly(listingNum int) (*fileList, error) {
|
||||||
return dirsonly, err
|
return dirsonly, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertPrecision returns the Modtime rounded to Dest's precision if lower, otherwise unchanged
|
|
||||||
// Need to use the other fs's precision (if lower) when copying
|
|
||||||
// Note: we need to use Truncate rather than Round so that After() is reliable.
|
|
||||||
// (2023-11-02 20:22:45.552679442 +0000 < UTC 2023-11-02 20:22:45.553 +0000 UTC)
|
|
||||||
func ConvertPrecision(Modtime time.Time, dst fs.Fs) time.Time {
|
|
||||||
DestPrecision := dst.Precision()
|
|
||||||
|
|
||||||
// In case it's wrapping an Fs with lower precision, try unwrapping and use the lowest.
|
|
||||||
if Modtime.Truncate(DestPrecision).After(Modtime.Truncate(fs.UnWrapFs(dst).Precision())) {
|
|
||||||
DestPrecision = fs.UnWrapFs(dst).Precision()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Modtime.After(Modtime.Truncate(DestPrecision)) {
|
|
||||||
return Modtime.Truncate(DestPrecision)
|
|
||||||
}
|
|
||||||
return Modtime
|
|
||||||
}
|
|
||||||
|
|
||||||
// modifyListing will modify the listing based on the results of the sync
|
// modifyListing will modify the listing based on the results of the sync
|
||||||
func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, results []Results, queues queues, is1to2 bool) (err error) {
|
func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, results []Results, queues queues, is1to2 bool) (err error) {
|
||||||
queue := queues.copy2to1
|
queue := queues.copy2to1
|
||||||
|
@ -533,13 +517,13 @@ func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, res
|
||||||
|
|
||||||
// build src winners list
|
// build src winners list
|
||||||
if result.IsSrc && result.Src != "" && (result.Winner.Err == nil || result.Flags == "d") {
|
if result.IsSrc && result.Src != "" && (result.Winner.Err == nil || result.Flags == "d") {
|
||||||
srcWinners.put(result.Name, result.Size, ConvertPrecision(result.Modtime, src), result.Hash, "-", result.Flags)
|
srcWinners.put(result.Name, result.Size, result.Modtime, result.Hash, "-", result.Flags)
|
||||||
prettyprint(result, "winner: copy to src", fs.LogLevelDebug)
|
prettyprint(result, "winner: copy to src", fs.LogLevelDebug)
|
||||||
}
|
}
|
||||||
|
|
||||||
// build dst winners list
|
// build dst winners list
|
||||||
if result.IsWinner && result.Winner.Side != "none" && (result.Winner.Err == nil || result.Flags == "d") {
|
if result.IsWinner && result.Winner.Side != "none" && (result.Winner.Err == nil || result.Flags == "d") {
|
||||||
dstWinners.put(result.Name, result.Size, ConvertPrecision(result.Modtime, dst), result.Hash, "-", result.Flags)
|
dstWinners.put(result.Name, result.Size, result.Modtime, result.Hash, "-", result.Flags)
|
||||||
prettyprint(result, "winner: copy to dst", fs.LogLevelDebug)
|
prettyprint(result, "winner: copy to dst", fs.LogLevelDebug)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +607,7 @@ func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, res
|
||||||
}
|
}
|
||||||
if srcNewName != "" { // if it was renamed and not deleted
|
if srcNewName != "" { // if it was renamed and not deleted
|
||||||
srcList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
|
srcList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
|
||||||
dstList.put(srcNewName, new.size, ConvertPrecision(new.time, src), new.hash, new.id, new.flags)
|
dstList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags)
|
||||||
}
|
}
|
||||||
if srcNewName != srcOldName {
|
if srcNewName != srcOldName {
|
||||||
srcList.remove(srcOldName)
|
srcList.remove(srcOldName)
|
||||||
|
|
|
@ -1812,6 +1812,12 @@ about _Unison_ and synchronization in general.
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### `v1.68`
|
||||||
|
* Fixed an issue affecting backends that round modtimes to a lower precision.
|
||||||
|
|
||||||
|
### `v1.67`
|
||||||
|
* Added integration tests against all backends.
|
||||||
|
|
||||||
### `v1.66`
|
### `v1.66`
|
||||||
* Copies and deletes are now handled in one operation instead of two
|
* Copies and deletes are now handled in one operation instead of two
|
||||||
* `--track-renames` and `--backup-dir` are now supported
|
* `--track-renames` and `--backup-dir` are now supported
|
||||||
|
|
Loading…
Reference in New Issue
Block a user