diff --git a/lib/config/config.go b/lib/config/config.go index 43c128f81..35854309e 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -199,6 +199,9 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) { existingDevices[myID] = true } + // Ensure that the device list is free from duplicates + cfg.Devices = ensureNoDuplicateDevices(cfg.Devices) + sort.Sort(DeviceConfigurationList(cfg.Devices)) // Ensure that any loose devices are not present in the wrong places // Ensure that there are no duplicate devices @@ -206,7 +209,7 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) { for i := range cfg.Folders { cfg.Folders[i].Devices = ensureDevicePresent(cfg.Folders[i].Devices, myID) cfg.Folders[i].Devices = ensureExistingDevices(cfg.Folders[i].Devices, existingDevices) - cfg.Folders[i].Devices = ensureNoDuplicates(cfg.Folders[i].Devices) + cfg.Folders[i].Devices = ensureNoDuplicateFolderDevices(cfg.Folders[i].Devices) sort.Sort(FolderDeviceConfigurationList(cfg.Folders[i].Devices)) } @@ -408,7 +411,25 @@ loop: return devices[0:count] } -func ensureNoDuplicates(devices []FolderDeviceConfiguration) []FolderDeviceConfiguration { +func ensureNoDuplicateFolderDevices(devices []FolderDeviceConfiguration) []FolderDeviceConfiguration { + count := len(devices) + i := 0 + seenDevices := make(map[protocol.DeviceID]bool) +loop: + for i < count { + id := devices[i].DeviceID + if _, ok := seenDevices[id]; ok { + devices[i] = devices[count-1] + count-- + continue loop + } + seenDevices[id] = true + i++ + } + return devices[0:count] +} + +func ensureNoDuplicateDevices(devices []DeviceConfiguration) []DeviceConfiguration { count := len(devices) i := 0 seenDevices := make(map[protocol.DeviceID]bool) diff --git a/lib/config/config_test.go b/lib/config/config_test.go index 4a238e03a..ac142e481 100644 --- a/lib/config/config_test.go +++ b/lib/config/config_test.go @@ -592,3 +592,29 @@ func TestGUIConfigURL(t *testing.T) { } } } + +func TestRemoveDuplicateDevicesFolders(t *testing.T) { + wrapper, err := Load("testdata/duplicates.xml", device1) + if err != nil { + t.Fatal(err) + } + + // All folders are loaded, but the duplicate ones are disabled. + if l := len(wrapper.Raw().Folders); l != 3 { + t.Errorf("Incorrect number of folders, %d != 3", l) + } + for i, f := range wrapper.Raw().Folders { + if f.ID == "f1" && f.Invalid == "" { + t.Errorf("Folder %d (%q) is not set invalid", i, f.ID) + } + } + + if l := len(wrapper.Raw().Devices); l != 3 { + t.Errorf("Incorrect number of devices, %d != 3", l) + } + + f := wrapper.Folders()["f2"] + if l := len(f.Devices); l != 2 { + t.Errorf("Incorrect number of folder devices, %d != 2", l) + } +} diff --git a/lib/config/testdata/duplicates.xml b/lib/config/testdata/duplicates.xml new file mode 100644 index 000000000..a6fbbd15e --- /dev/null +++ b/lib/config/testdata/duplicates.xml @@ -0,0 +1,33 @@ + + +
192.0.2.1
+
192.0.2.2
+
+ +
192.0.2.3:6070
+
[2001:db8::42]:4242
+
+ +
[2001:db8::44]:4444
+
192.0.2.4:6090
+
+ + +
192.0.2.5
+
+ + + + + + + + + + + + + + + +