lib/model, lib/protocol: Fix file comparisons (fixes #8594) (#8603)

This commit is contained in:
Jakob Borg 2022-10-16 17:04:28 +02:00 committed by GitHub
parent ed588ce335
commit d3f50637d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 25 deletions

View File

@ -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

View File

@ -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
}