lib/model: Also handle missing parent dir non-regular items (#5048)

This is an improvement of PR #4493 and related to (and maybe fixing) #4961
and #4475. Maybe fixing, because there is no clear reproducer for that
problem.

The previous PR added a mechanism to resurrect missing parent directories,
if there is a valid child file to be pulled. The same mechanism does not
exist for dirs and symlinks, even though a missing parent can happen for
those items as well. Therefore this PR extends the resurrection to all types
of pulled items.

In addition I moved the IsDeleted branch while iterating over
processDirectly to the existing IsDeleted branch in the WithNeed iteration.
This saves one pointless assignment and IsDeleted query. Also
This commit is contained in:
Simon Frei
2018-07-10 17:40:06 +02:00
committed by Jakob Borg
parent 3f17bda786
commit 6b82538e62
3 changed files with 160 additions and 65 deletions

View File

@@ -266,7 +266,7 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) {
}
// Recreate foo and a file in it with some data
fc.addFile("foo", 0755, protocol.FileInfoTypeDirectory, nil)
fc.updateFile("foo", 0755, protocol.FileInfoTypeDirectory, nil)
fc.addFile("foo/test", 0644, protocol.FileInfoTypeFile, []byte("testtesttest"))
fc.sendIndexUpdate()
for updates := 0; updates < 1; updates += <-idx {
@@ -531,6 +531,83 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
}
}
func TestParentDeletion(t *testing.T) {
m, fc, tmpDir := setupModelWithConnection()
defer m.Stop()
defer os.RemoveAll(tmpDir)
parent := "foo"
child := filepath.Join(parent, "bar")
testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, tmpDir)
received := make(chan []protocol.FileInfo)
fc.addFile(parent, 0777, protocol.FileInfoTypeDirectory, nil)
fc.addFile(child, 0777, protocol.FileInfoTypeDirectory, nil)
fc.mut.Lock()
fc.indexFn = func(folder string, fs []protocol.FileInfo) {
received <- fs
return
}
fc.mut.Unlock()
fc.sendIndexUpdate()
// Get back index from initial setup
select {
case fs := <-received:
if len(fs) != 2 {
t.Fatalf("Sent index with %d files, should be 2", len(fs))
}
case <-time.After(time.Second):
t.Fatalf("timed out")
}
// Delete parent dir
if err := testFs.RemoveAll(parent); err != nil {
t.Fatal(err)
}
// Scan only the child dir (not the parent)
if err := m.ScanFolderSubdirs("default", []string{child}); err != nil {
t.Fatal("Failed scanning:", err)
}
select {
case fs := <-received:
if len(fs) != 1 {
t.Fatalf("Sent index with %d files, should be 1", len(fs))
}
if fs[0].Name != child {
t.Fatalf(`Sent index with file "%v", should be "%v"`, fs[0].Name, child)
}
case <-time.After(time.Second):
t.Fatalf("timed out")
}
// Recreate the child dir on the remote
fc.updateFile(child, 0777, protocol.FileInfoTypeDirectory, nil)
fc.sendIndexUpdate()
// Wait for the child dir to be recreated and sent to the remote
select {
case fs := <-received:
l.Debugln("sent:", fs)
found := false
for _, f := range fs {
if f.Name == child {
if f.Deleted {
t.Fatalf(`File "%v" is still deleted`, child)
}
found = true
}
}
if !found {
t.Fatalf(`File "%v" is missing in index`, child)
}
case <-time.After(5 * time.Second):
t.Fatalf("timed out")
}
}
func setupModelWithConnection() (*Model, *fakeConnection, string) {
tmpDir := createTmpDir()
cfg := defaultCfgWrapper.RawCopy()