mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-02 22:50:18 +00:00
Optionally ignore remote deletes (fixes #1254)
This commit is contained in:
parent
6ecc9bf93a
commit
12eab4a8ba
@ -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.
|
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.
|
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"`
|
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
|
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||||
|
|
||||||
|
@ -491,6 +491,7 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.fmut.RLock()
|
m.fmut.RLock()
|
||||||
|
cfg := m.folderCfgs[folder]
|
||||||
files, ok := m.folderFiles[folder]
|
files, ok := m.folderFiles[folder]
|
||||||
runner := m.folderRunners[folder]
|
runner := m.folderRunners[folder]
|
||||||
m.fmut.RUnlock()
|
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)
|
l.Fatalf("Index for nonexistant folder %q", folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(fs); {
|
fs = filterIndex(folder, fs, cfg.IgnoreDelete)
|
||||||
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++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files.Replace(deviceID, fs)
|
files.Replace(deviceID, fs)
|
||||||
|
|
||||||
events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
|
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()
|
m.fmut.RLock()
|
||||||
files := m.folderFiles[folder]
|
files := m.folderFiles[folder]
|
||||||
|
cfg := m.folderCfgs[folder]
|
||||||
runner, ok := m.folderRunners[folder]
|
runner, ok := m.folderRunners[folder]
|
||||||
m.fmut.RUnlock()
|
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)
|
l.Fatalf("IndexUpdate for nonexistant folder %q", folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(fs); {
|
fs = filterIndex(folder, fs, cfg.IgnoreDelete)
|
||||||
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++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files.Update(deviceID, fs)
|
files.Update(deviceID, fs)
|
||||||
|
|
||||||
events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
|
events.Default.Log(events.RemoteIndexUpdated, map[string]interface{}{
|
||||||
@ -1788,6 +1756,33 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
|
|||||||
return true
|
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 {
|
func symlinkInvalid(folder string, fi db.FileIntf) bool {
|
||||||
if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() {
|
if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() {
|
||||||
symlinkWarning.Do(func() {
|
symlinkWarning.Do(func() {
|
||||||
|
@ -1192,3 +1192,40 @@ func benchmarkTree(b *testing.B, n1, n2 int) {
|
|||||||
}
|
}
|
||||||
b.ReportAllocs()
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user