mirror of
https://github.com/octoleo/syncthing.git
synced 2025-03-21 10:12:21 +00:00
lib/model: Consider case conflicts when checking to be deleted items (#6986)
This commit is contained in:
parent
3e24d82513
commit
8210466b03
@ -813,9 +813,10 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, snap *db.Snapshot,
|
|||||||
|
|
||||||
cur, hasCur := snap.Get(protocol.LocalDeviceID, file.Name)
|
cur, hasCur := snap.Get(protocol.LocalDeviceID, file.Name)
|
||||||
|
|
||||||
if err = f.checkToBeDeleted(file, cur, hasCur, dbUpdateDeleteDir, dbUpdateChan, scanChan); err != nil {
|
if err = f.checkToBeDeleted(file, cur, hasCur, scanChan); err != nil {
|
||||||
if fs.IsNotExist(err) {
|
if fs.IsNotExist(err) || fs.IsErrCaseConflict(err) {
|
||||||
err = nil
|
err = nil
|
||||||
|
dbUpdateChan <- dbUpdateJob{file, dbUpdateDeleteDir}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -860,9 +861,10 @@ func (f *sendReceiveFolder) deleteFileWithCurrent(file, cur protocol.FileInfo, h
|
|||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = f.checkToBeDeleted(file, cur, hasCur, dbUpdateDeleteFile, dbUpdateChan, scanChan); err != nil {
|
if err = f.checkToBeDeleted(file, cur, hasCur, scanChan); err != nil {
|
||||||
if fs.IsNotExist(err) {
|
if fs.IsNotExist(err) || fs.IsErrCaseConflict(err) {
|
||||||
err = nil
|
err = nil
|
||||||
|
dbUpdateChan <- dbUpdateJob{file, dbUpdateDeleteFile}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -945,7 +947,7 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, sn
|
|||||||
l.Debugln(f, "taking rename shortcut", source.Name, "->", target.Name)
|
l.Debugln(f, "taking rename shortcut", source.Name, "->", target.Name)
|
||||||
|
|
||||||
// Check that source is compatible with what we have in the DB
|
// Check that source is compatible with what we have in the DB
|
||||||
if err = f.checkToBeDeleted(source, cur, true, dbUpdateDeleteFile, dbUpdateChan, scanChan); err != nil {
|
if err = f.checkToBeDeleted(source, cur, true, scanChan); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Check that the target corresponds to what we have in the DB
|
// Check that the target corresponds to what we have in the DB
|
||||||
@ -1979,26 +1981,25 @@ func (f *sendReceiveFolder) scanIfItemChanged(name string, stat fs.FileInfo, ite
|
|||||||
|
|
||||||
// checkToBeDeleted makes sure the file on disk is compatible with what there is
|
// checkToBeDeleted makes sure the file on disk is compatible with what there is
|
||||||
// in the DB before the caller proceeds with actually deleting it.
|
// in the DB before the caller proceeds with actually deleting it.
|
||||||
// I.e. non-nil error status means "Do not delete!".
|
// I.e. non-nil error status means "Do not delete!" or "is already deleted".
|
||||||
func (f *sendReceiveFolder) checkToBeDeleted(file, cur protocol.FileInfo, hasCur bool, updateType dbUpdateType, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) error {
|
func (f *sendReceiveFolder) checkToBeDeleted(file, cur protocol.FileInfo, hasCur bool, scanChan chan<- string) error {
|
||||||
if err := osutil.TraversesSymlink(f.fs, filepath.Dir(file.Name)); err != nil {
|
if err := osutil.TraversesSymlink(f.fs, filepath.Dir(file.Name)); err != nil {
|
||||||
l.Debugln(f, "not deleting item behind symlink on disk, but update db", file.Name)
|
l.Debugln(f, "not deleting item behind symlink on disk, but update db", file.Name)
|
||||||
dbUpdateChan <- dbUpdateJob{file, updateType}
|
|
||||||
return fs.ErrNotExist
|
return fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
stat, err := f.fs.Lstat(file.Name)
|
stat, err := f.fs.Lstat(file.Name)
|
||||||
if !fs.IsNotExist(err) && err != nil {
|
deleted := fs.IsNotExist(err) || fs.IsErrCaseConflict(err)
|
||||||
|
if !deleted && err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if fs.IsNotExist(err) {
|
if deleted {
|
||||||
if hasCur && !cur.Deleted && !cur.IsUnsupported() {
|
if hasCur && !cur.Deleted && !cur.IsUnsupported() {
|
||||||
scanChan <- file.Name
|
scanChan <- file.Name
|
||||||
return errModified
|
return errModified
|
||||||
}
|
}
|
||||||
l.Debugln(f, "not deleting item we don't have, but update db", file.Name)
|
l.Debugln(f, "not deleting item we don't have, but update db", file.Name)
|
||||||
dbUpdateChan <- dbUpdateJob{file, updateType}
|
return err
|
||||||
return fs.ErrNotExist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.scanIfItemChanged(file.Name, stat, cur, hasCur, scanChan)
|
return f.scanIfItemChanged(file.Name, stat, cur, hasCur, scanChan)
|
||||||
|
@ -781,18 +781,8 @@ func TestDeleteIgnorePerms(t *testing.T) {
|
|||||||
fi, err := scanner.CreateFileInfo(stat, name, ffs)
|
fi, err := scanner.CreateFileInfo(stat, name, ffs)
|
||||||
must(t, err)
|
must(t, err)
|
||||||
ffs.Chmod(name, 0600)
|
ffs.Chmod(name, 0600)
|
||||||
scanChan := make(chan string)
|
scanChan := make(chan string, 1)
|
||||||
dbUpdateChan := make(chan dbUpdateJob)
|
err = f.checkToBeDeleted(fi, fi, true, scanChan)
|
||||||
finished := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
err = f.checkToBeDeleted(fi, fi, true, dbUpdateDeleteFile, dbUpdateChan, scanChan)
|
|
||||||
close(finished)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-scanChan:
|
|
||||||
<-finished
|
|
||||||
case <-finished:
|
|
||||||
}
|
|
||||||
must(t, err)
|
must(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,6 +1315,40 @@ func TestPullSymlinkOverExistingWindows(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPullDeleteCaseConflict(t *testing.T) {
|
||||||
|
m, f := setupSendReceiveFolder()
|
||||||
|
defer cleanupSRFolder(f, m)
|
||||||
|
|
||||||
|
name := "foo"
|
||||||
|
fi := protocol.FileInfo{Name: "Foo"}
|
||||||
|
dbUpdateChan := make(chan dbUpdateJob, 1)
|
||||||
|
scanChan := make(chan string)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
f.deleteFileWithCurrent(fi, protocol.FileInfo{}, false, dbUpdateChan, scanChan)
|
||||||
|
select {
|
||||||
|
case <-dbUpdateChan:
|
||||||
|
default:
|
||||||
|
t.Error("Missing db update for file")
|
||||||
|
}
|
||||||
|
|
||||||
|
snap := f.fset.Snapshot()
|
||||||
|
defer snap.Release()
|
||||||
|
f.deleteDir(fi, snap, dbUpdateChan, scanChan)
|
||||||
|
select {
|
||||||
|
case <-dbUpdateChan:
|
||||||
|
default:
|
||||||
|
t.Error("Missing db update for dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func cleanupSharedPullerState(s *sharedPullerState) {
|
func cleanupSharedPullerState(s *sharedPullerState) {
|
||||||
s.mut.Lock()
|
s.mut.Lock()
|
||||||
defer s.mut.Unlock()
|
defer s.mut.Unlock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user