When adding a folder in receive-only mode where the contents were already identical to a remote device, directories would remain as locally changed when everything else had consolidated. The reason this happened is that we only did the matching between locally changed files and their global equivalent for changed items, but directories are typically not "changed" much as we don't track their mtime, so they wouldn't pass through this stage when scanning. Now, instead, do the check when we're anyway walking all the files in phase two of scanning. This catches all cases of identical items, files or directories, regardless of how they came to be in the index. Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
+45
-22
@@ -656,32 +656,17 @@ func (b *scanBatch) Update(fi protocol.FileInfo) (bool, error) {
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
// Resolve receive-only items which are identical with the global state or
|
||||
// the global item is our own receive-only item.
|
||||
switch gf, ok, err := b.f.db.GetGlobalFile(b.f.folderID, fi.Name); {
|
||||
case err != nil:
|
||||
return false, err
|
||||
case !ok:
|
||||
case gf.IsReceiveOnlyChanged():
|
||||
if fi.IsDeleted() {
|
||||
// Our item is deleted and the global item is our own receive only
|
||||
// file. No point in keeping track of that.
|
||||
// A deleted receive-only item whose global item is our own receive-only
|
||||
// change need not be tracked at all.
|
||||
if fi.IsDeleted() && (b.f.Type == config.FolderTypeReceiveOnly || b.f.Type == config.FolderTypeReceiveEncrypted) {
|
||||
switch gf, ok, err := b.f.db.GetGlobalFile(b.f.folderID, fi.Name); {
|
||||
case err != nil:
|
||||
return false, err
|
||||
case ok && gf.IsReceiveOnlyChanged():
|
||||
b.Remove(fi.Name)
|
||||
b.f.sl.Debug("Deleting deleted receive-only local-changed file", slogutil.FilePath(fi.Name))
|
||||
return true, nil
|
||||
}
|
||||
case (b.f.Type == config.FolderTypeReceiveOnly || b.f.Type == config.FolderTypeReceiveEncrypted) &&
|
||||
gf.IsEquivalentOptional(fi, protocol.FileInfoComparison{
|
||||
ModTimeWindow: b.f.modTimeWindow,
|
||||
IgnorePerms: b.f.IgnorePerms,
|
||||
IgnoreBlocks: true,
|
||||
IgnoreFlags: protocol.FlagLocalReceiveOnly,
|
||||
IgnoreOwnership: !b.f.SyncOwnership && !b.f.SendOwnership,
|
||||
IgnoreXattrs: !b.f.SyncXattrs && !b.f.SendXattrs,
|
||||
}):
|
||||
// What we have locally is equivalent to the global file.
|
||||
b.f.sl.Debug("Merging identical locally changed item with global", slogutil.FilePath(fi.Name))
|
||||
fi = gf
|
||||
}
|
||||
b.updateBatch.Append(fi)
|
||||
return true, nil
|
||||
@@ -845,6 +830,11 @@ outer:
|
||||
toIgnore = toIgnore[:0]
|
||||
ignoredParent = ""
|
||||
}
|
||||
if changed, err := f.reconcileReceiveOnlyToGlobal(fi, batch); err != nil {
|
||||
return 0, err
|
||||
} else if changed {
|
||||
changes++
|
||||
}
|
||||
continue
|
||||
}
|
||||
nf := fi
|
||||
@@ -925,6 +915,39 @@ outer:
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
// reconcileReceiveOnlyToGlobal merges a locally receive-only changed item
|
||||
// back into an equivalent global item, when there is no relevant difference
|
||||
// between the two.
|
||||
func (f *folder) reconcileReceiveOnlyToGlobal(fi protocol.FileInfo, batch *scanBatch) (bool, error) {
|
||||
if f.Type != config.FolderTypeReceiveOnly && f.Type != config.FolderTypeReceiveEncrypted {
|
||||
return false, nil
|
||||
}
|
||||
if !fi.IsReceiveOnlyChanged() {
|
||||
return false, nil
|
||||
}
|
||||
gf, ok, err := f.db.GetGlobalFile(f.folderID, fi.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !ok || gf.IsReceiveOnlyChanged() {
|
||||
// No global to adopt, or the global item is our own receive-only
|
||||
// change (nothing to reconcile against).
|
||||
return false, nil
|
||||
}
|
||||
if !gf.IsEquivalentOptional(fi, protocol.FileInfoComparison{
|
||||
ModTimeWindow: f.modTimeWindow,
|
||||
IgnorePerms: f.IgnorePerms,
|
||||
IgnoreBlocks: true,
|
||||
IgnoreFlags: protocol.FlagLocalReceiveOnly,
|
||||
IgnoreOwnership: !f.SyncOwnership && !f.SendOwnership,
|
||||
IgnoreXattrs: !f.SyncXattrs && !f.SendXattrs,
|
||||
}) {
|
||||
return false, nil
|
||||
}
|
||||
f.sl.Debug("Merging identical locally changed item with global", slogutil.FilePath(fi.Name))
|
||||
return batch.Update(gf)
|
||||
}
|
||||
|
||||
func (f *folder) findRename(ctx context.Context, file protocol.FileInfo, batch *scanBatch) (protocol.FileInfo, bool) {
|
||||
if len(file.Blocks) == 0 || file.Size == 0 {
|
||||
return protocol.FileInfo{}, false
|
||||
|
||||
Reference in New Issue
Block a user