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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user