浏览代码

lib/model: Don't fail over case-conflict on tempfile (fixes #6973) (#6975)

Simon Frei 5 年之前
父节点
当前提交
e3cd9219b8
共有 3 个文件被更改,包括 36 次插入2 次删除
  1. 2 2
      lib/fs/casefs.go
  2. 8 0
      lib/model/folder_sendrecv.go
  3. 26 0
      lib/model/folder_sendrecv_test.go

+ 2 - 2
lib/fs/casefs.go

@@ -25,11 +25,11 @@ const (
 )
 
 type ErrCaseConflict struct {
-	given, real string
+	Given, Real string
 }
 
 func (e *ErrCaseConflict) Error() string {
-	return fmt.Sprintf(`given name "%v" differs from name in filesystem "%v"`, e.given, e.real)
+	return fmt.Sprintf(`given name "%v" differs from name in filesystem "%v"`, e.Given, e.Real)
 }
 
 func IsErrCaseConflict(err error) bool {

+ 8 - 0
lib/model/folder_sendrecv.go

@@ -1060,6 +1060,14 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, snap *db.Snapshot
 	// Check for an old temporary file which might have some blocks we could
 	// reuse.
 	tempBlocks, err := scanner.HashFile(f.ctx, f.fs, tempName, file.BlockSize(), nil, false)
+	if err != nil {
+		var caseErr *fs.ErrCaseConflict
+		if errors.As(err, &caseErr) {
+			if rerr := f.fs.Rename(caseErr.Real, tempName); rerr == nil {
+				tempBlocks, err = scanner.HashFile(f.ctx, f.fs, tempName, file.BlockSize(), nil, false)
+			}
+		}
+	}
 	if err == nil {
 		// Check for any reusable blocks in the temp file
 		tempCopyBlocks, _ := blockDiff(tempBlocks, file.Blocks)

+ 26 - 0
lib/model/folder_sendrecv_test.go

@@ -1216,6 +1216,32 @@ func testPullCaseOnlyDirOrSymlink(t *testing.T, dir bool) {
 	}
 }
 
+func TestPullTempFileCaseConflict(t *testing.T) {
+	m, f := setupSendReceiveFolder()
+	defer cleanupSRFolder(f, m)
+
+	copyChan := make(chan copyBlocksState, 1)
+
+	file := protocol.FileInfo{Name: "foo"}
+	confl := "Foo"
+	tempNameConfl := fs.TempName(confl)
+	if fd, err := f.fs.Create(tempNameConfl); err != nil {
+		t.Fatal(err)
+	} else {
+		if _, err := fd.Write([]byte("data")); err != nil {
+			t.Fatal(err)
+		}
+		fd.Close()
+	}
+
+	f.handleFile(file, f.fset.Snapshot(), copyChan)
+
+	cs := <-copyChan
+	if _, err := cs.tempFile(); err != nil {
+		t.Error(err)
+	}
+}
+
 func cleanupSharedPullerState(s *sharedPullerState) {
 	s.mut.Lock()
 	defer s.mut.Unlock()