lib/model: Fix case-only renames on pull (#6978)
This commit is contained in:
@@ -945,16 +945,26 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, sn
|
|||||||
// Check that the target corresponds to what we have in the DB
|
// Check that the target corresponds to what we have in the DB
|
||||||
curTarget, ok := snap.Get(protocol.LocalDeviceID, target.Name)
|
curTarget, ok := snap.Get(protocol.LocalDeviceID, target.Name)
|
||||||
switch stat, serr := f.fs.Lstat(target.Name); {
|
switch stat, serr := f.fs.Lstat(target.Name); {
|
||||||
case serr != nil && fs.IsNotExist(serr):
|
|
||||||
if !ok || curTarget.IsDeleted() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
scanChan <- target.Name
|
|
||||||
err = errModified
|
|
||||||
case serr != nil:
|
case serr != nil:
|
||||||
// We can't check whether the file changed as compared to the db,
|
var caseErr *fs.ErrCaseConflict
|
||||||
// do not delete.
|
switch {
|
||||||
err = serr
|
case errors.As(serr, &caseErr):
|
||||||
|
if caseErr.Real != source.Name {
|
||||||
|
err = serr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough // This is a case only rename
|
||||||
|
case fs.IsNotExist(serr):
|
||||||
|
if !ok || curTarget.IsDeleted() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
scanChan <- target.Name
|
||||||
|
err = errModified
|
||||||
|
default:
|
||||||
|
// We can't check whether the file changed as compared to the db,
|
||||||
|
// do not delete.
|
||||||
|
err = serr
|
||||||
|
}
|
||||||
case !ok:
|
case !ok:
|
||||||
// Target appeared from nowhere
|
// Target appeared from nowhere
|
||||||
scanChan <- target.Name
|
scanChan <- target.Name
|
||||||
|
|||||||
@@ -1242,6 +1242,45 @@ func TestPullTempFileCaseConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPullCaseOnlyRename(t *testing.T) {
|
||||||
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
|
|
||||||
|
// tempNameConfl := fs.TempName(confl)
|
||||||
|
|
||||||
|
name := "foo"
|
||||||
|
if fd, err := f.fs.Create(name); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
if _, err := fd.Write([]byte("data")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fd.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
must(t, f.scanSubdirs(nil))
|
||||||
|
|
||||||
|
cur, ok := m.CurrentFolderFile(f.ID, name)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("file missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
deleted := cur
|
||||||
|
deleted.SetDeleted(myID.Short())
|
||||||
|
|
||||||
|
confl := cur
|
||||||
|
confl.Name = "Foo"
|
||||||
|
confl.Version = confl.Version.Update(device1.Short())
|
||||||
|
|
||||||
|
dbUpdateChan := make(chan dbUpdateJob, 2)
|
||||||
|
scanChan := make(chan string, 2)
|
||||||
|
snap := f.fset.Snapshot()
|
||||||
|
defer snap.Release()
|
||||||
|
if err := f.renameFile(cur, deleted, confl, snap, dbUpdateChan, scanChan); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func cleanupSharedPullerState(s *sharedPullerState) {
|
func cleanupSharedPullerState(s *sharedPullerState) {
|
||||||
s.mut.Lock()
|
s.mut.Lock()
|
||||||
defer s.mut.Unlock()
|
defer s.mut.Unlock()
|
||||||
|
|||||||
Reference in New Issue
Block a user