diff --git a/lib/model/folder.go b/lib/model/folder.go index 555de4ac6..52638a2df 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 d2a0cad35..3d3eb437c 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 +}