1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package model
import (
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/ignore"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/semaphore"
"github.com/syncthing/syncthing/lib/versioner"
)
func init() {
folderFactories[config.FolderTypeSendOnly] = newSendOnlyFolder
}
type sendOnlyFolder struct {
folder
}
func newSendOnlyFolder(model *model, fset *db.FileSet, ignores *ignore.Matcher, cfg config.FolderConfiguration, _ versioner.Versioner, evLogger events.Logger, ioLimiter *semaphore.Semaphore) service {
f := &sendOnlyFolder{
folder: newFolder(model, fset, ignores, cfg, evLogger, ioLimiter, nil),
}
f.folder.puller = f
return f
}
func (*sendOnlyFolder) PullErrors() []FileError {
return nil
}
// pull checks need for files that only differ by metadata (no changes on disk)
func (f *sendOnlyFolder) pull() (bool, error) {
batch := db.NewFileInfoBatch(func(files []protocol.FileInfo) error {
f.updateLocalsFromPulling(files)
return nil
})
snap, err := f.dbSnapshot()
if err != nil {
return false, err
}
defer snap.Release()
snap.WithNeed(protocol.LocalDeviceID, func(file protocol.FileInfo) bool {
batch.FlushIfFull()
if f.ignores.Match(file.FileName()).IsIgnored() {
file.SetIgnored()
batch.Append(file)
l.Debugln(f, "Handling ignored file", file)
return true
}
curFile, ok := snap.Get(protocol.LocalDeviceID, file.FileName())
if !ok {
if file.IsInvalid() {
// Global invalid file just exists for need accounting
batch.Append(file)
} else if file.IsDeleted() {
l.Debugln("Should never get a deleted file as needed when we don't have it")
f.evLogger.Log(events.Failure, "got deleted file that doesn't exist locally as needed when pulling on send-only")
}
return true
}
if !file.IsEquivalentOptional(curFile, protocol.FileInfoComparison{
ModTimeWindow: f.modTimeWindow,
IgnorePerms: f.IgnorePerms,
IgnoreOwnership: !f.SyncOwnership,
IgnoreXattrs: !f.SyncXattrs,
}) {
return true
}
batch.Append(file)
l.Debugln(f, "Merging versions of identical file", file)
return true
})
batch.Flush()
return true, nil
}
func (f *sendOnlyFolder) Override() {
f.doInSync(f.override)
}
func (f *sendOnlyFolder) override() error {
l.Infoln("Overriding global state on folder", f.Description())
f.setState(FolderScanning)
defer f.setState(FolderIdle)
batch := db.NewFileInfoBatch(func(files []protocol.FileInfo) error {
f.updateLocalsFromScanning(files)
return nil
})
snap, err := f.dbSnapshot()
if err != nil {
return err
}
defer snap.Release()
snap.WithNeed(protocol.LocalDeviceID, func(need protocol.FileInfo) bool {
_ = batch.FlushIfFull()
have, ok := snap.Get(protocol.LocalDeviceID, need.Name)
// Don't override files that are in a bad state (ignored,
// unsupported, must rescan, ...).
if ok && have.IsInvalid() {
return true
}
if !ok || have.Name != need.Name {
// We are missing the file
need.SetDeleted(f.shortID)
} else {
// We have the file, replace with our version
have.Version = have.Version.Merge(need.Version).Update(f.shortID)
need = have
}
need.Sequence = 0
batch.Append(need)
return true
})
return batch.Flush()
}
|