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
|
return false, nil
|
||||||
}
|
}
|
||||||
// Resolve receive-only items which are identical with the global state or
|
// A deleted receive-only item whose global item is our own receive-only
|
||||||
// the global item is our own receive-only item.
|
// change need not be tracked at all.
|
||||||
switch gf, ok, err := b.f.db.GetGlobalFile(b.f.folderID, fi.Name); {
|
if fi.IsDeleted() && (b.f.Type == config.FolderTypeReceiveOnly || b.f.Type == config.FolderTypeReceiveEncrypted) {
|
||||||
case err != nil:
|
switch gf, ok, err := b.f.db.GetGlobalFile(b.f.folderID, fi.Name); {
|
||||||
return false, err
|
case err != nil:
|
||||||
case !ok:
|
return false, err
|
||||||
case gf.IsReceiveOnlyChanged():
|
case ok && 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.
|
|
||||||
b.Remove(fi.Name)
|
b.Remove(fi.Name)
|
||||||
b.f.sl.Debug("Deleting deleted receive-only local-changed file", slogutil.FilePath(fi.Name))
|
b.f.sl.Debug("Deleting deleted receive-only local-changed file", slogutil.FilePath(fi.Name))
|
||||||
return true, nil
|
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)
|
b.updateBatch.Append(fi)
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -845,6 +830,11 @@ outer:
|
|||||||
toIgnore = toIgnore[:0]
|
toIgnore = toIgnore[:0]
|
||||||
ignoredParent = ""
|
ignoredParent = ""
|
||||||
}
|
}
|
||||||
|
if changed, err := f.reconcileReceiveOnlyToGlobal(fi, batch); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if changed {
|
||||||
|
changes++
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nf := fi
|
nf := fi
|
||||||
@@ -925,6 +915,39 @@ outer:
|
|||||||
return changes, nil
|
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) {
|
func (f *folder) findRename(ctx context.Context, file protocol.FileInfo, batch *scanBatch) (protocol.FileInfo, bool) {
|
||||||
if len(file.Blocks) == 0 || file.Size == 0 {
|
if len(file.Blocks) == 0 || file.Size == 0 {
|
||||||
return protocol.FileInfo{}, false
|
return protocol.FileInfo{}, false
|
||||||
|
|||||||
Reference in New Issue
Block a user