Browse Source

lib/model: Don't crash when taking rename shortcut (fixes #6654) (#6657)

If we fail to take the rename shortcut we may crash on a later loop,
because we do trickiness with the indexes but the original buckets[key]
in "range buckets[key]" isn't re-evaluated so i exceeds the max index.
Jakob Borg 5 years ago
parent
commit
5ffa012410
1 changed files with 11 additions and 6 deletions
  1. 11 6
      lib/model/folder_sendrecv.go

+ 11 - 6
lib/model/folder_sendrecv.go

@@ -460,12 +460,7 @@ nextFile:
 		// Check our list of files to be removed for a match, in which case
 		// we can just do a rename instead.
 		key := string(fi.BlocksHash)
-		for i, candidate := range buckets[key] {
-			// Remove the candidate from the bucket
-			lidx := len(buckets[key]) - 1
-			buckets[key][i] = buckets[key][lidx]
-			buckets[key] = buckets[key][:lidx]
-
+		for candidate, ok := popCandidate(buckets, key); ok; candidate, ok = popCandidate(buckets, key) {
 			// candidate is our current state of the file, where as the
 			// desired state with the delete bit set is in the deletion
 			// map.
@@ -498,6 +493,16 @@ nextFile:
 	return changed, fileDeletions, dirDeletions, nil
 }
 
+func popCandidate(buckets map[string][]protocol.FileInfo, key string) (protocol.FileInfo, bool) {
+	cands := buckets[key]
+	if len(cands) == 0 {
+		return protocol.FileInfo{}, false
+	}
+
+	buckets[key] = cands[1:]
+	return cands[0], true
+}
+
 func (f *sendReceiveFolder) processDeletions(fileDeletions map[string]protocol.FileInfo, dirDeletions []protocol.FileInfo, snap *db.Snapshot, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) {
 	for _, file := range fileDeletions {
 		select {