Browse Source

Merge pull request #2076 from calmh/ignoredelete

Optionally ignore remote deletes
Audrius Butkevicius 10 years ago
parent
commit
895d56ed04
3 changed files with 69 additions and 36 deletions
  1. 1 0
      internal/config/config.go
  2. 31 36
      internal/model/model.go
  3. 37 0
      internal/model/model_test.go

+ 1 - 0
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
 

+ 31 - 36
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() {

+ 37 - 0
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")
+	}
+}