Browse Source

lib/model: Treat failed rename like del&update (#5203)

Simon Frei 7 years ago
parent
commit
523ac45456
1 changed files with 25 additions and 35 deletions
  1. 25 35
      lib/model/folder_sendrecv.go

+ 25 - 35
lib/model/folder_sendrecv.go

@@ -474,10 +474,14 @@ nextFile:
 				// desired state with the delete bit set is in the deletion
 				// map.
 				desired := fileDeletions[candidate.Name]
-				// Remove the pending deletion (as we perform it by renaming)
-				delete(fileDeletions, candidate.Name)
+				if err := f.renameFile(candidate, desired, fi, dbUpdateChan, scanChan); err != nil {
+					// Failed to rename, try to handle files as separate
+					// deletions and updates.
+					break
+				}
 
-				f.renameFile(candidate, desired, fi, dbUpdateChan, scanChan)
+				// Remove the pending deletion (as we performed it by renaming)
+				delete(fileDeletions, candidate.Name)
 
 				f.queue.Done(fileName)
 				continue nextFile
@@ -812,7 +816,7 @@ func (f *sendReceiveFolder) deleteFile(file protocol.FileInfo, scanChan chan<- s
 
 // renameFile attempts to rename an existing file to a destination
 // and set the right attributes on it.
-func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) {
+func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) error {
 	// Used in the defer closure below, updated by the function body. Take
 	// care not declare another err.
 	var err error
@@ -851,9 +855,7 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
 
 	// Check that source is compatible with what we have in the DB
 	if err = f.checkToBeDeleted(cur, scanChan); err != nil {
-		err = fmt.Errorf("from %s: %s", source.Name, err.Error())
-		f.newError("rename check source", target.Name, err)
-		return
+		return err
 	}
 	// Check that the target corresponds to what we have in the DB
 	curTarget, ok := f.model.CurrentFolderFile(f.folderID, target.Name)
@@ -882,9 +884,7 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
 		}
 	}
 	if err != nil {
-		err = fmt.Errorf("from %s: %s", source.Name, err.Error())
-		f.newError("rename check target", target.Name, err)
-		return
+		return err
 	}
 
 	tempName := fs.TempName(target.Name)
@@ -900,36 +900,26 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
 	} else {
 		err = osutil.TryRename(f.fs, source.Name, tempName)
 	}
+	if err != nil {
+		return err
+	}
 
-	if err == nil {
-		blockStatsMut.Lock()
-		blockStats["total"] += len(target.Blocks)
-		blockStats["renamed"] += len(target.Blocks)
-		blockStatsMut.Unlock()
-
-		// The file was renamed, so we have handled both the necessary delete
-		// of the source and the creation of the target. Fix-up the metadata,
-		// update the local index of the target file and rename from temp to real name.
+	blockStatsMut.Lock()
+	blockStats["total"] += len(target.Blocks)
+	blockStats["renamed"] += len(target.Blocks)
+	blockStatsMut.Unlock()
 
-		dbUpdateChan <- dbUpdateJob{source, dbUpdateDeleteFile}
+	// The file was renamed, so we have handled both the necessary delete
+	// of the source and the creation of the target temp file. Fix-up the metadata,
+	// update the local index of the target file and rename from temp to real name.
 
-		if err = f.performFinish(nil, target, curTarget, true, tempName, dbUpdateChan, scanChan); err != nil {
-			return
-		}
-	} else {
-		// We failed the rename so we have a source file that we still need to
-		// get rid of. Attempt to delete it instead so that we make *some*
-		// progress. The target is unhandled.
+	if err = f.performFinish(nil, target, curTarget, true, tempName, dbUpdateChan, scanChan); err != nil {
+		return err
+	}
 
-		err = osutil.InWritableDir(f.fs.Remove, f.fs, source.Name)
-		if err != nil {
-			err = fmt.Errorf("from %s: %s", source.Name, err.Error())
-			f.newError("rename delete", target.Name, err)
-			return
-		}
+	dbUpdateChan <- dbUpdateJob{source, dbUpdateDeleteFile}
 
-		dbUpdateChan <- dbUpdateJob{source, dbUpdateDeleteFile}
-	}
+	return nil
 }
 
 // This is the flow of data and events here, I think...