From 12eab4a8bae17d71ced31868c24e875ae423715b Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 21 Jul 2015 13:14:33 +0200 Subject: [PATCH] Optionally ignore remote deletes (fixes #1254) --- internal/config/config.go | 1 + internal/model/model.go | 67 +++++++++++++++++------------------- internal/model/model_test.go | 37 ++++++++++++++++++++ 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 2cb89efe..953d9b67 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -79,6 +79,7 @@ type FolderConfiguration struct { Pullers int `xml:"pullers" json:"pullers"` // Defines how many blocks are fetched at the same time, possibly between separate copier routines. Hashers int `xml:"hashers" json:"hashers"` // Less than one sets the value to the number of cores. These are CPU bound due to hashing. Order PullOrder `xml:"order" json:"order"` + IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"` Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved diff --git a/internal/model/model.go b/internal/model/model.go index 89e04874..21e20c22 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -491,6 +491,7 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F } m.fmut.RLock() + cfg := m.folderCfgs[folder] files, ok := m.folderFiles[folder] runner := m.folderRunners[folder] m.fmut.RUnlock() @@ -505,24 +506,7 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F l.Fatalf("Index for nonexistant folder %q", folder) } - for i := 0; i < len(fs); { - if fs[i].Flags&^protocol.FlagsAll != 0 { - if debug { - l.Debugln("dropping update for file with unknown bits set", fs[i]) - } - fs[i] = fs[len(fs)-1] - fs = fs[:len(fs)-1] - } else if symlinkInvalid(folder, fs[i]) { - if debug { - l.Debugln("dropping update for unsupported symlink", fs[i]) - } - fs[i] = fs[len(fs)-1] - fs = fs[:len(fs)-1] - } else { - i++ - } - } - + fs = filterIndex(folder, fs, cfg.IgnoreDelete) files.Replace(deviceID, fs) events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{ @@ -552,6 +536,7 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot m.fmut.RLock() files := m.folderFiles[folder] + cfg := m.folderCfgs[folder] runner, ok := m.folderRunners[folder] m.fmut.RUnlock() @@ -559,24 +544,7 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot l.Fatalf("IndexUpdate for nonexistant folder %q", folder) } - for i := 0; i < len(fs); { - if fs[i].Flags&^protocol.FlagsAll != 0 { - if debug { - l.Debugln("dropping update for file with unknown bits set", fs[i]) - } - fs[i] = fs[len(fs)-1] - fs = fs[:len(fs)-1] - } else if symlinkInvalid(folder, fs[i]) { - if debug { - l.Debugln("dropping update for unsupported symlink", fs[i]) - } - fs[i] = fs[len(fs)-1] - fs = fs[:len(fs)-1] - } else { - i++ - } - } - + fs = filterIndex(folder, fs, cfg.IgnoreDelete) files.Update(deviceID, fs) events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{ @@ -1788,6 +1756,33 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool { return true } +func filterIndex(folder string, fs []protocol.FileInfo, dropDeletes bool) []protocol.FileInfo { + for i := 0; i < len(fs); { + if fs[i].Flags&^protocol.FlagsAll != 0 { + if debug { + l.Debugln("dropping update for file with unknown bits set", fs[i]) + } + fs[i] = fs[len(fs)-1] + fs = fs[:len(fs)-1] + } else if fs[i].IsDeleted() && dropDeletes { + if debug { + l.Debugln("dropping update for undesired delete", fs[i]) + } + fs[i] = fs[len(fs)-1] + fs = fs[:len(fs)-1] + } else if symlinkInvalid(folder, fs[i]) { + if debug { + l.Debugln("dropping update for unsupported symlink", fs[i]) + } + fs[i] = fs[len(fs)-1] + fs = fs[:len(fs)-1] + } else { + i++ + } + } + return fs +} + func symlinkInvalid(folder string, fi db.FileIntf) bool { if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() { symlinkWarning.Do(func() { diff --git a/internal/model/model_test.go b/internal/model/model_test.go index 1dc5bd96..117557ee 100644 --- a/internal/model/model_test.go +++ b/internal/model/model_test.go @@ -1192,3 +1192,40 @@ func benchmarkTree(b *testing.B, n1, n2 int) { } b.ReportAllocs() } + +func TestIgnoreDelete(t *testing.T) { + db, _ := leveldb.Open(storage.NewMemStorage(), nil) + m := NewModel(defaultConfig, protocol.LocalDeviceID, "device", "syncthing", "dev", db) + + // This folder should ignore external deletes + cfg := defaultFolderConfig + cfg.IgnoreDelete = true + + m.AddFolder(cfg) + m.ServeBackground() + m.StartFolderRW("default") + m.ScanFolder("default") + + // Get a currently existing file + f, ok := m.CurrentGlobalFile("default", "foo") + if !ok { + t.Fatal("foo should exist") + } + + // Mark it for deletion + f.Flags = protocol.FlagDeleted + f.Version = f.Version.Update(142) // arbitrary short remote ID + f.Blocks = nil + + // Send the index + m.Index(device1, "default", []protocol.FileInfo{f}, 0, nil) + + // Make sure we ignored it + f, ok = m.CurrentGlobalFile("default", "foo") + if !ok { + t.Fatal("foo should exist") + } + if f.IsDeleted() { + t.Fatal("foo should not be marked for deletion") + } +}