summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Borg <jakob@kastelo.net>2022-10-16 17:04:28 +0200
committerGitHub <noreply@github.com>2022-10-16 17:04:28 +0200
commitd3f50637d2e818c2b6ad516e4811fe2192b9b305 (patch)
treedbe0757e766d4ac234301c6bee91ecd2ae69775b
parented588ce335877b31f864581bd130d9fa528fd36e (diff)
lib/model, lib/protocol: Fix file comparisons (fixes #8594) (#8603)
-rw-r--r--lib/model/folder.go17
-rw-r--r--lib/protocol/bep_extensions.go49
2 files changed, 41 insertions, 25 deletions
diff --git a/lib/model/folder.go b/lib/model/folder.go
index 555de4ac69..52638a2dfb 100644
--- a/lib/model/folder.go
+++ b/lib/model/folder.go
@@ -601,14 +601,15 @@ func (b *scanBatch) Update(fi protocol.FileInfo, snap *db.Snapshot) bool {
b.Remove(fi.Name)
return true
}
- case gf.IsEquivalentOptional(fi, protocol.FileInfoComparison{
- ModTimeWindow: b.f.modTimeWindow,
- IgnorePerms: b.f.IgnorePerms,
- IgnoreBlocks: true,
- IgnoreFlags: protocol.FlagLocalReceiveOnly,
- IgnoreOwnership: !b.f.SyncOwnership,
- IgnoreXattrs: !b.f.SyncXattrs,
- }):
+ 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.
l.Debugf("%v scanning: Merging identical locally changed item with global", b.f, fi)
fi = gf
diff --git a/lib/protocol/bep_extensions.go b/lib/protocol/bep_extensions.go
index d2a0cad35c..3d3eb437c3 100644
--- a/lib/protocol/bep_extensions.go
+++ b/lib/protocol/bep_extensions.go
@@ -246,7 +246,7 @@ func (f FileInfo) isEquivalent(other FileInfo, comp FileInfoComparison) bool {
// If we are recording inode change times and it changed, they are not
// equal.
- if f.InodeChangeNs != 0 && other.InodeChangeNs != 0 && f.InodeChangeNs != other.InodeChangeNs {
+ if (f.InodeChangeNs != 0 && other.InodeChangeNs != 0) && f.InodeChangeNs != other.InodeChangeNs {
return false
}
@@ -258,21 +258,12 @@ func (f FileInfo) isEquivalent(other FileInfo, comp FileInfoComparison) bool {
return false
}
- // OS data comparison is special: we consider a difference only if an
- // entry for the same OS exists on both sides and they are different.
- // Otherwise a file would become different as soon as it's synced from
- // Windows to Linux, as Linux would add a new POSIX entry for the file.
if !comp.IgnoreOwnership && f.Platform != other.Platform {
- if f.Platform.Unix != nil && other.Platform.Unix != nil {
- if *f.Platform.Unix != *other.Platform.Unix {
- return false
- }
+ if !unixOwnershipEqual(f.Platform.Unix, other.Platform.Unix) {
+ return false
}
- if f.Platform.Windows != nil && other.Platform.Windows != nil {
- if f.Platform.Windows.OwnerName != other.Platform.Windows.OwnerName ||
- f.Platform.Windows.OwnerIsGroup != other.Platform.Windows.OwnerIsGroup {
- return false
- }
+ if !windowsOwnershipEqual(f.Platform.Windows, other.Platform.Windows) {
+ return false
}
}
if !comp.IgnoreXattrs && f.Platform != other.Platform {
@@ -542,11 +533,15 @@ func (x *FileInfoType) UnmarshalJSON(data []byte) error {
}
func xattrsEqual(a, b *XattrData) bool {
- if a == nil || b == nil {
- // Having no data on either side means we have nothing to compare
- // to, and we consider that equal.
+ aEmpty := a == nil || len(a.Xattrs) == 0
+ bEmpty := b == nil || len(b.Xattrs) == 0
+ if aEmpty && bEmpty {
return true
}
+ if aEmpty || bEmpty {
+ // Only one side is empty, so they can't be equal.
+ return false
+ }
if len(a.Xattrs) != len(b.Xattrs) {
return false
}
@@ -560,3 +555,23 @@ func xattrsEqual(a, b *XattrData) bool {
}
return true
}
+
+func unixOwnershipEqual(a, b *UnixData) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a == nil || b == nil {
+ return false
+ }
+ return a.UID == b.UID && a.GID == b.GID && a.OwnerName == b.OwnerName && a.GroupName == b.GroupName
+}
+
+func windowsOwnershipEqual(a, b *WindowsData) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a == nil || b == nil {
+ return false
+ }
+ return a.OwnerName == b.OwnerName && a.OwnerIsGroup == b.OwnerIsGroup
+}