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:
@@ -586,7 +586,7 @@ func (db *Instance) checkGlobals(folder []byte, meta *metadataTracker) {
|
||||
|
||||
if i == 0 {
|
||||
if fi, ok := db.getFile(fk); ok {
|
||||
meta.addFile(globalDeviceID, fi)
|
||||
meta.addFile(protocol.GlobalDeviceID, fi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ func TestUpdate0to3(t *testing.T) {
|
||||
t.Error("Unexpected additional file via sequence", f.FileName())
|
||||
return true
|
||||
}
|
||||
if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalent(e, true, true) {
|
||||
if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, true, true, 0) {
|
||||
found = true
|
||||
} else {
|
||||
t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
|
||||
@@ -330,7 +330,7 @@ func TestUpdate0to3(t *testing.T) {
|
||||
}
|
||||
f := fi.(protocol.FileInfo)
|
||||
delete(need, f.Name)
|
||||
if !f.IsEquivalent(e, true, true) {
|
||||
if !f.IsEquivalentOptional(e, true, true, 0) {
|
||||
t.Errorf("Wrong needed file, got %v, expected %v", f, e)
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -140,11 +140,11 @@ func (t readWriteTransaction) updateGlobal(gk, folder, device []byte, file proto
|
||||
if oldFile, ok := t.getFile(folder, oldGlobalFV.Device, name); ok {
|
||||
// A failure to get the file here is surprising and our
|
||||
// global size data will be incorrect until a restart...
|
||||
meta.removeFile(globalDeviceID, oldFile)
|
||||
meta.removeFile(protocol.GlobalDeviceID, oldFile)
|
||||
}
|
||||
|
||||
// Add the new global to the global size counter
|
||||
meta.addFile(globalDeviceID, newGlobal)
|
||||
meta.addFile(protocol.GlobalDeviceID, newGlobal)
|
||||
|
||||
l.Debugf(`new global for "%v" after update: %v`, file.Name, fl)
|
||||
t.Put(gk, mustMarshal(&fl))
|
||||
@@ -197,7 +197,7 @@ func (t readWriteTransaction) removeFromGlobal(gk, folder, device, file []byte,
|
||||
// didn't exist anyway, apparently
|
||||
continue
|
||||
}
|
||||
meta.removeFile(globalDeviceID, f)
|
||||
meta.removeFile(protocol.GlobalDeviceID, f)
|
||||
removed = true
|
||||
}
|
||||
fl.Versions = append(fl.Versions[:i], fl.Versions[i+1:]...)
|
||||
@@ -215,7 +215,7 @@ func (t readWriteTransaction) removeFromGlobal(gk, folder, device, file []byte,
|
||||
if f, ok := t.getFile(folder, fl.Versions[0].Device, file); ok {
|
||||
// A failure to get the file here is surprising and our
|
||||
// global size data will be incorrect until a restart...
|
||||
meta.addFile(globalDeviceID, f)
|
||||
meta.addFile(protocol.GlobalDeviceID, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
135
lib/db/meta.go
135
lib/db/meta.go
@@ -7,25 +7,30 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/bits"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
// like protocol.LocalDeviceID but with 0xf8 in all positions
|
||||
var globalDeviceID = protocol.DeviceID{0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8}
|
||||
|
||||
// metadataTracker keeps metadata on a per device, per local flag basis.
|
||||
type metadataTracker struct {
|
||||
mut sync.RWMutex
|
||||
counts CountsSet
|
||||
indexes map[protocol.DeviceID]int // device ID -> index in counts
|
||||
indexes map[metaKey]int // device ID + local flags -> index in counts
|
||||
}
|
||||
|
||||
type metaKey struct {
|
||||
dev protocol.DeviceID
|
||||
flags uint32
|
||||
}
|
||||
|
||||
func newMetadataTracker() *metadataTracker {
|
||||
return &metadataTracker{
|
||||
mut: sync.NewRWMutex(),
|
||||
indexes: make(map[protocol.DeviceID]int),
|
||||
indexes: make(map[metaKey]int),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +43,7 @@ func (m *metadataTracker) Unmarshal(bs []byte) error {
|
||||
|
||||
// Initialize the index map
|
||||
for i, c := range m.counts.Counts {
|
||||
m.indexes[protocol.DeviceIDFromBytes(c.DeviceID)] = i
|
||||
m.indexes[metaKey{protocol.DeviceIDFromBytes(c.DeviceID), c.LocalFlags}] = i
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -72,14 +77,15 @@ func (m *metadataTracker) fromDB(db *Instance, folder []byte) error {
|
||||
|
||||
// countsPtr returns a pointer to the corresponding Counts struct, if
|
||||
// necessary allocating one in the process
|
||||
func (m *metadataTracker) countsPtr(dev protocol.DeviceID) *Counts {
|
||||
func (m *metadataTracker) countsPtr(dev protocol.DeviceID, flags uint32) *Counts {
|
||||
// must be called with the mutex held
|
||||
|
||||
idx, ok := m.indexes[dev]
|
||||
key := metaKey{dev, flags}
|
||||
idx, ok := m.indexes[key]
|
||||
if !ok {
|
||||
idx = len(m.counts.Counts)
|
||||
m.counts.Counts = append(m.counts.Counts, Counts{DeviceID: dev[:]})
|
||||
m.indexes[dev] = idx
|
||||
m.counts.Counts = append(m.counts.Counts, Counts{DeviceID: dev[:], LocalFlags: flags})
|
||||
m.indexes[key] = idx
|
||||
}
|
||||
return &m.counts.Counts[idx]
|
||||
}
|
||||
@@ -87,12 +93,23 @@ func (m *metadataTracker) countsPtr(dev protocol.DeviceID) *Counts {
|
||||
// addFile adds a file to the counts, adjusting the sequence number as
|
||||
// appropriate
|
||||
func (m *metadataTracker) addFile(dev protocol.DeviceID, f FileIntf) {
|
||||
if f.IsInvalid() {
|
||||
return
|
||||
m.mut.Lock()
|
||||
|
||||
if flags := f.FileLocalFlags(); flags == 0 {
|
||||
// Account regular files in the zero-flags bucket.
|
||||
m.addFileLocked(dev, 0, f)
|
||||
} else {
|
||||
// Account in flag specific buckets.
|
||||
eachFlagBit(flags, func(flag uint32) {
|
||||
m.addFileLocked(dev, flag, f)
|
||||
})
|
||||
}
|
||||
|
||||
m.mut.Lock()
|
||||
cp := m.countsPtr(dev)
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
func (m *metadataTracker) addFileLocked(dev protocol.DeviceID, flags uint32, f FileIntf) {
|
||||
cp := m.countsPtr(dev, flags)
|
||||
|
||||
switch {
|
||||
case f.IsDeleted():
|
||||
@@ -109,18 +126,27 @@ func (m *metadataTracker) addFile(dev protocol.DeviceID, f FileIntf) {
|
||||
if seq := f.SequenceNo(); seq > cp.Sequence {
|
||||
cp.Sequence = seq
|
||||
}
|
||||
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
// removeFile removes a file from the counts
|
||||
func (m *metadataTracker) removeFile(dev protocol.DeviceID, f FileIntf) {
|
||||
if f.IsInvalid() {
|
||||
return
|
||||
m.mut.Lock()
|
||||
|
||||
if flags := f.FileLocalFlags(); flags == 0 {
|
||||
// Remove regular files from the zero-flags bucket
|
||||
m.removeFileLocked(dev, 0, f)
|
||||
} else {
|
||||
// Remove from flag specific buckets.
|
||||
eachFlagBit(flags, func(flag uint32) {
|
||||
m.removeFileLocked(dev, flag, f)
|
||||
})
|
||||
}
|
||||
|
||||
m.mut.Lock()
|
||||
cp := m.countsPtr(dev)
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
func (m *metadataTracker) removeFileLocked(dev protocol.DeviceID, flags uint32, f FileIntf) {
|
||||
cp := m.countsPtr(dev, f.FileLocalFlags())
|
||||
|
||||
switch {
|
||||
case f.IsDeleted():
|
||||
@@ -153,14 +179,19 @@ func (m *metadataTracker) removeFile(dev protocol.DeviceID, f FileIntf) {
|
||||
cp.Symlinks = 0
|
||||
m.counts.Created = 0
|
||||
}
|
||||
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
// resetAll resets all metadata for the given device
|
||||
func (m *metadataTracker) resetAll(dev protocol.DeviceID) {
|
||||
m.mut.Lock()
|
||||
*m.countsPtr(dev) = Counts{DeviceID: dev[:]}
|
||||
for i, c := range m.counts.Counts {
|
||||
if bytes.Equal(c.DeviceID, dev[:]) {
|
||||
m.counts.Counts[i] = Counts{
|
||||
DeviceID: c.DeviceID,
|
||||
LocalFlags: c.LocalFlags,
|
||||
}
|
||||
}
|
||||
}
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
@@ -169,23 +200,30 @@ func (m *metadataTracker) resetAll(dev protocol.DeviceID) {
|
||||
func (m *metadataTracker) resetCounts(dev protocol.DeviceID) {
|
||||
m.mut.Lock()
|
||||
|
||||
c := m.countsPtr(dev)
|
||||
c.Bytes = 0
|
||||
c.Deleted = 0
|
||||
c.Directories = 0
|
||||
c.Files = 0
|
||||
c.Symlinks = 0
|
||||
// c.Sequence deliberately untouched
|
||||
for i, c := range m.counts.Counts {
|
||||
if bytes.Equal(c.DeviceID, dev[:]) {
|
||||
m.counts.Counts[i] = Counts{
|
||||
DeviceID: c.DeviceID,
|
||||
Sequence: c.Sequence,
|
||||
LocalFlags: c.LocalFlags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
// Counts returns the counts for the given device ID
|
||||
func (m *metadataTracker) Counts(dev protocol.DeviceID) Counts {
|
||||
// Counts returns the counts for the given device ID and flag. `flag` should
|
||||
// be zero or have exactly one bit set.
|
||||
func (m *metadataTracker) Counts(dev protocol.DeviceID, flag uint32) Counts {
|
||||
if bits.OnesCount32(flag) > 1 {
|
||||
panic("incorrect usage: set at most one bit in flag")
|
||||
}
|
||||
|
||||
m.mut.RLock()
|
||||
defer m.mut.RUnlock()
|
||||
|
||||
idx, ok := m.indexes[dev]
|
||||
idx, ok := m.indexes[metaKey{dev, flag}]
|
||||
if !ok {
|
||||
return Counts{}
|
||||
}
|
||||
@@ -198,7 +236,7 @@ func (m *metadataTracker) nextSeq(dev protocol.DeviceID) int64 {
|
||||
m.mut.Lock()
|
||||
defer m.mut.Unlock()
|
||||
|
||||
c := m.countsPtr(dev)
|
||||
c := m.countsPtr(dev, 0)
|
||||
c.Sequence++
|
||||
return c.Sequence
|
||||
}
|
||||
@@ -206,21 +244,26 @@ func (m *metadataTracker) nextSeq(dev protocol.DeviceID) int64 {
|
||||
// devices returns the list of devices tracked, excluding the local device
|
||||
// (which we don't know the ID of)
|
||||
func (m *metadataTracker) devices() []protocol.DeviceID {
|
||||
devs := make([]protocol.DeviceID, 0, len(m.counts.Counts))
|
||||
devs := make(map[protocol.DeviceID]struct{}, len(m.counts.Counts))
|
||||
|
||||
m.mut.RLock()
|
||||
for _, dev := range m.counts.Counts {
|
||||
if dev.Sequence > 0 {
|
||||
id := protocol.DeviceIDFromBytes(dev.DeviceID)
|
||||
if id == globalDeviceID || id == protocol.LocalDeviceID {
|
||||
if id == protocol.GlobalDeviceID || id == protocol.LocalDeviceID {
|
||||
continue
|
||||
}
|
||||
devs = append(devs, id)
|
||||
devs[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
m.mut.RUnlock()
|
||||
|
||||
return devs
|
||||
devList := make([]protocol.DeviceID, 0, len(devs))
|
||||
for dev := range devs {
|
||||
devList = append(devList, dev)
|
||||
}
|
||||
|
||||
return devList
|
||||
}
|
||||
|
||||
func (m *metadataTracker) Created() time.Time {
|
||||
@@ -234,3 +277,19 @@ func (m *metadataTracker) SetCreated() {
|
||||
m.counts.Created = time.Now().UnixNano()
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
// eachFlagBit calls the function once for every bit that is set in flags
|
||||
func eachFlagBit(flags uint32, fn func(flag uint32)) {
|
||||
// Test each bit from the right, as long as there are bits left in the
|
||||
// flag set. Clear any bits found and stop testing as soon as there are
|
||||
// no more bits set.
|
||||
|
||||
currentBit := uint32(1 << 0)
|
||||
for flags != 0 {
|
||||
if flags¤tBit != 0 {
|
||||
fn(currentBit)
|
||||
flags &^= currentBit
|
||||
}
|
||||
currentBit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
82
lib/db/meta_test.go
Normal file
82
lib/db/meta_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (C) 2018 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
func TestEachFlagBit(t *testing.T) {
|
||||
cases := []struct {
|
||||
flags uint32
|
||||
iterations int
|
||||
}{
|
||||
{0, 0},
|
||||
{1<<0 | 1<<3, 2},
|
||||
{1 << 0, 1},
|
||||
{1 << 31, 1},
|
||||
{1<<10 | 1<<20 | 1<<30, 3},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
var flags uint32
|
||||
iterations := 0
|
||||
|
||||
eachFlagBit(tc.flags, func(f uint32) {
|
||||
iterations++
|
||||
flags |= f
|
||||
if bits.OnesCount32(f) != 1 {
|
||||
t.Error("expected exactly one bit to be set in every call")
|
||||
}
|
||||
})
|
||||
|
||||
if flags != tc.flags {
|
||||
t.Errorf("expected 0x%x flags, got 0x%x", tc.flags, flags)
|
||||
}
|
||||
if iterations != tc.iterations {
|
||||
t.Errorf("expected %d iterations, got %d", tc.iterations, iterations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaDevices(t *testing.T) {
|
||||
d1 := protocol.DeviceID{1}
|
||||
d2 := protocol.DeviceID{2}
|
||||
meta := newMetadataTracker()
|
||||
|
||||
meta.addFile(d1, protocol.FileInfo{Sequence: 1})
|
||||
meta.addFile(d1, protocol.FileInfo{Sequence: 2, LocalFlags: 1})
|
||||
meta.addFile(d2, protocol.FileInfo{Sequence: 1})
|
||||
meta.addFile(d2, protocol.FileInfo{Sequence: 2, LocalFlags: 2})
|
||||
meta.addFile(protocol.LocalDeviceID, protocol.FileInfo{Sequence: 1})
|
||||
|
||||
// There are five device/flags combos
|
||||
if l := len(meta.counts.Counts); l < 5 {
|
||||
t.Error("expected at least five buckets, not", l)
|
||||
}
|
||||
|
||||
// There are only two non-local devices
|
||||
devs := meta.devices()
|
||||
if l := len(devs); l != 2 {
|
||||
t.Fatal("expected two devices, not", l)
|
||||
}
|
||||
|
||||
// Check that we got the two devices we expect
|
||||
sort.Slice(devs, func(a, b int) bool {
|
||||
return devs[a].Compare(devs[b]) == -1
|
||||
})
|
||||
if devs[0] != d1 {
|
||||
t.Error("first device should be d1")
|
||||
}
|
||||
if devs[1] != d2 {
|
||||
t.Error("second device should be d2")
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,12 @@ type FileSet struct {
|
||||
type FileIntf interface {
|
||||
FileSize() int64
|
||||
FileName() string
|
||||
FileLocalFlags() uint32
|
||||
IsDeleted() bool
|
||||
IsInvalid() bool
|
||||
IsIgnored() bool
|
||||
IsUnsupported() bool
|
||||
MustRescan() bool
|
||||
IsDirectory() bool
|
||||
IsSymlink() bool
|
||||
HasPermissionBits() bool
|
||||
@@ -248,15 +252,23 @@ func (s *FileSet) Availability(file string) []protocol.DeviceID {
|
||||
}
|
||||
|
||||
func (s *FileSet) Sequence(device protocol.DeviceID) int64 {
|
||||
return s.meta.Counts(device).Sequence
|
||||
return s.meta.Counts(device, 0).Sequence
|
||||
}
|
||||
|
||||
func (s *FileSet) LocalSize() Counts {
|
||||
return s.meta.Counts(protocol.LocalDeviceID)
|
||||
local := s.meta.Counts(protocol.LocalDeviceID, 0)
|
||||
recvOnlyChanged := s.meta.Counts(protocol.LocalDeviceID, protocol.FlagLocalReceiveOnly)
|
||||
return local.Add(recvOnlyChanged)
|
||||
}
|
||||
|
||||
func (s *FileSet) ReceiveOnlyChangedSize() Counts {
|
||||
return s.meta.Counts(protocol.LocalDeviceID, protocol.FlagLocalReceiveOnly)
|
||||
}
|
||||
|
||||
func (s *FileSet) GlobalSize() Counts {
|
||||
return s.meta.Counts(globalDeviceID)
|
||||
global := s.meta.Counts(protocol.GlobalDeviceID, 0)
|
||||
recvOnlyChanged := s.meta.Counts(protocol.GlobalDeviceID, protocol.FlagLocalReceiveOnly)
|
||||
return global.Add(recvOnlyChanged)
|
||||
}
|
||||
|
||||
func (s *FileSet) IndexID(device protocol.DeviceID) protocol.IndexID {
|
||||
|
||||
@@ -906,7 +906,7 @@ func TestWithHaveSequence(t *testing.T) {
|
||||
|
||||
i := 2
|
||||
s.WithHaveSequence(int64(i), func(fi db.FileIntf) bool {
|
||||
if f := fi.(protocol.FileInfo); !f.IsEquivalent(localHave[i-1], false, false) {
|
||||
if f := fi.(protocol.FileInfo); !f.IsEquivalent(localHave[i-1]) {
|
||||
t.Fatalf("Got %v\nExpected %v", f, localHave[i-1])
|
||||
}
|
||||
i++
|
||||
@@ -917,7 +917,7 @@ func TestWithHaveSequence(t *testing.T) {
|
||||
func TestIssue4925(t *testing.T) {
|
||||
ldb := db.OpenMemory()
|
||||
|
||||
folder := "test)"
|
||||
folder := "test"
|
||||
s := db.NewFileSet(folder, fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
|
||||
|
||||
localHave := fileList{
|
||||
@@ -955,7 +955,7 @@ func TestMoveGlobalBack(t *testing.T) {
|
||||
|
||||
if need := needList(s, protocol.LocalDeviceID); len(need) != 1 {
|
||||
t.Error("Expected 1 local need, got", need)
|
||||
} else if !need[0].IsEquivalent(remote0Have[0], false, false) {
|
||||
} else if !need[0].IsEquivalent(remote0Have[0]) {
|
||||
t.Errorf("Local need incorrect;\n A: %v !=\n E: %v", need[0], remote0Have[0])
|
||||
}
|
||||
|
||||
@@ -981,7 +981,7 @@ func TestMoveGlobalBack(t *testing.T) {
|
||||
|
||||
if need := needList(s, remoteDevice0); len(need) != 1 {
|
||||
t.Error("Expected 1 need for remote 0, got", need)
|
||||
} else if !need[0].IsEquivalent(localHave[0], false, false) {
|
||||
} else if !need[0].IsEquivalent(localHave[0]) {
|
||||
t.Errorf("Need for remote 0 incorrect;\n A: %v !=\n E: %v", need[0], localHave[0])
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,7 @@ func TestIssue5007(t *testing.T) {
|
||||
|
||||
if need := needList(s, protocol.LocalDeviceID); len(need) != 1 {
|
||||
t.Fatal("Expected 1 local need, got", need)
|
||||
} else if !need[0].IsEquivalent(fs[0], false, false) {
|
||||
} else if !need[0].IsEquivalent(fs[0]) {
|
||||
t.Fatalf("Local need incorrect;\n A: %v !=\n E: %v", need[0], fs[0])
|
||||
}
|
||||
|
||||
@@ -1052,7 +1052,7 @@ func TestNeedDeleted(t *testing.T) {
|
||||
|
||||
if need := needList(s, protocol.LocalDeviceID); len(need) != 1 {
|
||||
t.Fatal("Expected 1 local need, got", need)
|
||||
} else if !need[0].IsEquivalent(fs[0], false, false) {
|
||||
} else if !need[0].IsEquivalent(fs[0]) {
|
||||
t.Fatalf("Local need incorrect;\n A: %v !=\n E: %v", need[0], fs[0])
|
||||
}
|
||||
|
||||
@@ -1065,6 +1065,110 @@ func TestNeedDeleted(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReceiveOnlyAccounting(t *testing.T) {
|
||||
ldb := db.OpenMemory()
|
||||
|
||||
folder := "test"
|
||||
s := db.NewFileSet(folder, fs.NewFilesystem(fs.FilesystemTypeBasic, "."), ldb)
|
||||
|
||||
local := protocol.DeviceID{1}
|
||||
remote := protocol.DeviceID{2}
|
||||
|
||||
// Three files that have been created by the remote device
|
||||
|
||||
version := protocol.Vector{Counters: []protocol.Counter{{ID: remote.Short(), Value: 1}}}
|
||||
files := fileList{
|
||||
protocol.FileInfo{Name: "f1", Size: 10, Sequence: 1, Version: version},
|
||||
protocol.FileInfo{Name: "f2", Size: 10, Sequence: 1, Version: version},
|
||||
protocol.FileInfo{Name: "f3", Size: 10, Sequence: 1, Version: version},
|
||||
}
|
||||
|
||||
// We have synced them locally
|
||||
|
||||
replace(s, protocol.LocalDeviceID, files)
|
||||
replace(s, remote, files)
|
||||
|
||||
if n := s.LocalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 local files initially, not", n)
|
||||
}
|
||||
if n := s.LocalSize().Bytes; n != 30 {
|
||||
t.Fatal("expected 30 local bytes initially, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 global files initially, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Bytes; n != 30 {
|
||||
t.Fatal("expected 30 global bytes initially, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Files; n != 0 {
|
||||
t.Fatal("expected 0 receive only changed files initially, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Bytes; n != 0 {
|
||||
t.Fatal("expected 0 receive only changed bytes initially, not", n)
|
||||
}
|
||||
|
||||
// Detected a local change in a receive only folder
|
||||
|
||||
changed := files[0]
|
||||
changed.Version = changed.Version.Update(local.Short())
|
||||
changed.Size = 100
|
||||
changed.ModifiedBy = local.Short()
|
||||
changed.LocalFlags = protocol.FlagLocalReceiveOnly
|
||||
s.Update(protocol.LocalDeviceID, []protocol.FileInfo{changed})
|
||||
|
||||
// Check that we see the files
|
||||
|
||||
if n := s.LocalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 local files after local change, not", n)
|
||||
}
|
||||
if n := s.LocalSize().Bytes; n != 120 {
|
||||
t.Fatal("expected 120 local bytes after local change, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 global files after local change, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Bytes; n != 120 {
|
||||
t.Fatal("expected 120 global bytes after local change, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Files; n != 1 {
|
||||
t.Fatal("expected 1 receive only changed file after local change, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Bytes; n != 100 {
|
||||
t.Fatal("expected 100 receive only changed btyes after local change, not", n)
|
||||
}
|
||||
|
||||
// Fake a revert. That's a two step process, first converting our
|
||||
// changed file into a less preferred variant, then pulling down the old
|
||||
// version.
|
||||
|
||||
changed.Version = protocol.Vector{}
|
||||
changed.LocalFlags &^= protocol.FlagLocalReceiveOnly
|
||||
s.Update(protocol.LocalDeviceID, []protocol.FileInfo{changed})
|
||||
|
||||
s.Update(protocol.LocalDeviceID, []protocol.FileInfo{files[0]})
|
||||
|
||||
// Check that we see the files, same data as initially
|
||||
|
||||
if n := s.LocalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 local files after revert, not", n)
|
||||
}
|
||||
if n := s.LocalSize().Bytes; n != 30 {
|
||||
t.Fatal("expected 30 local bytes after revert, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Files; n != 3 {
|
||||
t.Fatal("expected 3 global files after revert, not", n)
|
||||
}
|
||||
if n := s.GlobalSize().Bytes; n != 30 {
|
||||
t.Fatal("expected 30 global bytes after revert, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Files; n != 0 {
|
||||
t.Fatal("expected 0 receive only changed files after revert, not", n)
|
||||
}
|
||||
if n := s.ReceiveOnlyChangedSize().Bytes; n != 0 {
|
||||
t.Fatal("expected 0 receive only changed bytes after revert, not", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNeedAfterUnignore(t *testing.T) {
|
||||
ldb := db.OpenMemory()
|
||||
|
||||
@@ -1090,7 +1194,7 @@ func TestNeedAfterUnignore(t *testing.T) {
|
||||
|
||||
if need := needList(s, protocol.LocalDeviceID); len(need) != 1 {
|
||||
t.Fatal("Expected one local need, got", need)
|
||||
} else if !need[0].IsEquivalent(remote, false, false) {
|
||||
} else if !need[0].IsEquivalent(remote) {
|
||||
t.Fatalf("Got %v, expected %v", need[0], remote)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ func (f FileInfoTruncated) IsInvalid() bool {
|
||||
return f.RawInvalid || f.LocalFlags&protocol.LocalInvalidFlags != 0
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) IsUnsupported() bool {
|
||||
return f.LocalFlags&protocol.FlagLocalUnsupported != 0
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) IsIgnored() bool {
|
||||
return f.LocalFlags&protocol.FlagLocalIgnored != 0
|
||||
}
|
||||
@@ -48,6 +52,10 @@ func (f FileInfoTruncated) MustRescan() bool {
|
||||
return f.LocalFlags&protocol.FlagLocalMustRescan != 0
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) IsReceiveOnlyChanged() bool {
|
||||
return f.LocalFlags&protocol.FlagLocalReceiveOnly != 0
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) IsDirectory() bool {
|
||||
return f.Type == protocol.FileInfoTypeDirectory
|
||||
}
|
||||
@@ -86,6 +94,10 @@ func (f FileInfoTruncated) FileName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) FileLocalFlags() uint32 {
|
||||
return f.LocalFlags
|
||||
}
|
||||
|
||||
func (f FileInfoTruncated) ModTime() time.Time {
|
||||
return time.Unix(f.ModifiedS, int64(f.ModifiedNs))
|
||||
}
|
||||
@@ -110,3 +122,16 @@ func (f FileInfoTruncated) ConvertToIgnoredFileInfo(by protocol.ShortID) protoco
|
||||
LocalFlags: protocol.FlagLocalIgnored,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Counts) Add(other Counts) Counts {
|
||||
return Counts{
|
||||
Files: c.Files + other.Files,
|
||||
Directories: c.Directories + other.Directories,
|
||||
Symlinks: c.Symlinks + other.Symlinks,
|
||||
Deleted: c.Deleted + other.Deleted,
|
||||
Bytes: c.Bytes + other.Bytes,
|
||||
Sequence: c.Sequence + other.Sequence,
|
||||
DeviceID: protocol.EmptyDeviceID[:],
|
||||
LocalFlags: c.LocalFlags | other.LocalFlags,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ type Counts struct {
|
||||
Bytes int64 `protobuf:"varint,5,opt,name=bytes,proto3" json:"bytes,omitempty"`
|
||||
Sequence int64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"`
|
||||
DeviceID []byte `protobuf:"bytes,17,opt,name=deviceID,proto3" json:"deviceID,omitempty"`
|
||||
LocalFlags uint32 `protobuf:"varint,18,opt,name=localFlags,proto3" json:"localFlags,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Counts) Reset() { *m = Counts{} }
|
||||
@@ -357,6 +358,13 @@ func (m *Counts) MarshalTo(dAtA []byte) (int, error) {
|
||||
i = encodeVarintStructs(dAtA, i, uint64(len(m.DeviceID)))
|
||||
i += copy(dAtA[i:], m.DeviceID)
|
||||
}
|
||||
if m.LocalFlags != 0 {
|
||||
dAtA[i] = 0x90
|
||||
i++
|
||||
dAtA[i] = 0x1
|
||||
i++
|
||||
i = encodeVarintStructs(dAtA, i, uint64(m.LocalFlags))
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -526,6 +534,9 @@ func (m *Counts) ProtoSize() (n int) {
|
||||
if l > 0 {
|
||||
n += 2 + l + sovStructs(uint64(l))
|
||||
}
|
||||
if m.LocalFlags != 0 {
|
||||
n += 2 + sovStructs(uint64(m.LocalFlags))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1312,6 +1323,25 @@ func (m *Counts) Unmarshal(dAtA []byte) error {
|
||||
m.DeviceID = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 18:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LocalFlags", wireType)
|
||||
}
|
||||
m.LocalFlags = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowStructs
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.LocalFlags |= (uint32(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipStructs(dAtA[iNdEx:])
|
||||
@@ -1541,47 +1571,47 @@ var (
|
||||
func init() { proto.RegisterFile("structs.proto", fileDescriptorStructs) }
|
||||
|
||||
var fileDescriptorStructs = []byte{
|
||||
// 663 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcd, 0x6a, 0xdb, 0x40,
|
||||
0x10, 0xb6, 0x62, 0xf9, 0x6f, 0x6c, 0xa7, 0xc9, 0x12, 0x82, 0x30, 0xd4, 0x16, 0x86, 0x82, 0x28,
|
||||
0xd4, 0x6e, 0x13, 0x7a, 0x69, 0x6f, 0x6a, 0x08, 0x18, 0x4a, 0x5b, 0xd6, 0x21, 0xa7, 0x82, 0xd1,
|
||||
0xcf, 0xda, 0x59, 0x22, 0x6b, 0x1d, 0xed, 0x3a, 0x41, 0x79, 0x92, 0x1e, 0xf3, 0x30, 0x3d, 0xe4,
|
||||
0xd8, 0x73, 0x0f, 0x26, 0x75, 0x2f, 0x7d, 0x8c, 0xb2, 0xbb, 0x92, 0xa2, 0xf6, 0xd4, 0xde, 0xe6,
|
||||
0x9b, 0x9f, 0x9d, 0x6f, 0x66, 0xbe, 0x85, 0x2e, 0x17, 0xc9, 0x3a, 0x10, 0x7c, 0xb4, 0x4a, 0x98,
|
||||
0x60, 0x68, 0x27, 0xf4, 0x7b, 0x2f, 0x16, 0x54, 0x5c, 0xac, 0xfd, 0x51, 0xc0, 0x96, 0xe3, 0x05,
|
||||
0x5b, 0xb0, 0xb1, 0x0a, 0xf9, 0xeb, 0xb9, 0x42, 0x0a, 0x28, 0x4b, 0x97, 0xf4, 0x5e, 0x97, 0xd2,
|
||||
0x79, 0x1a, 0x07, 0xe2, 0x82, 0xc6, 0x8b, 0x92, 0x15, 0x51, 0x5f, 0xbf, 0x10, 0xb0, 0x68, 0xec,
|
||||
0x93, 0x95, 0x2e, 0x1b, 0x5e, 0x41, 0xfb, 0x94, 0x46, 0xe4, 0x9c, 0x24, 0x9c, 0xb2, 0x18, 0xbd,
|
||||
0x84, 0xc6, 0xb5, 0x36, 0x2d, 0xc3, 0x36, 0x9c, 0xf6, 0xd1, 0xde, 0x28, 0x2f, 0x1a, 0x9d, 0x93,
|
||||
0x40, 0xb0, 0xc4, 0x35, 0xef, 0x37, 0x83, 0x0a, 0xce, 0xd3, 0xd0, 0x21, 0xd4, 0x43, 0x72, 0x4d,
|
||||
0x03, 0x62, 0xed, 0xd8, 0x86, 0xd3, 0xc1, 0x19, 0x42, 0x16, 0x34, 0x68, 0x7c, 0xed, 0x45, 0x34,
|
||||
0xb4, 0xaa, 0xb6, 0xe1, 0x34, 0x71, 0x0e, 0x87, 0xa7, 0xd0, 0xce, 0xda, 0xbd, 0xa7, 0x5c, 0xa0,
|
||||
0x57, 0xd0, 0xcc, 0xde, 0xe2, 0x96, 0x61, 0x57, 0x9d, 0xf6, 0xd1, 0x93, 0x51, 0xe8, 0x8f, 0x4a,
|
||||
0xac, 0xb2, 0x96, 0x45, 0xda, 0x1b, 0xf3, 0xcb, 0xdd, 0xa0, 0x32, 0x7c, 0x30, 0x61, 0x5f, 0x66,
|
||||
0x4d, 0xe2, 0x39, 0x3b, 0x4b, 0xd6, 0x71, 0xe0, 0x09, 0x12, 0x22, 0x04, 0x66, 0xec, 0x2d, 0x89,
|
||||
0xa2, 0xdf, 0xc2, 0xca, 0x46, 0xcf, 0xc1, 0x14, 0xe9, 0x4a, 0x33, 0xdc, 0x3d, 0x3a, 0x7c, 0x1c,
|
||||
0xa9, 0x28, 0x4f, 0x57, 0x04, 0xab, 0x1c, 0x59, 0xcf, 0xe9, 0x2d, 0x51, 0xa4, 0xab, 0x58, 0xd9,
|
||||
0xc8, 0x86, 0xf6, 0x8a, 0x24, 0x4b, 0xca, 0x35, 0x4b, 0xd3, 0x36, 0x9c, 0x2e, 0x2e, 0xbb, 0xd0,
|
||||
0x53, 0x80, 0x25, 0x0b, 0xe9, 0x9c, 0x92, 0x70, 0xc6, 0xad, 0x9a, 0xaa, 0x6d, 0xe5, 0x9e, 0xa9,
|
||||
0x5c, 0x46, 0x48, 0x22, 0x22, 0x48, 0x68, 0xd5, 0xf5, 0x32, 0x32, 0x88, 0x9c, 0xc7, 0x35, 0x35,
|
||||
0x64, 0xc4, 0xdd, 0xdd, 0x6e, 0x06, 0x80, 0xbd, 0x9b, 0x89, 0xf6, 0x16, 0x6b, 0x43, 0xcf, 0x60,
|
||||
0x37, 0x66, 0xb3, 0x32, 0x8f, 0xa6, 0x7a, 0xaa, 0x1b, 0xb3, 0x4f, 0x25, 0x26, 0xa5, 0x0b, 0xb6,
|
||||
0xfe, 0xed, 0x82, 0x3d, 0x68, 0x72, 0x72, 0xb5, 0x26, 0x71, 0x40, 0x2c, 0x50, 0xcc, 0x0b, 0x8c,
|
||||
0x06, 0xd0, 0x2e, 0xe6, 0x8a, 0xb9, 0xd5, 0xb6, 0x0d, 0xa7, 0x86, 0x8b, 0x51, 0x3f, 0x70, 0xf4,
|
||||
0xb9, 0x94, 0xe0, 0xa7, 0x56, 0xc7, 0x36, 0x1c, 0xd3, 0x7d, 0x2b, 0x1b, 0x7c, 0xdf, 0x0c, 0x8e,
|
||||
0xff, 0x43, 0x93, 0xa3, 0xe9, 0x05, 0x4b, 0xc4, 0xe4, 0xe4, 0xf1, 0x75, 0x37, 0x45, 0x63, 0x00,
|
||||
0x3f, 0x62, 0xc1, 0xe5, 0x4c, 0x9d, 0xa4, 0x2b, 0xbb, 0xbb, 0x7b, 0xdb, 0xcd, 0xa0, 0x83, 0xbd,
|
||||
0x1b, 0x57, 0x06, 0xa6, 0xf4, 0x96, 0xe0, 0x96, 0x9f, 0x9b, 0x72, 0x49, 0x3c, 0x5d, 0x46, 0x34,
|
||||
0xbe, 0x9c, 0x09, 0x2f, 0x59, 0x10, 0x61, 0xed, 0x2b, 0x1d, 0x74, 0x33, 0xef, 0x99, 0x72, 0xca,
|
||||
0x83, 0x46, 0x2c, 0xf0, 0xa2, 0xd9, 0x3c, 0xf2, 0x16, 0xdc, 0xfa, 0xd5, 0x50, 0x17, 0x05, 0xe5,
|
||||
0x3b, 0x95, 0xae, 0x4c, 0x62, 0x5f, 0x0d, 0xa8, 0xbf, 0x63, 0xeb, 0x58, 0x70, 0x74, 0x00, 0xb5,
|
||||
0x39, 0x8d, 0x08, 0x57, 0xc2, 0xaa, 0x61, 0x0d, 0xe4, 0x43, 0x21, 0x4d, 0xd4, 0x5a, 0x29, 0xe1,
|
||||
0x4a, 0x60, 0x35, 0x5c, 0x76, 0xa9, 0xed, 0xea, 0xde, 0x5c, 0x69, 0xaa, 0x86, 0x0b, 0x5c, 0x96,
|
||||
0x85, 0xa9, 0x42, 0x85, 0x2c, 0x0e, 0xa0, 0xe6, 0xa7, 0x82, 0xe4, 0x52, 0xd2, 0xe0, 0x8f, 0x4b,
|
||||
0xd5, 0xff, 0xba, 0x54, 0x0f, 0x9a, 0xfa, 0xe7, 0x4d, 0x4e, 0xd4, 0xcc, 0x1d, 0x5c, 0xe0, 0xe1,
|
||||
0x47, 0x68, 0xe9, 0x29, 0xa6, 0x44, 0x20, 0x07, 0xea, 0x81, 0x02, 0xd9, 0x6f, 0x03, 0xf9, 0xdb,
|
||||
0x74, 0x38, 0x53, 0x46, 0x16, 0x97, 0xf4, 0x82, 0x84, 0xc8, 0x5f, 0xa5, 0x06, 0xab, 0xe2, 0x1c,
|
||||
0xba, 0x07, 0xf7, 0x3f, 0xfa, 0x95, 0xfb, 0x6d, 0xdf, 0xf8, 0xb6, 0xed, 0x1b, 0x0f, 0xdb, 0x7e,
|
||||
0xe5, 0xee, 0x67, 0xdf, 0xf0, 0xeb, 0xea, 0x96, 0xc7, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x9a,
|
||||
0x4b, 0x16, 0x44, 0xcd, 0x04, 0x00, 0x00,
|
||||
// 671 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x4d, 0x6b, 0xdb, 0x4c,
|
||||
0x10, 0xb6, 0x62, 0xf9, 0x6b, 0x6c, 0xe7, 0x4d, 0x96, 0x10, 0x84, 0xe1, 0xb5, 0x85, 0xa1, 0x20,
|
||||
0x0a, 0xb5, 0xdb, 0x84, 0x5e, 0xda, 0x9b, 0x1a, 0x02, 0x86, 0xd2, 0x96, 0x75, 0xc8, 0xa9, 0x60,
|
||||
0xf4, 0xb1, 0x76, 0x96, 0xc8, 0x5a, 0x47, 0xbb, 0x4e, 0x50, 0x7e, 0x49, 0x8f, 0xf9, 0x39, 0x39,
|
||||
0xf6, 0xdc, 0x83, 0x49, 0xdd, 0x1e, 0xfa, 0x33, 0xca, 0xee, 0x4a, 0x8a, 0x9a, 0x53, 0x7b, 0x9b,
|
||||
0x67, 0x3e, 0x76, 0x9e, 0x99, 0x79, 0x16, 0xba, 0x5c, 0x24, 0xeb, 0x40, 0xf0, 0xd1, 0x2a, 0x61,
|
||||
0x82, 0xa1, 0x9d, 0xd0, 0xef, 0xbd, 0x58, 0x50, 0x71, 0xb1, 0xf6, 0x47, 0x01, 0x5b, 0x8e, 0x17,
|
||||
0x6c, 0xc1, 0xc6, 0x2a, 0xe4, 0xaf, 0xe7, 0x0a, 0x29, 0xa0, 0x2c, 0x5d, 0xd2, 0x7b, 0x5d, 0x4a,
|
||||
0xe7, 0x69, 0x1c, 0x88, 0x0b, 0x1a, 0x2f, 0x4a, 0x56, 0x44, 0x7d, 0xfd, 0x42, 0xc0, 0xa2, 0xb1,
|
||||
0x4f, 0x56, 0xba, 0x6c, 0x78, 0x05, 0xed, 0x53, 0x1a, 0x91, 0x73, 0x92, 0x70, 0xca, 0x62, 0xf4,
|
||||
0x12, 0x1a, 0xd7, 0xda, 0xb4, 0x0c, 0xdb, 0x70, 0xda, 0x47, 0x7b, 0xa3, 0xbc, 0x68, 0x74, 0x4e,
|
||||
0x02, 0xc1, 0x12, 0xd7, 0xbc, 0xdf, 0x0c, 0x2a, 0x38, 0x4f, 0x43, 0x87, 0x50, 0x0f, 0xc9, 0x35,
|
||||
0x0d, 0x88, 0xb5, 0x63, 0x1b, 0x4e, 0x07, 0x67, 0x08, 0x59, 0xd0, 0xa0, 0xf1, 0xb5, 0x17, 0xd1,
|
||||
0xd0, 0xaa, 0xda, 0x86, 0xd3, 0xc4, 0x39, 0x1c, 0x9e, 0x42, 0x3b, 0x6b, 0xf7, 0x9e, 0x72, 0x81,
|
||||
0x5e, 0x41, 0x33, 0x7b, 0x8b, 0x5b, 0x86, 0x5d, 0x75, 0xda, 0x47, 0xff, 0x8d, 0x42, 0x7f, 0x54,
|
||||
0x62, 0x95, 0xb5, 0x2c, 0xd2, 0xde, 0x98, 0x5f, 0xee, 0x06, 0x95, 0xe1, 0x83, 0x09, 0xfb, 0x32,
|
||||
0x6b, 0x12, 0xcf, 0xd9, 0x59, 0xb2, 0x8e, 0x03, 0x4f, 0x90, 0x10, 0x21, 0x30, 0x63, 0x6f, 0x49,
|
||||
0x14, 0xfd, 0x16, 0x56, 0x36, 0x7a, 0x0e, 0xa6, 0x48, 0x57, 0x9a, 0xe1, 0xee, 0xd1, 0xe1, 0xe3,
|
||||
0x48, 0x45, 0x79, 0xba, 0x22, 0x58, 0xe5, 0xc8, 0x7a, 0x4e, 0x6f, 0x89, 0x22, 0x5d, 0xc5, 0xca,
|
||||
0x46, 0x36, 0xb4, 0x57, 0x24, 0x59, 0x52, 0xae, 0x59, 0x9a, 0xb6, 0xe1, 0x74, 0x71, 0xd9, 0x85,
|
||||
0xfe, 0x07, 0x58, 0xb2, 0x90, 0xce, 0x29, 0x09, 0x67, 0xdc, 0xaa, 0xa9, 0xda, 0x56, 0xee, 0x99,
|
||||
0xca, 0x65, 0x84, 0x24, 0x22, 0x82, 0x84, 0x56, 0x5d, 0x2f, 0x23, 0x83, 0xc8, 0x79, 0x5c, 0x53,
|
||||
0x43, 0x46, 0xdc, 0xdd, 0xed, 0x66, 0x00, 0xd8, 0xbb, 0x99, 0x68, 0x6f, 0xb1, 0x36, 0xf4, 0x0c,
|
||||
0x76, 0x63, 0x36, 0x2b, 0xf3, 0x68, 0xaa, 0xa7, 0xba, 0x31, 0xfb, 0x54, 0x62, 0x52, 0xba, 0x60,
|
||||
0xeb, 0xef, 0x2e, 0xd8, 0x83, 0x26, 0x27, 0x57, 0x6b, 0x12, 0x07, 0xc4, 0x02, 0xc5, 0xbc, 0xc0,
|
||||
0x68, 0x00, 0xed, 0x62, 0xae, 0x98, 0x5b, 0x6d, 0xdb, 0x70, 0x6a, 0xb8, 0x18, 0xf5, 0x03, 0x47,
|
||||
0x9f, 0x4b, 0x09, 0x7e, 0x6a, 0x75, 0x6c, 0xc3, 0x31, 0xdd, 0xb7, 0xb2, 0xc1, 0xb7, 0xcd, 0xe0,
|
||||
0xf8, 0x1f, 0x34, 0x39, 0x9a, 0x5e, 0xb0, 0x44, 0x4c, 0x4e, 0x1e, 0x5f, 0x77, 0x53, 0x34, 0x06,
|
||||
0xf0, 0x23, 0x16, 0x5c, 0xce, 0xd4, 0x49, 0xba, 0xb2, 0xbb, 0xbb, 0xb7, 0xdd, 0x0c, 0x3a, 0xd8,
|
||||
0xbb, 0x71, 0x65, 0x60, 0x4a, 0x6f, 0x09, 0x6e, 0xf9, 0xb9, 0x29, 0x97, 0xc4, 0xd3, 0x65, 0x44,
|
||||
0xe3, 0xcb, 0x99, 0xf0, 0x92, 0x05, 0x11, 0xd6, 0xbe, 0xd2, 0x41, 0x37, 0xf3, 0x9e, 0x29, 0xa7,
|
||||
0x3c, 0x68, 0xc4, 0x02, 0x2f, 0x9a, 0xcd, 0x23, 0x6f, 0xc1, 0xad, 0x5f, 0x0d, 0x75, 0x51, 0x50,
|
||||
0xbe, 0x53, 0xe9, 0xca, 0x24, 0xf6, 0xd3, 0x80, 0xfa, 0x3b, 0xb6, 0x8e, 0x05, 0x47, 0x07, 0x50,
|
||||
0x9b, 0xd3, 0x88, 0x70, 0x25, 0xac, 0x1a, 0xd6, 0x40, 0x3e, 0x14, 0xd2, 0x44, 0xad, 0x95, 0x12,
|
||||
0xae, 0x04, 0x56, 0xc3, 0x65, 0x97, 0xda, 0xae, 0xee, 0xcd, 0x95, 0xa6, 0x6a, 0xb8, 0xc0, 0x65,
|
||||
0x59, 0x98, 0x2a, 0x54, 0xc8, 0xe2, 0x00, 0x6a, 0x7e, 0x2a, 0x48, 0x2e, 0x25, 0x0d, 0xfe, 0xb8,
|
||||
0x54, 0xfd, 0xc9, 0xa5, 0x7a, 0xd0, 0xd4, 0x3f, 0x6f, 0x72, 0xa2, 0x66, 0xee, 0xe0, 0x02, 0xa3,
|
||||
0x3e, 0x94, 0x46, 0xb3, 0xd0, 0xd3, 0x61, 0x87, 0x1f, 0xa1, 0xa5, 0xa7, 0x9c, 0x12, 0x81, 0x1c,
|
||||
0xa8, 0x07, 0x0a, 0x64, 0xbf, 0x11, 0xe4, 0x6f, 0xd4, 0xe1, 0x4c, 0x39, 0x59, 0x5c, 0xd2, 0x0f,
|
||||
0x12, 0x22, 0x7f, 0x9d, 0x1a, 0xbc, 0x8a, 0x73, 0xe8, 0x1e, 0xdc, 0x7f, 0xef, 0x57, 0xee, 0xb7,
|
||||
0x7d, 0xe3, 0xeb, 0xb6, 0x6f, 0x3c, 0x6c, 0xfb, 0x95, 0xbb, 0x1f, 0x7d, 0xc3, 0xaf, 0xab, 0x5b,
|
||||
0x1f, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x4d, 0xd7, 0x14, 0xed, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -46,13 +46,14 @@ message FileInfoTruncated {
|
||||
// For each folder and device we keep one of these to track the current
|
||||
// counts and sequence. We also keep one for the global state of the folder.
|
||||
message Counts {
|
||||
int32 files = 1;
|
||||
int32 directories = 2;
|
||||
int32 symlinks = 3;
|
||||
int32 deleted = 4;
|
||||
int64 bytes = 5;
|
||||
int64 sequence = 6; // zero for the global state
|
||||
bytes deviceID = 17; // device ID for remote devices, or special values for local/global
|
||||
int32 files = 1;
|
||||
int32 directories = 2;
|
||||
int32 symlinks = 3;
|
||||
int32 deleted = 4;
|
||||
int64 bytes = 5;
|
||||
int64 sequence = 6; // zero for the global state
|
||||
bytes deviceID = 17; // device ID for remote devices, or special values for local/global
|
||||
uint32 localFlags = 18; // the local flag for this count bucket
|
||||
}
|
||||
|
||||
message CountsSet {
|
||||
|
||||
Reference in New Issue
Block a user