lib/model: Fix case-only renames on pull (#6978)

This commit is contained in:
Simon Frei 2020-09-10 08:23:54 +02:00 committed by GitHub
parent 780fb3bac1
commit 56d48d341f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 9 deletions

View File

@ -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
curTarget, ok := snap.Get(protocol.LocalDeviceID, 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:
// We can't check whether the file changed as compared to the db,
// do not delete.
err = serr
var caseErr *fs.ErrCaseConflict
switch {
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:
// Target appeared from nowhere
scanChan <- target.Name

View File

@ -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) {
s.mut.Lock()
defer s.mut.Unlock()