all: Add receive only folder type (#5027)
Adds a receive only folder type that does not send changes, and where the user can optionally revert local changes. Also changes some of the icons to make the three folder types distinguishable.
This commit is contained in:
@@ -49,6 +49,10 @@ func (f FileInfo) IsInvalid() bool {
|
||||
return f.RawInvalid || f.LocalFlags&LocalInvalidFlags != 0
|
||||
}
|
||||
|
||||
func (f FileInfo) IsUnsupported() bool {
|
||||
return f.LocalFlags&FlagLocalUnsupported != 0
|
||||
}
|
||||
|
||||
func (f FileInfo) IsIgnored() bool {
|
||||
return f.LocalFlags&FlagLocalIgnored != 0
|
||||
}
|
||||
@@ -57,6 +61,10 @@ func (f FileInfo) MustRescan() bool {
|
||||
return f.LocalFlags&FlagLocalMustRescan != 0
|
||||
}
|
||||
|
||||
func (f FileInfo) IsReceiveOnlyChanged() bool {
|
||||
return f.LocalFlags&FlagLocalReceiveOnly != 0
|
||||
}
|
||||
|
||||
func (f FileInfo) IsDirectory() bool {
|
||||
return f.Type == FileInfoTypeDirectory
|
||||
}
|
||||
@@ -99,6 +107,10 @@ func (f FileInfo) FileName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f FileInfo) FileLocalFlags() uint32 {
|
||||
return f.LocalFlags
|
||||
}
|
||||
|
||||
func (f FileInfo) ModTime() time.Time {
|
||||
return time.Unix(f.ModifiedS, int64(f.ModifiedNs))
|
||||
}
|
||||
@@ -114,7 +126,7 @@ func (f FileInfo) FileVersion() Vector {
|
||||
// WinsConflict returns true if "f" is the one to choose when it is in
|
||||
// conflict with "other".
|
||||
func (f FileInfo) WinsConflict(other FileInfo) bool {
|
||||
// If only one of the files is invalid, that one loses
|
||||
// If only one of the files is invalid, that one loses.
|
||||
if f.IsInvalid() != other.IsInvalid() {
|
||||
return !f.IsInvalid()
|
||||
}
|
||||
@@ -145,7 +157,15 @@ func (f FileInfo) IsEmpty() bool {
|
||||
return f.Version.Counters == nil
|
||||
}
|
||||
|
||||
// IsEquivalent checks that the two file infos represent the same actual file content,
|
||||
func (f FileInfo) IsEquivalent(other FileInfo) bool {
|
||||
return f.isEquivalent(other, false, false, 0)
|
||||
}
|
||||
|
||||
func (f FileInfo) IsEquivalentOptional(other FileInfo, ignorePerms bool, ignoreBlocks bool, ignoreFlags uint32) bool {
|
||||
return f.isEquivalent(other, ignorePerms, ignoreBlocks, ignoreFlags)
|
||||
}
|
||||
|
||||
// isEquivalent checks that the two file infos represent the same actual file content,
|
||||
// i.e. it does purposely not check only selected (see below) struct members.
|
||||
// Permissions (config) and blocks (scanning) can be excluded from the comparison.
|
||||
// Any file info is not "equivalent", if it has different
|
||||
@@ -160,7 +180,7 @@ func (f FileInfo) IsEmpty() bool {
|
||||
// A symlink is not "equivalent", if it has different
|
||||
// - target
|
||||
// A directory does not have anything specific to check.
|
||||
func (f FileInfo) IsEquivalent(other FileInfo, ignorePerms bool, ignoreBlocks bool) bool {
|
||||
func (f FileInfo) isEquivalent(other FileInfo, ignorePerms bool, ignoreBlocks bool, ignoreFlags uint32) bool {
|
||||
if f.MustRescan() || other.MustRescan() {
|
||||
// These are per definition not equivalent because they don't
|
||||
// represent a valid state, even if both happen to have the
|
||||
@@ -168,6 +188,10 @@ func (f FileInfo) IsEquivalent(other FileInfo, ignorePerms bool, ignoreBlocks bo
|
||||
return false
|
||||
}
|
||||
|
||||
// Mask out the ignored local flags before checking IsInvalid() below
|
||||
f.LocalFlags &^= ignoreFlags
|
||||
other.LocalFlags &^= ignoreFlags
|
||||
|
||||
if f.Name != other.Name || f.Type != other.Type || f.Deleted != other.Deleted || f.IsInvalid() != other.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -19,10 +19,18 @@ type DeviceID [DeviceIDLength]byte
|
||||
type ShortID uint64
|
||||
|
||||
var (
|
||||
LocalDeviceID = DeviceID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
EmptyDeviceID = DeviceID{ /* all zeroes */ }
|
||||
LocalDeviceID = repeatedDeviceID(0xff)
|
||||
GlobalDeviceID = repeatedDeviceID(0xf8)
|
||||
EmptyDeviceID = DeviceID{ /* all zeroes */ }
|
||||
)
|
||||
|
||||
func repeatedDeviceID(v byte) (d DeviceID) {
|
||||
for i := range d {
|
||||
d[i] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewDeviceID generates a new device ID from the raw bytes of a certificate
|
||||
func NewDeviceID(rawCert []byte) DeviceID {
|
||||
var n DeviceID
|
||||
|
||||
@@ -94,14 +94,15 @@ const (
|
||||
FlagLocalUnsupported = 1 << 0 // The kind is unsupported, e.g. symlinks on Windows
|
||||
FlagLocalIgnored = 1 << 1 // Matches local ignore patterns
|
||||
FlagLocalMustRescan = 1 << 2 // Doesn't match content on disk, must be rechecked fully
|
||||
FlagLocalReceiveOnly = 1 << 3 // Change detected on receive only folder
|
||||
|
||||
// Flags that should result in the Invalid bit on outgoing updates
|
||||
LocalInvalidFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan
|
||||
LocalInvalidFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly
|
||||
|
||||
// Flags that should result in a file being in conflict with its
|
||||
// successor, due to us not having an up to date picture of its state on
|
||||
// disk.
|
||||
LocalConflictFlags = FlagLocalUnsupported | FlagLocalIgnored
|
||||
LocalConflictFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalReceiveOnly
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -423,6 +423,7 @@ func TestIsEquivalent(t *testing.T) {
|
||||
b FileInfo
|
||||
ignPerms *bool // nil means should not matter, we'll test both variants
|
||||
ignBlocks *bool
|
||||
ignFlags uint32
|
||||
eq bool
|
||||
}
|
||||
cases := []testCase{
|
||||
@@ -491,6 +492,17 @@ func TestIsEquivalent(t *testing.T) {
|
||||
b: FileInfo{LocalFlags: FlagLocalUnsupported},
|
||||
eq: true,
|
||||
},
|
||||
{
|
||||
a: FileInfo{LocalFlags: 0},
|
||||
b: FileInfo{LocalFlags: FlagLocalReceiveOnly},
|
||||
eq: false,
|
||||
},
|
||||
{
|
||||
a: FileInfo{LocalFlags: 0},
|
||||
b: FileInfo{LocalFlags: FlagLocalReceiveOnly},
|
||||
ignFlags: FlagLocalReceiveOnly,
|
||||
eq: true,
|
||||
},
|
||||
|
||||
// Difference in blocks is not OK
|
||||
{
|
||||
@@ -588,10 +600,10 @@ func TestIsEquivalent(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if res := tc.a.IsEquivalent(tc.b, ignPerms, ignBlocks); res != tc.eq {
|
||||
if res := tc.a.isEquivalent(tc.b, ignPerms, ignBlocks, tc.ignFlags); res != tc.eq {
|
||||
t.Errorf("Case %d:\na: %v\nb: %v\na.IsEquivalent(b, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq)
|
||||
}
|
||||
if res := tc.b.IsEquivalent(tc.a, ignPerms, ignBlocks); res != tc.eq {
|
||||
if res := tc.b.isEquivalent(tc.a, ignPerms, ignBlocks, tc.ignFlags); res != tc.eq {
|
||||
t.Errorf("Case %d:\na: %v\nb: %v\nb.IsEquivalent(a, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user