mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-03 15:17:25 +00:00
parent
de9489585f
commit
a1c5b44c74
@ -201,7 +201,7 @@ func (db *Lowlevel) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
|
|||||||
blocksHashSame := ok && bytes.Equal(ef.BlocksHash, f.BlocksHash)
|
blocksHashSame := ok && bytes.Equal(ef.BlocksHash, f.BlocksHash)
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
if len(ef.Blocks) != 0 && !ef.IsInvalid() {
|
if len(ef.Blocks) != 0 && !ef.IsInvalid() && ef.Size > 0 {
|
||||||
for _, block := range ef.Blocks {
|
for _, block := range ef.Blocks {
|
||||||
keyBuf, err = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
|
keyBuf, err = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -262,7 +262,7 @@ func (db *Lowlevel) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
|
|||||||
}
|
}
|
||||||
l.Debugf("adding sequence; folder=%q sequence=%v %v", folder, f.Sequence, f.Name)
|
l.Debugf("adding sequence; folder=%q sequence=%v %v", folder, f.Sequence, f.Name)
|
||||||
|
|
||||||
if len(f.Blocks) != 0 && !f.IsInvalid() {
|
if len(f.Blocks) != 0 && !f.IsInvalid() && f.Size > 0 {
|
||||||
for i, block := range f.Blocks {
|
for i, block := range f.Blocks {
|
||||||
binary.BigEndian.PutUint32(blockBuf, uint32(i))
|
binary.BigEndian.PutUint32(blockBuf, uint32(i))
|
||||||
keyBuf, err = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
|
keyBuf, err = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
|
||||||
|
@ -484,11 +484,11 @@ func TestUpdateToInvalid(t *testing.T) {
|
|||||||
f := db.NewBlockFinder(ldb)
|
f := db.NewBlockFinder(ldb)
|
||||||
|
|
||||||
localHave := fileList{
|
localHave := fileList{
|
||||||
protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
|
protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1), Size: 1},
|
||||||
protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
|
protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2), Size: 1},
|
||||||
protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), LocalFlags: protocol.FlagLocalIgnored},
|
protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), LocalFlags: protocol.FlagLocalIgnored, Size: 1},
|
||||||
protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
|
protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7), Size: 1},
|
||||||
protocol.FileInfo{Name: "e", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, LocalFlags: protocol.FlagLocalIgnored},
|
protocol.FileInfo{Name: "e", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, LocalFlags: protocol.FlagLocalIgnored, Size: 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
replace(s, protocol.LocalDeviceID, localHave)
|
replace(s, protocol.LocalDeviceID, localHave)
|
||||||
|
@ -453,20 +453,27 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
f.clearScanErrors(subDirs)
|
f.clearScanErrors(subDirs)
|
||||||
|
alreadyUsed := make(map[string]struct{})
|
||||||
for res := range fchan {
|
for res := range fchan {
|
||||||
if res.Err != nil {
|
if res.Err != nil {
|
||||||
f.newScanError(res.Path, res.Err)
|
f.newScanError(res.Path, res.Err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := batch.flushIfFull(); err != nil {
|
|
||||||
return err
|
if batch.full() {
|
||||||
|
if err := batch.flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
snap.Release()
|
||||||
|
snap = f.fset.Snapshot()
|
||||||
|
alreadyUsed = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.append(res.File)
|
batch.append(res.File)
|
||||||
changes++
|
changes++
|
||||||
|
|
||||||
if f.localFlags&protocol.FlagLocalReceiveOnly == 0 {
|
if f.localFlags&protocol.FlagLocalReceiveOnly == 0 {
|
||||||
if nf, ok := f.findRename(snap, mtimefs, res.File); ok {
|
if nf, ok := f.findRename(snap, mtimefs, res.File, alreadyUsed); ok {
|
||||||
batch.append(nf)
|
batch.append(nf)
|
||||||
changes++
|
changes++
|
||||||
}
|
}
|
||||||
@ -622,8 +629,8 @@ func (f *folder) scanSubdirs(subDirs []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *folder) findRename(snap *db.Snapshot, mtimefs fs.Filesystem, file protocol.FileInfo) (protocol.FileInfo, bool) {
|
func (f *folder) findRename(snap *db.Snapshot, mtimefs fs.Filesystem, file protocol.FileInfo, alreadyUsed map[string]struct{}) (protocol.FileInfo, bool) {
|
||||||
if len(file.Blocks) == 0 {
|
if len(file.Blocks) == 0 || file.Size == 0 {
|
||||||
return protocol.FileInfo{}, false
|
return protocol.FileInfo{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +646,10 @@ func (f *folder) findRename(snap *db.Snapshot, mtimefs fs.Filesystem, file proto
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := alreadyUsed[fi.Name]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if fi.ShouldConflict() {
|
if fi.ShouldConflict() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -658,6 +669,8 @@ func (f *folder) findRename(snap *db.Snapshot, mtimefs fs.Filesystem, file proto
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alreadyUsed[fi.Name] = struct{}{}
|
||||||
|
|
||||||
nf = fi
|
nf = fi
|
||||||
nf.SetDeleted(f.shortID)
|
nf.SetDeleted(f.shortID)
|
||||||
nf.LocalFlags = f.localFlags
|
nf.LocalFlags = f.localFlags
|
||||||
|
@ -213,6 +213,7 @@ func TestCopierFinder(t *testing.T) {
|
|||||||
|
|
||||||
existingBlocks := []int{0, 2, 3, 4, 0, 0, 7, 0}
|
existingBlocks := []int{0, 2, 3, 4, 0, 0, 7, 0}
|
||||||
existingFile := setupFile(fs.TempName("file"), existingBlocks)
|
existingFile := setupFile(fs.TempName("file"), existingBlocks)
|
||||||
|
existingFile.Size = 1
|
||||||
requiredFile := existingFile
|
requiredFile := existingFile
|
||||||
requiredFile.Blocks = blocks[1:]
|
requiredFile.Blocks = blocks[1:]
|
||||||
requiredFile.Name = "file2"
|
requiredFile.Name = "file2"
|
||||||
@ -422,6 +423,7 @@ func TestCopierCleanup(t *testing.T) {
|
|||||||
|
|
||||||
// Create a file
|
// Create a file
|
||||||
file := setupFile("test", []int{0})
|
file := setupFile("test", []int{0})
|
||||||
|
file.Size = 1
|
||||||
m, f := setupSendReceiveFolder(file)
|
m, f := setupSendReceiveFolder(file)
|
||||||
defer cleanupSRFolder(f, m)
|
defer cleanupSRFolder(f, m)
|
||||||
|
|
||||||
|
@ -3609,6 +3609,132 @@ func TestRenameSequenceOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenameSameFile(t *testing.T) {
|
||||||
|
wcfg, fcfg := tmpDefaultWrapper()
|
||||||
|
m := setupModel(wcfg)
|
||||||
|
defer cleanupModel(m)
|
||||||
|
|
||||||
|
ffs := fcfg.Filesystem()
|
||||||
|
must(t, writeFile(ffs, "file", []byte("file"), 0644))
|
||||||
|
|
||||||
|
m.ScanFolders()
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
snap := dbSnapshot(t, m, "default")
|
||||||
|
snap.WithHave(protocol.LocalDeviceID, func(i db.FileIntf) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
snap.Release()
|
||||||
|
|
||||||
|
if count != 1 {
|
||||||
|
t.Errorf("Unexpected count: %d != %d", count, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
must(t, ffs.Rename("file", "file1"))
|
||||||
|
must(t, osutil.Copy(ffs, ffs, "file1", "file0"))
|
||||||
|
must(t, osutil.Copy(ffs, ffs, "file1", "file2"))
|
||||||
|
must(t, osutil.Copy(ffs, ffs, "file1", "file3"))
|
||||||
|
must(t, osutil.Copy(ffs, ffs, "file1", "file4"))
|
||||||
|
|
||||||
|
m.ScanFolders()
|
||||||
|
|
||||||
|
snap = dbSnapshot(t, m, "default")
|
||||||
|
defer snap.Release()
|
||||||
|
|
||||||
|
prevSeq := int64(0)
|
||||||
|
seen := false
|
||||||
|
snap.WithHaveSequence(0, func(i db.FileIntf) bool {
|
||||||
|
if i.SequenceNo() <= prevSeq {
|
||||||
|
t.Fatalf("non-increasing sequences: %d <= %d", i.SequenceNo(), prevSeq)
|
||||||
|
}
|
||||||
|
if i.FileName() == "file" {
|
||||||
|
if seen {
|
||||||
|
t.Fatal("already seen file")
|
||||||
|
}
|
||||||
|
seen = true
|
||||||
|
}
|
||||||
|
prevSeq = i.SequenceNo()
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenameEmptyFile(t *testing.T) {
|
||||||
|
wcfg, fcfg := tmpDefaultWrapper()
|
||||||
|
m := setupModel(wcfg)
|
||||||
|
defer cleanupModel(m)
|
||||||
|
|
||||||
|
ffs := fcfg.Filesystem()
|
||||||
|
|
||||||
|
must(t, writeFile(ffs, "file", []byte("data"), 0644))
|
||||||
|
must(t, writeFile(ffs, "empty", nil, 0644))
|
||||||
|
|
||||||
|
m.ScanFolders()
|
||||||
|
|
||||||
|
snap := dbSnapshot(t, m, "default")
|
||||||
|
defer snap.Release()
|
||||||
|
empty, eok := snap.Get(protocol.LocalDeviceID, "empty")
|
||||||
|
if !eok {
|
||||||
|
t.Fatal("failed to find empty file")
|
||||||
|
}
|
||||||
|
file, fok := snap.Get(protocol.LocalDeviceID, "file")
|
||||||
|
if !fok {
|
||||||
|
t.Fatal("failed to find non-empty file")
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
snap.WithBlocksHash(empty.BlocksHash, func(_ db.FileIntf) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if count != 0 {
|
||||||
|
t.Fatalf("Found %d entries for empty file, expected 0", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
snap.WithBlocksHash(file.BlocksHash, func(_ db.FileIntf) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if count != 1 {
|
||||||
|
t.Fatalf("Found %d entries for non-empty file, expected 1", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
must(t, ffs.Rename("file", "new-file"))
|
||||||
|
must(t, ffs.Rename("empty", "new-empty"))
|
||||||
|
|
||||||
|
// Scan
|
||||||
|
m.ScanFolders()
|
||||||
|
|
||||||
|
snap = dbSnapshot(t, m, "default")
|
||||||
|
defer snap.Release()
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
snap.WithBlocksHash(empty.BlocksHash, func(_ db.FileIntf) bool {
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if count != 0 {
|
||||||
|
t.Fatalf("Found %d entries for empty file, expected 0", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
snap.WithBlocksHash(file.BlocksHash, func(i db.FileIntf) bool {
|
||||||
|
count++
|
||||||
|
if i.FileName() != "new-file" {
|
||||||
|
t.Fatalf("unexpected file name %s, expected new-file", i.FileName())
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if count != 1 {
|
||||||
|
t.Fatalf("Found %d entries for non-empty file, expected 1", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBlockListMap(t *testing.T) {
|
func TestBlockListMap(t *testing.T) {
|
||||||
wcfg, fcfg := tmpDefaultWrapper()
|
wcfg, fcfg := tmpDefaultWrapper()
|
||||||
m := setupModel(wcfg)
|
m := setupModel(wcfg)
|
||||||
|
Loading…
Reference in New Issue
Block a user