model.go 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package model
  7. import (
  8. "bytes"
  9. "context"
  10. "encoding/json"
  11. "fmt"
  12. "io"
  13. "net"
  14. "path/filepath"
  15. "reflect"
  16. "runtime"
  17. "strings"
  18. stdsync "sync"
  19. "time"
  20. "github.com/pkg/errors"
  21. "github.com/thejerf/suture/v4"
  22. "github.com/syncthing/syncthing/lib/config"
  23. "github.com/syncthing/syncthing/lib/connections"
  24. "github.com/syncthing/syncthing/lib/db"
  25. "github.com/syncthing/syncthing/lib/events"
  26. "github.com/syncthing/syncthing/lib/fs"
  27. "github.com/syncthing/syncthing/lib/ignore"
  28. "github.com/syncthing/syncthing/lib/osutil"
  29. "github.com/syncthing/syncthing/lib/protocol"
  30. "github.com/syncthing/syncthing/lib/scanner"
  31. "github.com/syncthing/syncthing/lib/stats"
  32. "github.com/syncthing/syncthing/lib/svcutil"
  33. "github.com/syncthing/syncthing/lib/sync"
  34. "github.com/syncthing/syncthing/lib/ur/contract"
  35. "github.com/syncthing/syncthing/lib/versioner"
  36. )
  37. // How many files to send in each Index/IndexUpdate message.
  38. const (
  39. maxBatchSizeBytes = 250 * 1024 // Aim for making index messages no larger than 250 KiB (uncompressed)
  40. maxBatchSizeFiles = 1000 // Either way, don't include more files than this
  41. )
  42. type service interface {
  43. suture.Service
  44. BringToFront(string)
  45. Override()
  46. Revert()
  47. DelayScan(d time.Duration)
  48. SchedulePull() // something relevant changed, we should try a pull
  49. Jobs(page, perpage int) ([]string, []string, int) // In progress, Queued, skipped
  50. Scan(subs []string) error
  51. Errors() []FileError
  52. WatchError() error
  53. ScheduleForceRescan(path string)
  54. GetStatistics() (stats.FolderStatistics, error)
  55. getState() (folderState, time.Time, error)
  56. }
  57. type Availability struct {
  58. ID protocol.DeviceID `json:"id"`
  59. FromTemporary bool `json:"fromTemporary"`
  60. }
  61. type Model interface {
  62. suture.Service
  63. connections.Model
  64. ResetFolder(folder string)
  65. DelayScan(folder string, next time.Duration)
  66. ScanFolder(folder string) error
  67. ScanFolders() map[string]error
  68. ScanFolderSubdirs(folder string, subs []string) error
  69. State(folder string) (string, time.Time, error)
  70. FolderErrors(folder string) ([]FileError, error)
  71. WatchError(folder string) error
  72. Override(folder string)
  73. Revert(folder string)
  74. BringToFront(folder, file string)
  75. GetIgnores(folder string) ([]string, []string, error)
  76. SetIgnores(folder string, content []string) error
  77. GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
  78. RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error)
  79. DBSnapshot(folder string) (*db.Snapshot, error)
  80. NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error)
  81. RemoteNeedFolderFiles(folder string, device protocol.DeviceID, page, perpage int) ([]db.FileInfoTruncated, error)
  82. LocalChangedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, error)
  83. FolderProgressBytesCompleted(folder string) int64
  84. CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool)
  85. CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool)
  86. Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []Availability
  87. Completion(device protocol.DeviceID, folder string) FolderCompletion
  88. ConnectionStats() map[string]interface{}
  89. DeviceStatistics() (map[string]stats.DeviceStatistics, error)
  90. FolderStatistics() (map[string]stats.FolderStatistics, error)
  91. UsageReportingStats(report *contract.Report, version int, preview bool)
  92. PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error)
  93. PendingFolders(device protocol.DeviceID) (map[string]db.PendingFolder, error)
  94. StartDeadlockDetector(timeout time.Duration)
  95. GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{}
  96. }
  97. type model struct {
  98. *suture.Supervisor
  99. // constructor parameters
  100. cfg config.Wrapper
  101. id protocol.DeviceID
  102. clientName string
  103. clientVersion string
  104. db *db.Lowlevel
  105. protectedFiles []string
  106. evLogger events.Logger
  107. // constant or concurrency safe fields
  108. finder *db.BlockFinder
  109. progressEmitter *ProgressEmitter
  110. shortID protocol.ShortID
  111. // globalRequestLimiter limits the amount of data in concurrent incoming
  112. // requests
  113. globalRequestLimiter *byteSemaphore
  114. // folderIOLimiter limits the number of concurrent I/O heavy operations,
  115. // such as scans and pulls.
  116. folderIOLimiter *byteSemaphore
  117. fatalChan chan error
  118. // fields protected by fmut
  119. fmut sync.RWMutex
  120. folderCfgs map[string]config.FolderConfiguration // folder -> cfg
  121. folderFiles map[string]*db.FileSet // folder -> files
  122. deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
  123. folderIgnores map[string]*ignore.Matcher // folder -> matcher object
  124. folderRunners map[string]service // folder -> puller or scanner
  125. folderRunnerToken map[string]suture.ServiceToken // folder -> token for folder runner
  126. folderRestartMuts syncMutexMap // folder -> restart mutex
  127. folderVersioners map[string]versioner.Versioner // folder -> versioner (may be nil)
  128. folderEncryptionPasswordTokens map[string][]byte // folder -> encryption token (may be missing, and only for encryption type folders)
  129. folderEncryptionFailures map[string]map[protocol.DeviceID]error // folder -> device -> error regarding encryption consistency (may be missing)
  130. // fields protected by pmut
  131. pmut sync.RWMutex
  132. conn map[protocol.DeviceID]protocol.Connection
  133. connRequestLimiters map[protocol.DeviceID]*byteSemaphore
  134. closed map[protocol.DeviceID]chan struct{}
  135. helloMessages map[protocol.DeviceID]protocol.Hello
  136. deviceDownloads map[protocol.DeviceID]*deviceDownloadState
  137. remotePausedFolders map[protocol.DeviceID]map[string]struct{} // deviceID -> folders
  138. indexSenders map[protocol.DeviceID]*indexSenderRegistry
  139. // for testing only
  140. foldersRunning int32
  141. started chan struct{}
  142. }
  143. type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, events.Logger, *byteSemaphore) service
  144. var (
  145. folderFactories = make(map[config.FolderType]folderFactory)
  146. )
  147. var (
  148. errDeviceUnknown = errors.New("unknown device")
  149. errDevicePaused = errors.New("device is paused")
  150. errDeviceIgnored = errors.New("device is ignored")
  151. errDeviceRemoved = errors.New("device has been removed")
  152. ErrFolderPaused = errors.New("folder is paused")
  153. errFolderNotRunning = errors.New("folder is not running")
  154. errFolderMissing = errors.New("no such folder")
  155. errNetworkNotAllowed = errors.New("network not allowed")
  156. errNoVersioner = errors.New("folder has no versioner")
  157. // errors about why a connection is closed
  158. errIgnoredFolderRemoved = errors.New("folder no longer ignored")
  159. errReplacingConnection = errors.New("replacing connection")
  160. errStopped = errors.New("Syncthing is being stopped")
  161. errEncryptionInvConfigLocal = errors.New("can't encrypt data for a device when the folder type is receiveEncrypted")
  162. errEncryptionInvConfigRemote = errors.New("remote has encrypted data and encrypts that data for us - this is impossible")
  163. errEncryptionNotEncryptedLocal = errors.New("folder is announced as encrypted, but not configured thus")
  164. errEncryptionNotEncryptedRemote = errors.New("folder is configured to be encrypted but not announced thus")
  165. errEncryptionNotEncryptedUntrusted = errors.New("device is untrusted, but configured to receive not encrypted data")
  166. errEncryptionPassword = errors.New("different encryption passwords used")
  167. errEncryptionReceivedToken = errors.New("resetting connection to send info on new encrypted folder (new cluster config)")
  168. errMissingRemoteInClusterConfig = errors.New("remote device missing in cluster config")
  169. errMissingLocalInClusterConfig = errors.New("local device missing in cluster config")
  170. )
  171. // NewModel creates and starts a new model. The model starts in read-only mode,
  172. // where it sends index information to connected peers and responds to requests
  173. // for file data without altering the local folder in any way.
  174. func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string, evLogger events.Logger) Model {
  175. spec := svcutil.SpecWithDebugLogger(l)
  176. m := &model{
  177. Supervisor: suture.New("model", spec),
  178. // constructor parameters
  179. cfg: cfg,
  180. id: id,
  181. clientName: clientName,
  182. clientVersion: clientVersion,
  183. db: ldb,
  184. protectedFiles: protectedFiles,
  185. evLogger: evLogger,
  186. // constant or concurrency safe fields
  187. finder: db.NewBlockFinder(ldb),
  188. progressEmitter: NewProgressEmitter(cfg, evLogger),
  189. shortID: id.Short(),
  190. globalRequestLimiter: newByteSemaphore(1024 * cfg.Options().MaxConcurrentIncomingRequestKiB()),
  191. folderIOLimiter: newByteSemaphore(cfg.Options().MaxFolderConcurrency()),
  192. fatalChan: make(chan error),
  193. // fields protected by fmut
  194. fmut: sync.NewRWMutex(),
  195. folderCfgs: make(map[string]config.FolderConfiguration),
  196. folderFiles: make(map[string]*db.FileSet),
  197. deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
  198. folderIgnores: make(map[string]*ignore.Matcher),
  199. folderRunners: make(map[string]service),
  200. folderRunnerToken: make(map[string]suture.ServiceToken),
  201. folderVersioners: make(map[string]versioner.Versioner),
  202. folderEncryptionPasswordTokens: make(map[string][]byte),
  203. folderEncryptionFailures: make(map[string]map[protocol.DeviceID]error),
  204. // fields protected by pmut
  205. pmut: sync.NewRWMutex(),
  206. conn: make(map[protocol.DeviceID]protocol.Connection),
  207. connRequestLimiters: make(map[protocol.DeviceID]*byteSemaphore),
  208. closed: make(map[protocol.DeviceID]chan struct{}),
  209. helloMessages: make(map[protocol.DeviceID]protocol.Hello),
  210. deviceDownloads: make(map[protocol.DeviceID]*deviceDownloadState),
  211. remotePausedFolders: make(map[protocol.DeviceID]map[string]struct{}),
  212. indexSenders: make(map[protocol.DeviceID]*indexSenderRegistry),
  213. // for testing only
  214. started: make(chan struct{}),
  215. }
  216. for devID := range cfg.Devices() {
  217. m.deviceStatRefs[devID] = stats.NewDeviceStatisticsReference(m.db, devID.String())
  218. }
  219. m.Add(m.progressEmitter)
  220. m.Add(svcutil.AsService(m.serve, m.String()))
  221. return m
  222. }
  223. func (m *model) serve(ctx context.Context) error {
  224. defer m.closeAllConnectionsAndWait()
  225. m.cfg.Subscribe(m)
  226. defer m.cfg.Unsubscribe(m)
  227. if err := m.initFolders(); err != nil {
  228. close(m.started)
  229. return svcutil.AsFatalErr(err, svcutil.ExitError)
  230. }
  231. close(m.started)
  232. select {
  233. case <-ctx.Done():
  234. return ctx.Err()
  235. case err := <-m.fatalChan:
  236. return svcutil.AsFatalErr(err, svcutil.ExitError)
  237. }
  238. }
  239. func (m *model) initFolders() error {
  240. cacheIgnoredFiles := m.cfg.Options().CacheIgnoredFiles
  241. existingDevices := m.cfg.Devices()
  242. existingFolders := m.cfg.Folders()
  243. clusterConfigDevices := make(deviceIDSet, len(existingDevices))
  244. for _, folderCfg := range existingFolders {
  245. if folderCfg.Paused {
  246. folderCfg.CreateRoot()
  247. continue
  248. }
  249. err := m.newFolder(folderCfg, cacheIgnoredFiles)
  250. if err != nil {
  251. return err
  252. }
  253. clusterConfigDevices.add(folderCfg.DeviceIDs())
  254. }
  255. ignoredDevices := observedDeviceSet(m.cfg.IgnoredDevices())
  256. m.cleanPending(existingDevices, existingFolders, ignoredDevices, nil)
  257. m.resendClusterConfig(clusterConfigDevices.AsSlice())
  258. return nil
  259. }
  260. func (m *model) closeAllConnectionsAndWait() {
  261. m.pmut.RLock()
  262. closed := make([]chan struct{}, 0, len(m.conn))
  263. for id, conn := range m.conn {
  264. closed = append(closed, m.closed[id])
  265. go conn.Close(errStopped)
  266. }
  267. m.pmut.RUnlock()
  268. for _, c := range closed {
  269. <-c
  270. }
  271. }
  272. func (m *model) fatal(err error) {
  273. select {
  274. case m.fatalChan <- err:
  275. default:
  276. }
  277. }
  278. // StartDeadlockDetector starts a deadlock detector on the models locks which
  279. // causes panics in case the locks cannot be acquired in the given timeout
  280. // period.
  281. func (m *model) StartDeadlockDetector(timeout time.Duration) {
  282. l.Infof("Starting deadlock detector with %v timeout", timeout)
  283. detector := newDeadlockDetector(timeout)
  284. detector.Watch("fmut", m.fmut)
  285. detector.Watch("pmut", m.pmut)
  286. }
  287. // Need to hold lock on m.fmut when calling this.
  288. func (m *model) addAndStartFolderLocked(cfg config.FolderConfiguration, fset *db.FileSet, cacheIgnoredFiles bool) {
  289. ignores := ignore.New(cfg.Filesystem(), ignore.WithCache(cacheIgnoredFiles))
  290. if err := ignores.Load(".stignore"); err != nil && !fs.IsNotExist(err) {
  291. l.Warnln("Loading ignores:", err)
  292. }
  293. m.addAndStartFolderLockedWithIgnores(cfg, fset, ignores)
  294. }
  295. // Only needed for testing, use addAndStartFolderLocked instead.
  296. func (m *model) addAndStartFolderLockedWithIgnores(cfg config.FolderConfiguration, fset *db.FileSet, ignores *ignore.Matcher) {
  297. m.folderCfgs[cfg.ID] = cfg
  298. m.folderFiles[cfg.ID] = fset
  299. m.folderIgnores[cfg.ID] = ignores
  300. _, ok := m.folderRunners[cfg.ID]
  301. if ok {
  302. l.Warnln("Cannot start already running folder", cfg.Description())
  303. panic("cannot start already running folder")
  304. }
  305. folderFactory, ok := folderFactories[cfg.Type]
  306. if !ok {
  307. panic(fmt.Sprintf("unknown folder type 0x%x", cfg.Type))
  308. }
  309. folder := cfg.ID
  310. // Find any devices for which we hold the index in the db, but the folder
  311. // is not shared, and drop it.
  312. expected := mapDevices(cfg.DeviceIDs())
  313. for _, available := range fset.ListDevices() {
  314. if _, ok := expected[available]; !ok {
  315. l.Debugln("dropping", folder, "state for", available)
  316. fset.Drop(available)
  317. }
  318. }
  319. v, ok := fset.Sequence(protocol.LocalDeviceID), true
  320. indexHasFiles := ok && v > 0
  321. if !indexHasFiles {
  322. // It's a blank folder, so this may the first time we're looking at
  323. // it. Attempt to create and tag with our marker as appropriate. We
  324. // don't really do anything with errors at this point except warn -
  325. // if these things don't work, we still want to start the folder and
  326. // it'll show up as errored later.
  327. if err := cfg.CreateRoot(); err != nil {
  328. l.Warnln("Failed to create folder root directory", err)
  329. } else if err = cfg.CreateMarker(); err != nil {
  330. l.Warnln("Failed to create folder marker:", err)
  331. }
  332. }
  333. if cfg.Type == config.FolderTypeReceiveEncrypted {
  334. if encryptionToken, err := readEncryptionToken(cfg); err == nil {
  335. m.folderEncryptionPasswordTokens[folder] = encryptionToken
  336. } else if !fs.IsNotExist(err) {
  337. l.Warnf("Failed to read encryption token: %v", err)
  338. }
  339. }
  340. // These are our metadata files, and they should always be hidden.
  341. ffs := cfg.Filesystem()
  342. _ = ffs.Hide(config.DefaultMarkerName)
  343. _ = ffs.Hide(".stversions")
  344. _ = ffs.Hide(".stignore")
  345. var ver versioner.Versioner
  346. if cfg.Versioning.Type != "" {
  347. var err error
  348. ver, err = versioner.New(cfg)
  349. if err != nil {
  350. panic(fmt.Errorf("creating versioner: %w", err))
  351. }
  352. }
  353. m.folderVersioners[folder] = ver
  354. p := folderFactory(m, fset, ignores, cfg, ver, m.evLogger, m.folderIOLimiter)
  355. m.folderRunners[folder] = p
  356. m.warnAboutOverwritingProtectedFiles(cfg, ignores)
  357. m.folderRunnerToken[folder] = m.Add(p)
  358. l.Infof("Ready to synchronize %s (%s)", cfg.Description(), cfg.Type)
  359. }
  360. func (m *model) warnAboutOverwritingProtectedFiles(cfg config.FolderConfiguration, ignores *ignore.Matcher) {
  361. if cfg.Type == config.FolderTypeSendOnly {
  362. return
  363. }
  364. // This is a bit of a hack.
  365. ffs := cfg.Filesystem()
  366. if ffs.Type() != fs.FilesystemTypeBasic {
  367. return
  368. }
  369. folderLocation := ffs.URI()
  370. var filesAtRisk []string
  371. for _, protectedFilePath := range m.protectedFiles {
  372. // check if file is synced in this folder
  373. if protectedFilePath != folderLocation && !fs.IsParent(protectedFilePath, folderLocation) {
  374. continue
  375. }
  376. // check if file is ignored
  377. relPath, _ := filepath.Rel(folderLocation, protectedFilePath)
  378. if ignores.Match(relPath).IsIgnored() {
  379. continue
  380. }
  381. filesAtRisk = append(filesAtRisk, protectedFilePath)
  382. }
  383. if len(filesAtRisk) > 0 {
  384. l.Warnln("Some protected files may be overwritten and cause issues. See https://docs.syncthing.net/users/config.html#syncing-configuration-files for more information. The at risk files are:", strings.Join(filesAtRisk, ", "))
  385. }
  386. }
  387. func (m *model) removeFolder(cfg config.FolderConfiguration) {
  388. m.fmut.RLock()
  389. token, ok := m.folderRunnerToken[cfg.ID]
  390. m.fmut.RUnlock()
  391. if ok {
  392. m.RemoveAndWait(token, 0)
  393. }
  394. // We need to hold both fmut and pmut and must acquire locks in the same
  395. // order always. (The locks can be *released* in any order.)
  396. m.fmut.Lock()
  397. m.pmut.RLock()
  398. isPathUnique := true
  399. for folderID, folderCfg := range m.folderCfgs {
  400. if folderID != cfg.ID && folderCfg.Path == cfg.Path {
  401. isPathUnique = false
  402. break
  403. }
  404. }
  405. if isPathUnique {
  406. // Delete syncthing specific files
  407. cfg.Filesystem().RemoveAll(config.DefaultMarkerName)
  408. }
  409. m.cleanupFolderLocked(cfg)
  410. for _, r := range m.indexSenders {
  411. r.remove(cfg.ID)
  412. }
  413. m.fmut.Unlock()
  414. m.pmut.RUnlock()
  415. // Remove it from the database
  416. db.DropFolder(m.db, cfg.ID)
  417. }
  418. // Need to hold lock on m.fmut when calling this.
  419. func (m *model) cleanupFolderLocked(cfg config.FolderConfiguration) {
  420. // clear up our config maps
  421. delete(m.folderCfgs, cfg.ID)
  422. delete(m.folderFiles, cfg.ID)
  423. delete(m.folderIgnores, cfg.ID)
  424. delete(m.folderRunners, cfg.ID)
  425. delete(m.folderRunnerToken, cfg.ID)
  426. delete(m.folderVersioners, cfg.ID)
  427. }
  428. func (m *model) restartFolder(from, to config.FolderConfiguration, cacheIgnoredFiles bool) error {
  429. if len(to.ID) == 0 {
  430. panic("bug: cannot restart empty folder ID")
  431. }
  432. if to.ID != from.ID {
  433. l.Warnf("bug: folder restart cannot change ID %q -> %q", from.ID, to.ID)
  434. panic("bug: folder restart cannot change ID")
  435. }
  436. folder := to.ID
  437. // This mutex protects the entirety of the restart operation, preventing
  438. // there from being more than one folder restart operation in progress
  439. // at any given time. The usual fmut/pmut stuff doesn't cover this,
  440. // because those locks are released while we are waiting for the folder
  441. // to shut down (and must be so because the folder might need them as
  442. // part of its operations before shutting down).
  443. restartMut := m.folderRestartMuts.Get(folder)
  444. restartMut.Lock()
  445. defer restartMut.Unlock()
  446. m.fmut.RLock()
  447. token, ok := m.folderRunnerToken[from.ID]
  448. m.fmut.RUnlock()
  449. if ok {
  450. m.RemoveAndWait(token, 0)
  451. }
  452. m.fmut.Lock()
  453. defer m.fmut.Unlock()
  454. // Cache the (maybe) existing fset before it's removed by cleanupFolderLocked
  455. fset := m.folderFiles[folder]
  456. fsetNil := fset == nil
  457. m.cleanupFolderLocked(from)
  458. if !to.Paused {
  459. if fsetNil {
  460. // Create a new fset. Might take a while and we do it under
  461. // locking, but it's unsafe to create fset:s concurrently so
  462. // that's the price we pay.
  463. var err error
  464. fset, err = db.NewFileSet(folder, to.Filesystem(), m.db)
  465. if err != nil {
  466. return fmt.Errorf("restarting %v: %w", to.Description(), err)
  467. }
  468. }
  469. m.addAndStartFolderLocked(to, fset, cacheIgnoredFiles)
  470. }
  471. // Care needs to be taken because we already hold fmut and the lock order
  472. // must be the same everywhere. As fmut is acquired first, this is fine.
  473. // toDeviceIDs := to.DeviceIDs()
  474. m.pmut.RLock()
  475. for _, id := range to.DeviceIDs() {
  476. indexSenders, ok := m.indexSenders[id]
  477. if !ok {
  478. continue
  479. }
  480. // In case the folder was newly shared with us we already got a
  481. // cluster config and wont necessarily get another soon - start
  482. // sending indexes if connected.
  483. if to.Paused {
  484. indexSenders.pause(to.ID)
  485. } else if !from.SharedWith(indexSenders.deviceID) || fsetNil || from.Paused {
  486. indexSenders.resume(to, fset)
  487. }
  488. }
  489. m.pmut.RUnlock()
  490. var infoMsg string
  491. switch {
  492. case to.Paused:
  493. infoMsg = "Paused"
  494. case from.Paused:
  495. infoMsg = "Unpaused"
  496. default:
  497. infoMsg = "Restarted"
  498. }
  499. l.Infof("%v folder %v (%v)", infoMsg, to.Description(), to.Type)
  500. return nil
  501. }
  502. func (m *model) newFolder(cfg config.FolderConfiguration, cacheIgnoredFiles bool) error {
  503. // Creating the fileset can take a long time (metadata calculation) so
  504. // we do it outside of the lock.
  505. fset, err := db.NewFileSet(cfg.ID, cfg.Filesystem(), m.db)
  506. if err != nil {
  507. return fmt.Errorf("adding %v: %w", cfg.Description(), err)
  508. }
  509. m.fmut.Lock()
  510. defer m.fmut.Unlock()
  511. // Cluster configs might be received and processed before reaching this
  512. // point, i.e. before the folder is started. If that's the case, start
  513. // index senders here.
  514. m.pmut.RLock()
  515. for _, id := range cfg.DeviceIDs() {
  516. if is, ok := m.indexSenders[id]; ok {
  517. is.resume(cfg, fset)
  518. }
  519. }
  520. m.pmut.RUnlock()
  521. m.addAndStartFolderLocked(cfg, fset, cacheIgnoredFiles)
  522. return nil
  523. }
  524. func (m *model) UsageReportingStats(report *contract.Report, version int, preview bool) {
  525. if version >= 3 {
  526. // Block stats
  527. blockStatsMut.Lock()
  528. for k, v := range blockStats {
  529. switch k {
  530. case "total":
  531. report.BlockStats.Total = v
  532. case "renamed":
  533. report.BlockStats.Renamed = v
  534. case "reused":
  535. report.BlockStats.Reused = v
  536. case "pulled":
  537. report.BlockStats.Pulled = v
  538. case "copyOrigin":
  539. report.BlockStats.CopyOrigin = v
  540. case "copyOriginShifted":
  541. report.BlockStats.CopyOriginShifted = v
  542. case "copyElsewhere":
  543. report.BlockStats.CopyElsewhere = v
  544. }
  545. // Reset counts, as these are incremental
  546. if !preview {
  547. blockStats[k] = 0
  548. }
  549. }
  550. blockStatsMut.Unlock()
  551. // Transport stats
  552. m.pmut.RLock()
  553. for _, conn := range m.conn {
  554. report.TransportStats[conn.Transport()]++
  555. }
  556. m.pmut.RUnlock()
  557. // Ignore stats
  558. var seenPrefix [3]bool
  559. for folder := range m.cfg.Folders() {
  560. lines, _, err := m.GetIgnores(folder)
  561. if err != nil {
  562. continue
  563. }
  564. report.IgnoreStats.Lines += len(lines)
  565. for _, line := range lines {
  566. // Allow prefixes to be specified in any order, but only once.
  567. for {
  568. if strings.HasPrefix(line, "!") && !seenPrefix[0] {
  569. seenPrefix[0] = true
  570. line = line[1:]
  571. report.IgnoreStats.Inverts++
  572. } else if strings.HasPrefix(line, "(?i)") && !seenPrefix[1] {
  573. seenPrefix[1] = true
  574. line = line[4:]
  575. report.IgnoreStats.Folded++
  576. } else if strings.HasPrefix(line, "(?d)") && !seenPrefix[2] {
  577. seenPrefix[2] = true
  578. line = line[4:]
  579. report.IgnoreStats.Deletable++
  580. } else {
  581. seenPrefix[0] = false
  582. seenPrefix[1] = false
  583. seenPrefix[2] = false
  584. break
  585. }
  586. }
  587. // Noops, remove
  588. line = strings.TrimSuffix(line, "**")
  589. line = strings.TrimPrefix(line, "**/")
  590. if strings.HasPrefix(line, "/") {
  591. report.IgnoreStats.Rooted++
  592. } else if strings.HasPrefix(line, "#include ") {
  593. report.IgnoreStats.Includes++
  594. if strings.Contains(line, "..") {
  595. report.IgnoreStats.EscapedIncludes++
  596. }
  597. }
  598. if strings.Contains(line, "**") {
  599. report.IgnoreStats.DoubleStars++
  600. // Remove not to trip up star checks.
  601. line = strings.Replace(line, "**", "", -1)
  602. }
  603. if strings.Contains(line, "*") {
  604. report.IgnoreStats.Stars++
  605. }
  606. }
  607. }
  608. }
  609. }
  610. type ConnectionInfo struct {
  611. protocol.Statistics
  612. Connected bool
  613. Paused bool
  614. Address string
  615. ClientVersion string
  616. Type string
  617. Crypto string
  618. }
  619. func (info ConnectionInfo) MarshalJSON() ([]byte, error) {
  620. return json.Marshal(map[string]interface{}{
  621. "at": info.At,
  622. "inBytesTotal": info.InBytesTotal,
  623. "outBytesTotal": info.OutBytesTotal,
  624. "connected": info.Connected,
  625. "paused": info.Paused,
  626. "address": info.Address,
  627. "clientVersion": info.ClientVersion,
  628. "type": info.Type,
  629. "crypto": info.Crypto,
  630. })
  631. }
  632. // ConnectionStats returns a map with connection statistics for each device.
  633. func (m *model) ConnectionStats() map[string]interface{} {
  634. m.pmut.RLock()
  635. defer m.pmut.RUnlock()
  636. res := make(map[string]interface{})
  637. devs := m.cfg.Devices()
  638. conns := make(map[string]ConnectionInfo, len(devs))
  639. for device, deviceCfg := range devs {
  640. hello := m.helloMessages[device]
  641. versionString := hello.ClientVersion
  642. if hello.ClientName != "syncthing" {
  643. versionString = hello.ClientName + " " + hello.ClientVersion
  644. }
  645. ci := ConnectionInfo{
  646. ClientVersion: strings.TrimSpace(versionString),
  647. Paused: deviceCfg.Paused,
  648. }
  649. if conn, ok := m.conn[device]; ok {
  650. ci.Type = conn.Type()
  651. ci.Crypto = conn.Crypto()
  652. ci.Connected = ok
  653. ci.Statistics = conn.Statistics()
  654. if addr := conn.RemoteAddr(); addr != nil {
  655. ci.Address = addr.String()
  656. }
  657. }
  658. conns[device.String()] = ci
  659. }
  660. res["connections"] = conns
  661. in, out := protocol.TotalInOut()
  662. res["total"] = ConnectionInfo{
  663. Statistics: protocol.Statistics{
  664. At: time.Now(),
  665. InBytesTotal: in,
  666. OutBytesTotal: out,
  667. },
  668. }
  669. return res
  670. }
  671. // DeviceStatistics returns statistics about each device
  672. func (m *model) DeviceStatistics() (map[string]stats.DeviceStatistics, error) {
  673. m.fmut.RLock()
  674. defer m.fmut.RUnlock()
  675. res := make(map[string]stats.DeviceStatistics, len(m.deviceStatRefs))
  676. for id, sr := range m.deviceStatRefs {
  677. stats, err := sr.GetStatistics()
  678. if err != nil {
  679. return nil, err
  680. }
  681. res[id.String()] = stats
  682. }
  683. return res, nil
  684. }
  685. // FolderStatistics returns statistics about each folder
  686. func (m *model) FolderStatistics() (map[string]stats.FolderStatistics, error) {
  687. res := make(map[string]stats.FolderStatistics)
  688. m.fmut.RLock()
  689. defer m.fmut.RUnlock()
  690. for id, runner := range m.folderRunners {
  691. stats, err := runner.GetStatistics()
  692. if err != nil {
  693. return nil, err
  694. }
  695. res[id] = stats
  696. }
  697. return res, nil
  698. }
  699. type FolderCompletion struct {
  700. CompletionPct float64
  701. GlobalBytes int64
  702. NeedBytes int64
  703. GlobalItems int
  704. NeedItems int
  705. NeedDeletes int
  706. Sequence int64
  707. }
  708. func newFolderCompletion(global, need db.Counts, sequence int64) FolderCompletion {
  709. comp := FolderCompletion{
  710. GlobalBytes: global.Bytes,
  711. NeedBytes: need.Bytes,
  712. GlobalItems: global.Files + global.Directories + global.Symlinks,
  713. NeedItems: need.Files + need.Directories + need.Symlinks,
  714. NeedDeletes: need.Deleted,
  715. Sequence: sequence,
  716. }
  717. comp.setComplectionPct()
  718. return comp
  719. }
  720. func (comp *FolderCompletion) add(other FolderCompletion) {
  721. comp.GlobalBytes += other.GlobalBytes
  722. comp.NeedBytes += other.NeedBytes
  723. comp.GlobalItems += other.GlobalItems
  724. comp.NeedItems += other.NeedItems
  725. comp.NeedDeletes += other.NeedDeletes
  726. comp.setComplectionPct()
  727. }
  728. func (comp *FolderCompletion) setComplectionPct() {
  729. if comp.GlobalBytes == 0 {
  730. comp.CompletionPct = 100
  731. } else {
  732. needRatio := float64(comp.NeedBytes) / float64(comp.GlobalBytes)
  733. comp.CompletionPct = 100 * (1 - needRatio)
  734. }
  735. // If the completion is 100% but there are deletes we need to handle,
  736. // drop it down a notch. Hack for consumers that look only at the
  737. // percentage (our own GUI does the same calculation as here on its own
  738. // and needs the same fixup).
  739. if comp.NeedBytes == 0 && comp.NeedDeletes > 0 {
  740. comp.CompletionPct = 95 // chosen by fair dice roll
  741. }
  742. }
  743. // Map returns the members as a map, e.g. used in api to serialize as Json.
  744. func (comp FolderCompletion) Map() map[string]interface{} {
  745. return map[string]interface{}{
  746. "completion": comp.CompletionPct,
  747. "globalBytes": comp.GlobalBytes,
  748. "needBytes": comp.NeedBytes,
  749. "globalItems": comp.GlobalItems,
  750. "needItems": comp.NeedItems,
  751. "needDeletes": comp.NeedDeletes,
  752. "sequence": comp.Sequence,
  753. }
  754. }
  755. // Completion returns the completion status, in percent with some counters,
  756. // for the given device and folder. The device can be any known device ID
  757. // (including the local device) or explicitly protocol.LocalDeviceID. An
  758. // empty folder string means the aggregate of all folders shared with the
  759. // given device.
  760. func (m *model) Completion(device protocol.DeviceID, folder string) FolderCompletion {
  761. // The user specifically asked for our own device ID. Internally that is
  762. // known as protocol.LocalDeviceID so translate.
  763. if device == m.id {
  764. device = protocol.LocalDeviceID
  765. }
  766. if folder != "" {
  767. // We want completion for a specific folder.
  768. return m.folderCompletion(device, folder)
  769. }
  770. // We want completion for all (shared) folders as an aggregate.
  771. var comp FolderCompletion
  772. for _, fcfg := range m.cfg.FolderList() {
  773. if device == protocol.LocalDeviceID || fcfg.SharedWith(device) {
  774. comp.add(m.folderCompletion(device, fcfg.ID))
  775. }
  776. }
  777. return comp
  778. }
  779. func (m *model) folderCompletion(device protocol.DeviceID, folder string) FolderCompletion {
  780. m.fmut.RLock()
  781. rf, ok := m.folderFiles[folder]
  782. m.fmut.RUnlock()
  783. if !ok {
  784. return FolderCompletion{} // Folder doesn't exist, so we hardly have any of it
  785. }
  786. snap := rf.Snapshot()
  787. defer snap.Release()
  788. m.pmut.RLock()
  789. downloaded := m.deviceDownloads[device].BytesDownloaded(folder)
  790. m.pmut.RUnlock()
  791. need := snap.NeedSize(device)
  792. need.Bytes -= downloaded
  793. // This might might be more than it really is, because some blocks can be of a smaller size.
  794. if need.Bytes < 0 {
  795. need.Bytes = 0
  796. }
  797. comp := newFolderCompletion(snap.GlobalSize(), need, snap.Sequence(device))
  798. l.Debugf("%v Completion(%s, %q): %v", m, device, folder, comp.Map())
  799. return comp
  800. }
  801. // DBSnapshot returns a snapshot of the database content relevant to the given folder.
  802. func (m *model) DBSnapshot(folder string) (*db.Snapshot, error) {
  803. m.fmut.RLock()
  804. err := m.checkFolderRunningLocked(folder)
  805. rf := m.folderFiles[folder]
  806. m.fmut.RUnlock()
  807. if err != nil {
  808. return nil, err
  809. }
  810. return rf.Snapshot(), nil
  811. }
  812. func (m *model) FolderProgressBytesCompleted(folder string) int64 {
  813. return m.progressEmitter.BytesCompleted(folder)
  814. }
  815. // NeedFolderFiles returns paginated list of currently needed files in
  816. // progress, queued, and to be queued on next puller iteration.
  817. func (m *model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, error) {
  818. m.fmut.RLock()
  819. rf, rfOk := m.folderFiles[folder]
  820. runner, runnerOk := m.folderRunners[folder]
  821. cfg := m.folderCfgs[folder]
  822. m.fmut.RUnlock()
  823. if !rfOk {
  824. return nil, nil, nil, errFolderMissing
  825. }
  826. snap := rf.Snapshot()
  827. defer snap.Release()
  828. var progress, queued, rest []db.FileInfoTruncated
  829. var seen map[string]struct{}
  830. p := newPager(page, perpage)
  831. if runnerOk {
  832. progressNames, queuedNames, skipped := runner.Jobs(page, perpage)
  833. progress = make([]db.FileInfoTruncated, len(progressNames))
  834. queued = make([]db.FileInfoTruncated, len(queuedNames))
  835. seen = make(map[string]struct{}, len(progressNames)+len(queuedNames))
  836. for i, name := range progressNames {
  837. if f, ok := snap.GetGlobalTruncated(name); ok {
  838. progress[i] = f
  839. seen[name] = struct{}{}
  840. }
  841. }
  842. for i, name := range queuedNames {
  843. if f, ok := snap.GetGlobalTruncated(name); ok {
  844. queued[i] = f
  845. seen[name] = struct{}{}
  846. }
  847. }
  848. p.get -= len(seen)
  849. if p.get == 0 {
  850. return progress, queued, nil, nil
  851. }
  852. p.toSkip -= skipped
  853. }
  854. rest = make([]db.FileInfoTruncated, 0, perpage)
  855. snap.WithNeedTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
  856. if cfg.IgnoreDelete && f.IsDeleted() {
  857. return true
  858. }
  859. if p.skip() {
  860. return true
  861. }
  862. ft := f.(db.FileInfoTruncated)
  863. if _, ok := seen[ft.Name]; !ok {
  864. rest = append(rest, ft)
  865. p.get--
  866. }
  867. return p.get > 0
  868. })
  869. return progress, queued, rest, nil
  870. }
  871. // RemoteNeedFolderFiles returns paginated list of currently needed files in
  872. // progress, queued, and to be queued on next puller iteration, as well as the
  873. // total number of files currently needed.
  874. func (m *model) RemoteNeedFolderFiles(folder string, device protocol.DeviceID, page, perpage int) ([]db.FileInfoTruncated, error) {
  875. m.fmut.RLock()
  876. rf, ok := m.folderFiles[folder]
  877. m.fmut.RUnlock()
  878. if !ok {
  879. return nil, errFolderMissing
  880. }
  881. snap := rf.Snapshot()
  882. defer snap.Release()
  883. files := make([]db.FileInfoTruncated, 0, perpage)
  884. p := newPager(page, perpage)
  885. snap.WithNeedTruncated(device, func(f protocol.FileIntf) bool {
  886. if p.skip() {
  887. return true
  888. }
  889. files = append(files, f.(db.FileInfoTruncated))
  890. return !p.done()
  891. })
  892. return files, nil
  893. }
  894. func (m *model) LocalChangedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, error) {
  895. m.fmut.RLock()
  896. rf, ok := m.folderFiles[folder]
  897. cfg := m.folderCfgs[folder]
  898. m.fmut.RUnlock()
  899. if !ok {
  900. return nil, errFolderMissing
  901. }
  902. snap := rf.Snapshot()
  903. defer snap.Release()
  904. if snap.ReceiveOnlyChangedSize().TotalItems() == 0 {
  905. return nil, nil
  906. }
  907. p := newPager(page, perpage)
  908. recvEnc := cfg.Type == config.FolderTypeReceiveEncrypted
  909. files := make([]db.FileInfoTruncated, 0, perpage)
  910. snap.WithHaveTruncated(protocol.LocalDeviceID, func(f protocol.FileIntf) bool {
  911. if !f.IsReceiveOnlyChanged() || (recvEnc && f.IsDeleted()) {
  912. return true
  913. }
  914. if p.skip() {
  915. return true
  916. }
  917. ft := f.(db.FileInfoTruncated)
  918. files = append(files, ft)
  919. return !p.done()
  920. })
  921. return files, nil
  922. }
  923. type pager struct {
  924. toSkip, get int
  925. }
  926. func newPager(page, perpage int) *pager {
  927. return &pager{
  928. toSkip: (page - 1) * perpage,
  929. get: perpage,
  930. }
  931. }
  932. func (p *pager) skip() bool {
  933. if p.toSkip == 0 {
  934. return false
  935. }
  936. p.toSkip--
  937. return true
  938. }
  939. func (p *pager) done() bool {
  940. if p.get > 0 {
  941. p.get--
  942. }
  943. return p.get == 0
  944. }
  945. // Index is called when a new device is connected and we receive their full index.
  946. // Implements the protocol.Model interface.
  947. func (m *model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) error {
  948. return m.handleIndex(deviceID, folder, fs, false)
  949. }
  950. // IndexUpdate is called for incremental updates to connected devices' indexes.
  951. // Implements the protocol.Model interface.
  952. func (m *model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo) error {
  953. return m.handleIndex(deviceID, folder, fs, true)
  954. }
  955. func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []protocol.FileInfo, update bool) error {
  956. op := "Index"
  957. if update {
  958. op += " update"
  959. }
  960. l.Debugf("%v (in): %s / %q: %d files", op, deviceID, folder, len(fs))
  961. if cfg, ok := m.cfg.Folder(folder); !ok || !cfg.SharedWith(deviceID) {
  962. l.Infof("%v for unexpected folder ID %q sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", op, folder, deviceID)
  963. return errors.Wrap(errFolderMissing, folder)
  964. } else if cfg.Paused {
  965. l.Debugf("%v for paused folder (ID %q) sent from device %q.", op, folder, deviceID)
  966. return errors.Wrap(ErrFolderPaused, folder)
  967. }
  968. m.fmut.RLock()
  969. files, existing := m.folderFiles[folder]
  970. runner, running := m.folderRunners[folder]
  971. m.fmut.RUnlock()
  972. if !existing {
  973. l.Infof("%v for nonexistent folder %q", op, folder)
  974. return errors.Wrap(errFolderMissing, folder)
  975. }
  976. if running {
  977. defer runner.SchedulePull()
  978. }
  979. m.pmut.RLock()
  980. downloads := m.deviceDownloads[deviceID]
  981. m.pmut.RUnlock()
  982. downloads.Update(folder, makeForgetUpdate(fs))
  983. if !update {
  984. files.Drop(deviceID)
  985. }
  986. for i := range fs {
  987. // The local attributes should never be transmitted over the wire.
  988. // Make sure they look like they weren't.
  989. fs[i].LocalFlags = 0
  990. fs[i].VersionHash = nil
  991. }
  992. files.Update(deviceID, fs)
  993. seq := files.Sequence(deviceID)
  994. m.evLogger.Log(events.RemoteIndexUpdated, map[string]interface{}{
  995. "device": deviceID.String(),
  996. "folder": folder,
  997. "items": len(fs),
  998. "sequence": seq,
  999. "version": seq, // legacy for sequence
  1000. })
  1001. return nil
  1002. }
  1003. func (m *model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterConfig) error {
  1004. // Check the peer device's announced folders against our own. Emits events
  1005. // for folders that we don't expect (unknown or not shared).
  1006. // Also, collect a list of folders we do share, and if he's interested in
  1007. // temporary indexes, subscribe the connection.
  1008. m.pmut.RLock()
  1009. indexSenderRegistry, ok := m.indexSenders[deviceID]
  1010. m.pmut.RUnlock()
  1011. if !ok {
  1012. panic("bug: ClusterConfig called on closed or nonexistent connection")
  1013. }
  1014. changed := false
  1015. deviceCfg, ok := m.cfg.Device(deviceID)
  1016. if !ok {
  1017. l.Debugln("Device disappeared from config while processing cluster-config")
  1018. return errDeviceUnknown
  1019. }
  1020. // Assemble the device information from the connected device about
  1021. // themselves and us for all folders.
  1022. ccDeviceInfos := make(map[string]*indexSenderStartInfo, len(cm.Folders))
  1023. for _, folder := range cm.Folders {
  1024. info := &indexSenderStartInfo{}
  1025. for _, dev := range folder.Devices {
  1026. if dev.ID == m.id {
  1027. info.local = dev
  1028. } else if dev.ID == deviceID {
  1029. info.remote = dev
  1030. }
  1031. if info.local.ID != protocol.EmptyDeviceID && info.remote.ID != protocol.EmptyDeviceID {
  1032. break
  1033. }
  1034. }
  1035. if info.remote.ID == protocol.EmptyDeviceID {
  1036. l.Infof("Device %v sent cluster-config without the device info for the remote on folder %v", deviceID, folder.Description())
  1037. return errMissingRemoteInClusterConfig
  1038. }
  1039. if info.local.ID == protocol.EmptyDeviceID {
  1040. l.Infof("Device %v sent cluster-config without the device info for us locally on folder %v", deviceID, folder.Description())
  1041. return errMissingLocalInClusterConfig
  1042. }
  1043. ccDeviceInfos[folder.ID] = info
  1044. }
  1045. // Needs to happen outside of the fmut, as can cause CommitConfiguration
  1046. if deviceCfg.AutoAcceptFolders {
  1047. changedFolders := make([]config.FolderConfiguration, 0, len(cm.Folders))
  1048. for _, folder := range cm.Folders {
  1049. if fcfg, fchanged := m.handleAutoAccepts(deviceID, folder, ccDeviceInfos[folder.ID]); fchanged {
  1050. changedFolders = append(changedFolders, fcfg)
  1051. }
  1052. }
  1053. if len(changedFolders) > 0 {
  1054. // Need to wait for the waiter, as this calls CommitConfiguration,
  1055. // which sets up the folder and as we return from this call,
  1056. // ClusterConfig starts poking at m.folderFiles and other things
  1057. // that might not exist until the config is committed.
  1058. w, _ := m.cfg.SetFolders(changedFolders)
  1059. w.Wait()
  1060. changed = true
  1061. }
  1062. }
  1063. tempIndexFolders, paused, err := m.ccHandleFolders(cm.Folders, deviceCfg, ccDeviceInfos, indexSenderRegistry)
  1064. if err != nil {
  1065. return err
  1066. }
  1067. m.pmut.Lock()
  1068. m.remotePausedFolders[deviceID] = paused
  1069. m.pmut.Unlock()
  1070. if len(tempIndexFolders) > 0 {
  1071. m.pmut.RLock()
  1072. conn, ok := m.conn[deviceID]
  1073. m.pmut.RUnlock()
  1074. // In case we've got ClusterConfig, and the connection disappeared
  1075. // from infront of our nose.
  1076. if ok {
  1077. m.progressEmitter.temporaryIndexSubscribe(conn, tempIndexFolders)
  1078. }
  1079. }
  1080. if deviceCfg.Introducer {
  1081. folders, devices, foldersDevices, introduced := m.handleIntroductions(deviceCfg, cm)
  1082. folders, devices, deintroduced := m.handleDeintroductions(deviceCfg, foldersDevices, folders, devices)
  1083. if introduced || deintroduced {
  1084. changed = true
  1085. cfg := m.cfg.RawCopy()
  1086. cfg.Folders = make([]config.FolderConfiguration, 0, len(folders))
  1087. for _, fcfg := range folders {
  1088. cfg.Folders = append(cfg.Folders, fcfg)
  1089. }
  1090. cfg.Devices = make([]config.DeviceConfiguration, len(devices))
  1091. for _, dcfg := range devices {
  1092. cfg.Devices = append(cfg.Devices, dcfg)
  1093. }
  1094. m.cfg.Replace(cfg)
  1095. }
  1096. }
  1097. if changed {
  1098. if err := m.cfg.Save(); err != nil {
  1099. l.Warnln("Failed to save config", err)
  1100. }
  1101. }
  1102. return nil
  1103. }
  1104. func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.DeviceConfiguration, ccDeviceInfos map[string]*indexSenderStartInfo, indexSenders *indexSenderRegistry) ([]string, map[string]struct{}, error) {
  1105. var folderDevice config.FolderDeviceConfiguration
  1106. tempIndexFolders := make([]string, 0, len(folders))
  1107. paused := make(map[string]struct{}, len(folders))
  1108. seenFolders := make(map[string]struct{}, len(folders))
  1109. deviceID := deviceCfg.DeviceID
  1110. for _, folder := range folders {
  1111. seenFolders[folder.ID] = struct{}{}
  1112. cfg, ok := m.cfg.Folder(folder.ID)
  1113. if ok {
  1114. folderDevice, ok = cfg.Device(deviceID)
  1115. }
  1116. if !ok {
  1117. indexSenders.remove(folder.ID)
  1118. if deviceCfg.IgnoredFolder(folder.ID) {
  1119. l.Infof("Ignoring folder %s from device %s since we are configured to", folder.Description(), deviceID)
  1120. continue
  1121. }
  1122. if err := m.db.AddOrUpdatePendingFolder(folder.ID, folder.Label, deviceID); err != nil {
  1123. l.Warnf("Failed to persist pending folder entry to database: %v", err)
  1124. }
  1125. indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])
  1126. m.evLogger.Log(events.FolderRejected, map[string]string{
  1127. "folder": folder.ID,
  1128. "folderLabel": folder.Label,
  1129. "device": deviceID.String(),
  1130. })
  1131. l.Infof("Unexpected folder %s sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", folder.Description(), deviceID)
  1132. continue
  1133. }
  1134. if folder.Paused {
  1135. indexSenders.remove(folder.ID)
  1136. paused[cfg.ID] = struct{}{}
  1137. continue
  1138. }
  1139. if cfg.Paused {
  1140. indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])
  1141. continue
  1142. }
  1143. if err := m.ccCheckEncryption(cfg, folderDevice, ccDeviceInfos[folder.ID], deviceCfg.Untrusted); err != nil {
  1144. sameError := false
  1145. if devs, ok := m.folderEncryptionFailures[folder.ID]; ok {
  1146. sameError = devs[deviceID] == err
  1147. } else {
  1148. m.folderEncryptionFailures[folder.ID] = make(map[protocol.DeviceID]error)
  1149. }
  1150. m.folderEncryptionFailures[folder.ID][deviceID] = err
  1151. msg := fmt.Sprintf("Failure checking encryption consistency with device %v for folder %v: %v", deviceID, cfg.Description(), err)
  1152. if sameError || err == errEncryptionReceivedToken {
  1153. l.Debugln(msg)
  1154. } else {
  1155. l.Warnln(msg)
  1156. }
  1157. return tempIndexFolders, paused, err
  1158. }
  1159. if devErrs, ok := m.folderEncryptionFailures[folder.ID]; ok {
  1160. if len(devErrs) == 1 {
  1161. delete(m.folderEncryptionFailures, folder.ID)
  1162. } else {
  1163. delete(m.folderEncryptionFailures[folder.ID], deviceID)
  1164. }
  1165. }
  1166. // Handle indexes
  1167. if !folder.DisableTempIndexes {
  1168. tempIndexFolders = append(tempIndexFolders, folder.ID)
  1169. }
  1170. m.fmut.RLock()
  1171. fs, ok := m.folderFiles[folder.ID]
  1172. m.fmut.RUnlock()
  1173. if !ok {
  1174. // Shouldn't happen because !cfg.Paused, but might happen
  1175. // if the folder is about to be unpaused, but not yet.
  1176. l.Debugln("ccH: no fset", folder.ID)
  1177. indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])
  1178. continue
  1179. }
  1180. indexSenders.add(cfg, fs, ccDeviceInfos[folder.ID])
  1181. // We might already have files that we need to pull so let the
  1182. // folder runner know that it should recheck the index data.
  1183. m.fmut.RLock()
  1184. if runner := m.folderRunners[folder.ID]; runner != nil {
  1185. defer runner.SchedulePull()
  1186. }
  1187. m.fmut.RUnlock()
  1188. }
  1189. indexSenders.removeAllExcept(seenFolders)
  1190. return tempIndexFolders, paused, nil
  1191. }
  1192. func (m *model) ccCheckEncryption(fcfg config.FolderConfiguration, folderDevice config.FolderDeviceConfiguration, ccDeviceInfos *indexSenderStartInfo, deviceUntrusted bool) error {
  1193. hasTokenRemote := len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0
  1194. hasTokenLocal := len(ccDeviceInfos.local.EncryptionPasswordToken) > 0
  1195. isEncryptedRemote := folderDevice.EncryptionPassword != ""
  1196. isEncryptedLocal := fcfg.Type == config.FolderTypeReceiveEncrypted
  1197. if !isEncryptedRemote && !isEncryptedLocal && deviceUntrusted {
  1198. return errEncryptionNotEncryptedUntrusted
  1199. }
  1200. if !(hasTokenRemote || hasTokenLocal || isEncryptedRemote || isEncryptedLocal) {
  1201. // Noone cares about encryption here
  1202. return nil
  1203. }
  1204. if isEncryptedRemote && isEncryptedLocal {
  1205. // Should never happen, but config racyness and be safe.
  1206. return errEncryptionInvConfigLocal
  1207. }
  1208. if hasTokenRemote && hasTokenLocal {
  1209. return errEncryptionInvConfigRemote
  1210. }
  1211. if !(hasTokenRemote || hasTokenLocal) {
  1212. return errEncryptionNotEncryptedRemote
  1213. }
  1214. if !(isEncryptedRemote || isEncryptedLocal) {
  1215. return errEncryptionNotEncryptedLocal
  1216. }
  1217. if isEncryptedRemote {
  1218. passwordToken := protocol.PasswordToken(fcfg.ID, folderDevice.EncryptionPassword)
  1219. match := false
  1220. if hasTokenLocal {
  1221. match = bytes.Equal(passwordToken, ccDeviceInfos.local.EncryptionPasswordToken)
  1222. } else {
  1223. // hasTokenRemote == true
  1224. match = bytes.Equal(passwordToken, ccDeviceInfos.remote.EncryptionPasswordToken)
  1225. }
  1226. if !match {
  1227. return errEncryptionPassword
  1228. }
  1229. return nil
  1230. }
  1231. // isEncryptedLocal == true
  1232. var ccToken []byte
  1233. if hasTokenLocal {
  1234. ccToken = ccDeviceInfos.local.EncryptionPasswordToken
  1235. } else {
  1236. // hasTokenRemote == true
  1237. ccToken = ccDeviceInfos.remote.EncryptionPasswordToken
  1238. }
  1239. m.fmut.RLock()
  1240. token, ok := m.folderEncryptionPasswordTokens[fcfg.ID]
  1241. m.fmut.RUnlock()
  1242. if !ok {
  1243. var err error
  1244. token, err = readEncryptionToken(fcfg)
  1245. if err != nil && !fs.IsNotExist(err) {
  1246. return err
  1247. }
  1248. if err == nil {
  1249. m.fmut.Lock()
  1250. m.folderEncryptionPasswordTokens[fcfg.ID] = token
  1251. m.fmut.Unlock()
  1252. } else {
  1253. if err := writeEncryptionToken(ccToken, fcfg); err != nil {
  1254. return err
  1255. }
  1256. m.fmut.Lock()
  1257. m.folderEncryptionPasswordTokens[fcfg.ID] = ccToken
  1258. m.fmut.Unlock()
  1259. // We can only announce ourselfs once we have the token,
  1260. // thus we need to resend CCs now that we have it.
  1261. m.resendClusterConfig(fcfg.DeviceIDs())
  1262. return nil
  1263. }
  1264. }
  1265. if !bytes.Equal(token, ccToken) {
  1266. return errEncryptionPassword
  1267. }
  1268. return nil
  1269. }
  1270. func (m *model) resendClusterConfig(ids []protocol.DeviceID) {
  1271. if len(ids) == 0 {
  1272. return
  1273. }
  1274. ccConns := make([]protocol.Connection, 0, len(ids))
  1275. m.pmut.RLock()
  1276. for _, id := range ids {
  1277. if conn, ok := m.conn[id]; ok {
  1278. ccConns = append(ccConns, conn)
  1279. }
  1280. }
  1281. m.pmut.RUnlock()
  1282. // Generating cluster-configs acquires fmut -> must happen outside of pmut.
  1283. for _, conn := range ccConns {
  1284. cm := m.generateClusterConfig(conn.ID())
  1285. go conn.ClusterConfig(cm)
  1286. }
  1287. }
  1288. // handleIntroductions handles adding devices/folders that are shared by an introducer device
  1289. func (m *model) handleIntroductions(introducerCfg config.DeviceConfiguration, cm protocol.ClusterConfig) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, folderDeviceSet, bool) {
  1290. changed := false
  1291. folders := m.cfg.Folders()
  1292. devices := m.cfg.Devices()
  1293. foldersDevices := make(folderDeviceSet)
  1294. for _, folder := range cm.Folders {
  1295. // Adds devices which we do not have, but the introducer has
  1296. // for the folders that we have in common. Also, shares folders
  1297. // with devices that we have in common, yet are currently not sharing
  1298. // the folder.
  1299. fcfg, ok := folders[folder.ID]
  1300. if !ok {
  1301. // Don't have this folder, carry on.
  1302. continue
  1303. }
  1304. folderChanged := false
  1305. for _, device := range folder.Devices {
  1306. // No need to share with self.
  1307. if device.ID == m.id {
  1308. continue
  1309. }
  1310. foldersDevices.set(device.ID, folder.ID)
  1311. if _, ok := m.cfg.Device(device.ID); !ok {
  1312. // The device is currently unknown. Add it to the config.
  1313. devices[device.ID] = m.introduceDevice(device, introducerCfg)
  1314. } else if fcfg.SharedWith(device.ID) {
  1315. // We already share the folder with this device, so
  1316. // nothing to do.
  1317. continue
  1318. }
  1319. // We don't yet share this folder with this device. Add the device
  1320. // to sharing list of the folder.
  1321. l.Infof("Sharing folder %s with %v (vouched for by introducer %v)", folder.Description(), device.ID, introducerCfg.DeviceID)
  1322. fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{
  1323. DeviceID: device.ID,
  1324. IntroducedBy: introducerCfg.DeviceID,
  1325. })
  1326. folderChanged = true
  1327. }
  1328. if folderChanged {
  1329. folders[fcfg.ID] = fcfg
  1330. changed = true
  1331. }
  1332. }
  1333. return folders, devices, foldersDevices, changed
  1334. }
  1335. // handleDeintroductions handles removals of devices/shares that are removed by an introducer device
  1336. func (m *model) handleDeintroductions(introducerCfg config.DeviceConfiguration, foldersDevices folderDeviceSet, folders map[string]config.FolderConfiguration, devices map[protocol.DeviceID]config.DeviceConfiguration) (map[string]config.FolderConfiguration, map[protocol.DeviceID]config.DeviceConfiguration, bool) {
  1337. if introducerCfg.SkipIntroductionRemovals {
  1338. return folders, devices, false
  1339. }
  1340. changed := false
  1341. devicesNotIntroduced := make(map[protocol.DeviceID]struct{})
  1342. // Check if we should unshare some folders, if the introducer has unshared them.
  1343. for folderID, folderCfg := range folders {
  1344. for k := 0; k < len(folderCfg.Devices); k++ {
  1345. if folderCfg.Devices[k].IntroducedBy != introducerCfg.DeviceID {
  1346. devicesNotIntroduced[folderCfg.Devices[k].DeviceID] = struct{}{}
  1347. continue
  1348. }
  1349. if !foldersDevices.has(folderCfg.Devices[k].DeviceID, folderCfg.ID) {
  1350. // We could not find that folder shared on the
  1351. // introducer with the device that was introduced to us.
  1352. // We should follow and unshare as well.
  1353. l.Infof("Unsharing folder %s with %v as introducer %v no longer shares the folder with that device", folderCfg.Description(), folderCfg.Devices[k].DeviceID, folderCfg.Devices[k].IntroducedBy)
  1354. folderCfg.Devices = append(folderCfg.Devices[:k], folderCfg.Devices[k+1:]...)
  1355. folders[folderID] = folderCfg
  1356. k--
  1357. changed = true
  1358. }
  1359. }
  1360. }
  1361. // Check if we should remove some devices, if the introducer no longer
  1362. // shares any folder with them. Yet do not remove if we share other
  1363. // folders that haven't been introduced by the introducer.
  1364. for deviceID, device := range devices {
  1365. if device.IntroducedBy == introducerCfg.DeviceID {
  1366. if !foldersDevices.hasDevice(deviceID) {
  1367. if _, ok := devicesNotIntroduced[deviceID]; !ok {
  1368. // The introducer no longer shares any folder with the
  1369. // device, remove the device.
  1370. l.Infof("Removing device %v as introducer %v no longer shares any folders with that device", deviceID, device.IntroducedBy)
  1371. changed = true
  1372. delete(devices, deviceID)
  1373. continue
  1374. }
  1375. l.Infof("Would have removed %v as %v no longer shares any folders, yet there are other folders that are shared with this device that haven't been introduced by this introducer.", deviceID, device.IntroducedBy)
  1376. }
  1377. }
  1378. }
  1379. return folders, devices, changed
  1380. }
  1381. // handleAutoAccepts handles adding and sharing folders for devices that have
  1382. // AutoAcceptFolders set to true.
  1383. func (m *model) handleAutoAccepts(deviceID protocol.DeviceID, folder protocol.Folder, ccDeviceInfos *indexSenderStartInfo) (config.FolderConfiguration, bool) {
  1384. if cfg, ok := m.cfg.Folder(folder.ID); !ok {
  1385. defaultPath := m.cfg.Options().DefaultFolderPath
  1386. defaultPathFs := fs.NewFilesystem(fs.FilesystemTypeBasic, defaultPath)
  1387. pathAlternatives := []string{
  1388. fs.SanitizePath(folder.Label),
  1389. fs.SanitizePath(folder.ID),
  1390. }
  1391. for _, path := range pathAlternatives {
  1392. if _, err := defaultPathFs.Lstat(path); !fs.IsNotExist(err) {
  1393. continue
  1394. }
  1395. fcfg := config.NewFolderConfiguration(m.id, folder.ID, folder.Label, fs.FilesystemTypeBasic, filepath.Join(defaultPath, path))
  1396. fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{
  1397. DeviceID: deviceID,
  1398. })
  1399. if len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0 || len(ccDeviceInfos.local.EncryptionPasswordToken) > 0 {
  1400. fcfg.Type = config.FolderTypeReceiveEncrypted
  1401. }
  1402. l.Infof("Auto-accepted %s folder %s at path %s", deviceID, folder.Description(), fcfg.Path)
  1403. return fcfg, true
  1404. }
  1405. l.Infof("Failed to auto-accept folder %s from %s due to path conflict", folder.Description(), deviceID)
  1406. return config.FolderConfiguration{}, false
  1407. } else {
  1408. for _, device := range cfg.DeviceIDs() {
  1409. if device == deviceID {
  1410. // Already shared nothing todo.
  1411. return config.FolderConfiguration{}, false
  1412. }
  1413. }
  1414. if cfg.Type == config.FolderTypeReceiveEncrypted {
  1415. if len(ccDeviceInfos.remote.EncryptionPasswordToken) == 0 && len(ccDeviceInfos.local.EncryptionPasswordToken) == 0 {
  1416. l.Infof("Failed to auto-accept device %s on existing folder %s as the remote wants to send us unencrypted data, but the folder type is receive-encrypted", folder.Description(), deviceID)
  1417. return config.FolderConfiguration{}, false
  1418. }
  1419. } else {
  1420. if len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0 || len(ccDeviceInfos.local.EncryptionPasswordToken) > 0 {
  1421. l.Infof("Failed to auto-accept device %s on existing folder %s as the remote wants to send us encrypted data, but the folder type is not receive-encrypted", folder.Description(), deviceID)
  1422. return config.FolderConfiguration{}, false
  1423. }
  1424. }
  1425. cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{
  1426. DeviceID: deviceID,
  1427. })
  1428. l.Infof("Shared %s with %s due to auto-accept", folder.ID, deviceID)
  1429. return cfg, true
  1430. }
  1431. }
  1432. func (m *model) introduceDevice(device protocol.Device, introducerCfg config.DeviceConfiguration) config.DeviceConfiguration {
  1433. addresses := []string{"dynamic"}
  1434. for _, addr := range device.Addresses {
  1435. if addr != "dynamic" {
  1436. addresses = append(addresses, addr)
  1437. }
  1438. }
  1439. l.Infof("Adding device %v to config (vouched for by introducer %v)", device.ID, introducerCfg.DeviceID)
  1440. newDeviceCfg := config.DeviceConfiguration{
  1441. DeviceID: device.ID,
  1442. Name: device.Name,
  1443. Compression: introducerCfg.Compression,
  1444. Addresses: addresses,
  1445. CertName: device.CertName,
  1446. IntroducedBy: introducerCfg.DeviceID,
  1447. }
  1448. // The introducers' introducers are also our introducers.
  1449. if device.Introducer {
  1450. l.Infof("Device %v is now also an introducer", device.ID)
  1451. newDeviceCfg.Introducer = true
  1452. newDeviceCfg.SkipIntroductionRemovals = device.SkipIntroductionRemovals
  1453. }
  1454. return newDeviceCfg
  1455. }
  1456. // Closed is called when a connection has been closed
  1457. func (m *model) Closed(conn protocol.Connection, err error) {
  1458. device := conn.ID()
  1459. m.pmut.Lock()
  1460. conn, ok := m.conn[device]
  1461. if !ok {
  1462. m.pmut.Unlock()
  1463. return
  1464. }
  1465. delete(m.conn, device)
  1466. delete(m.connRequestLimiters, device)
  1467. delete(m.helloMessages, device)
  1468. delete(m.deviceDownloads, device)
  1469. delete(m.remotePausedFolders, device)
  1470. closed := m.closed[device]
  1471. delete(m.closed, device)
  1472. delete(m.indexSenders, device)
  1473. m.pmut.Unlock()
  1474. m.progressEmitter.temporaryIndexUnsubscribe(conn)
  1475. l.Infof("Connection to %s at %s closed: %v", device, conn, err)
  1476. m.evLogger.Log(events.DeviceDisconnected, map[string]string{
  1477. "id": device.String(),
  1478. "error": err.Error(),
  1479. })
  1480. close(closed)
  1481. }
  1482. // Implements protocol.RequestResponse
  1483. type requestResponse struct {
  1484. data []byte
  1485. closed chan struct{}
  1486. once stdsync.Once
  1487. }
  1488. func newRequestResponse(size int) *requestResponse {
  1489. return &requestResponse{
  1490. data: protocol.BufferPool.Get(size),
  1491. closed: make(chan struct{}),
  1492. }
  1493. }
  1494. func (r *requestResponse) Data() []byte {
  1495. return r.data
  1496. }
  1497. func (r *requestResponse) Close() {
  1498. r.once.Do(func() {
  1499. protocol.BufferPool.Put(r.data)
  1500. close(r.closed)
  1501. })
  1502. }
  1503. func (r *requestResponse) Wait() {
  1504. <-r.closed
  1505. }
  1506. // Request returns the specified data segment by reading it from local disk.
  1507. // Implements the protocol.Model interface.
  1508. func (m *model) Request(deviceID protocol.DeviceID, folder, name string, blockNo, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (out protocol.RequestResponse, err error) {
  1509. if size < 0 || offset < 0 {
  1510. return nil, protocol.ErrInvalid
  1511. }
  1512. m.fmut.RLock()
  1513. folderCfg, ok := m.folderCfgs[folder]
  1514. folderIgnores := m.folderIgnores[folder]
  1515. m.fmut.RUnlock()
  1516. if !ok {
  1517. // The folder might be already unpaused in the config, but not yet
  1518. // in the model.
  1519. l.Debugf("Request from %s for file %s in unstarted folder %q", deviceID, name, folder)
  1520. return nil, protocol.ErrGeneric
  1521. }
  1522. if !folderCfg.SharedWith(deviceID) {
  1523. l.Warnf("Request from %s for file %s in unshared folder %q", deviceID, name, folder)
  1524. return nil, protocol.ErrGeneric
  1525. }
  1526. if folderCfg.Paused {
  1527. l.Debugf("Request from %s for file %s in paused folder %q", deviceID, name, folder)
  1528. return nil, protocol.ErrGeneric
  1529. }
  1530. // Make sure the path is valid and in canonical form
  1531. if name, err = fs.Canonicalize(name); err != nil {
  1532. l.Debugf("Request from %s in folder %q for invalid filename %s", deviceID, folder, name)
  1533. return nil, protocol.ErrGeneric
  1534. }
  1535. if deviceID != protocol.LocalDeviceID {
  1536. l.Debugf("%v REQ(in): %s: %q / %q o=%d s=%d t=%v", m, deviceID, folder, name, offset, size, fromTemporary)
  1537. }
  1538. if fs.IsInternal(name) {
  1539. l.Debugf("%v REQ(in) for internal file: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
  1540. return nil, protocol.ErrInvalid
  1541. }
  1542. if folderIgnores.Match(name).IsIgnored() {
  1543. l.Debugf("%v REQ(in) for ignored file: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
  1544. return nil, protocol.ErrInvalid
  1545. }
  1546. folderFs := folderCfg.Filesystem()
  1547. if err := osutil.TraversesSymlink(folderFs, filepath.Dir(name)); err != nil {
  1548. l.Debugf("%v REQ(in) traversal check: %s - %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
  1549. return nil, protocol.ErrNoSuchFile
  1550. }
  1551. // Restrict parallel requests by connection/device
  1552. m.pmut.RLock()
  1553. limiter := m.connRequestLimiters[deviceID]
  1554. m.pmut.RUnlock()
  1555. // The requestResponse releases the bytes to the buffer pool and the
  1556. // limiters when its Close method is called.
  1557. res := newLimitedRequestResponse(int(size), limiter, m.globalRequestLimiter)
  1558. defer func() {
  1559. // Close it ourselves if it isn't returned due to an error
  1560. if err != nil {
  1561. res.Close()
  1562. }
  1563. }()
  1564. // Only check temp files if the flag is set, and if we are set to advertise
  1565. // the temp indexes.
  1566. if fromTemporary && !folderCfg.DisableTempIndexes {
  1567. tempFn := fs.TempName(name)
  1568. if info, err := folderFs.Lstat(tempFn); err != nil || !info.IsRegular() {
  1569. // Reject reads for anything that doesn't exist or is something
  1570. // other than a regular file.
  1571. l.Debugf("%v REQ(in) failed stating temp file (%v): %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
  1572. return nil, protocol.ErrNoSuchFile
  1573. }
  1574. err := readOffsetIntoBuf(folderFs, tempFn, offset, res.data)
  1575. if err == nil && scanner.Validate(res.data, hash, weakHash) {
  1576. return res, nil
  1577. }
  1578. // Fall through to reading from a non-temp file, just incase the temp
  1579. // file has finished downloading.
  1580. }
  1581. if info, err := folderFs.Lstat(name); err != nil || !info.IsRegular() {
  1582. // Reject reads for anything that doesn't exist or is something
  1583. // other than a regular file.
  1584. l.Debugf("%v REQ(in) failed stating file (%v): %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
  1585. return nil, protocol.ErrNoSuchFile
  1586. }
  1587. if err := readOffsetIntoBuf(folderFs, name, offset, res.data); fs.IsNotExist(err) {
  1588. l.Debugf("%v REQ(in) file doesn't exist: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
  1589. return nil, protocol.ErrNoSuchFile
  1590. } else if err == io.EOF && len(hash) == 0 {
  1591. // Read beyond end of file when we can't verify the hash -- this is
  1592. // a padded read for an encrypted file. It's fine.
  1593. } else if err != nil {
  1594. l.Debugf("%v REQ(in) failed reading file (%v): %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
  1595. return nil, protocol.ErrGeneric
  1596. }
  1597. if len(hash) > 0 && !scanner.Validate(res.data, hash, weakHash) {
  1598. m.recheckFile(deviceID, folder, name, offset, hash, weakHash)
  1599. l.Debugf("%v REQ(in) failed validating data: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, size)
  1600. return nil, protocol.ErrNoSuchFile
  1601. }
  1602. return res, nil
  1603. }
  1604. // newLimitedRequestResponse takes size bytes from the limiters in order,
  1605. // skipping nil limiters, then returns a requestResponse of the given size.
  1606. // When the requestResponse is closed the limiters are given back the bytes,
  1607. // in reverse order.
  1608. func newLimitedRequestResponse(size int, limiters ...*byteSemaphore) *requestResponse {
  1609. for _, limiter := range limiters {
  1610. if limiter != nil {
  1611. limiter.take(size)
  1612. }
  1613. }
  1614. res := newRequestResponse(size)
  1615. go func() {
  1616. res.Wait()
  1617. for i := range limiters {
  1618. limiter := limiters[len(limiters)-1-i]
  1619. if limiter != nil {
  1620. limiter.give(size)
  1621. }
  1622. }
  1623. }()
  1624. return res
  1625. }
  1626. func (m *model) recheckFile(deviceID protocol.DeviceID, folder, name string, offset int64, hash []byte, weakHash uint32) {
  1627. cf, ok := m.CurrentFolderFile(folder, name)
  1628. if !ok {
  1629. l.Debugf("%v recheckFile: %s: %q / %q: no current file", m, deviceID, folder, name)
  1630. return
  1631. }
  1632. if cf.IsDeleted() || cf.IsInvalid() || cf.IsSymlink() || cf.IsDirectory() {
  1633. l.Debugf("%v recheckFile: %s: %q / %q: not a regular file", m, deviceID, folder, name)
  1634. return
  1635. }
  1636. blockIndex := int(offset / int64(cf.BlockSize()))
  1637. if blockIndex >= len(cf.Blocks) {
  1638. l.Debugf("%v recheckFile: %s: %q / %q i=%d: block index too far", m, deviceID, folder, name, blockIndex)
  1639. return
  1640. }
  1641. block := cf.Blocks[blockIndex]
  1642. // Seems to want a different version of the file, whatever.
  1643. if !bytes.Equal(block.Hash, hash) {
  1644. l.Debugf("%v recheckFile: %s: %q / %q i=%d: hash mismatch %x != %x", m, deviceID, folder, name, blockIndex, block.Hash, hash)
  1645. return
  1646. }
  1647. if weakHash != 0 && block.WeakHash != weakHash {
  1648. l.Debugf("%v recheckFile: %s: %q / %q i=%d: weak hash mismatch %v != %v", m, deviceID, folder, name, blockIndex, block.WeakHash, weakHash)
  1649. return
  1650. }
  1651. // The hashes provided part of the request match what we expect to find according
  1652. // to what we have in the database, yet the content we've read off the filesystem doesn't
  1653. // Something is fishy, invalidate the file and rescan it.
  1654. // The file will temporarily become invalid, which is ok as the content is messed up.
  1655. m.fmut.RLock()
  1656. runner, ok := m.folderRunners[folder]
  1657. m.fmut.RUnlock()
  1658. if !ok {
  1659. l.Debugf("%v recheckFile: %s: %q / %q: Folder stopped before rescan could be scheduled", m, deviceID, folder, name)
  1660. return
  1661. }
  1662. runner.ScheduleForceRescan(name)
  1663. l.Debugf("%v recheckFile: %s: %q / %q", m, deviceID, folder, name)
  1664. }
  1665. func (m *model) CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool) {
  1666. m.fmut.RLock()
  1667. fs, ok := m.folderFiles[folder]
  1668. m.fmut.RUnlock()
  1669. if !ok {
  1670. return protocol.FileInfo{}, false
  1671. }
  1672. snap := fs.Snapshot()
  1673. defer snap.Release()
  1674. return snap.Get(protocol.LocalDeviceID, file)
  1675. }
  1676. func (m *model) CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool) {
  1677. m.fmut.RLock()
  1678. fs, ok := m.folderFiles[folder]
  1679. m.fmut.RUnlock()
  1680. if !ok {
  1681. return protocol.FileInfo{}, false
  1682. }
  1683. snap := fs.Snapshot()
  1684. defer snap.Release()
  1685. return snap.GetGlobal(file)
  1686. }
  1687. // Connection returns the current connection for device, and a boolean whether a connection was found.
  1688. func (m *model) Connection(deviceID protocol.DeviceID) (protocol.Connection, bool) {
  1689. m.pmut.RLock()
  1690. cn, ok := m.conn[deviceID]
  1691. m.pmut.RUnlock()
  1692. if ok {
  1693. m.deviceWasSeen(deviceID)
  1694. }
  1695. return cn, ok
  1696. }
  1697. func (m *model) GetIgnores(folder string) ([]string, []string, error) {
  1698. m.fmut.RLock()
  1699. cfg, cfgOk := m.folderCfgs[folder]
  1700. ignores, ignoresOk := m.folderIgnores[folder]
  1701. m.fmut.RUnlock()
  1702. if !cfgOk {
  1703. cfg, cfgOk = m.cfg.Folder(folder)
  1704. if !cfgOk {
  1705. return nil, nil, fmt.Errorf("folder %s does not exist", folder)
  1706. }
  1707. }
  1708. // On creation a new folder with ignore patterns validly has no marker yet.
  1709. if err := cfg.CheckPath(); err != nil && err != config.ErrMarkerMissing {
  1710. return nil, nil, err
  1711. }
  1712. if !ignoresOk {
  1713. ignores = ignore.New(fs.NewFilesystem(cfg.FilesystemType, cfg.Path))
  1714. }
  1715. err := ignores.Load(".stignore")
  1716. if fs.IsNotExist(err) {
  1717. // Having no ignores is not an error.
  1718. return nil, nil, nil
  1719. }
  1720. // Return lines and patterns, which may have some meaning even when err
  1721. // != nil, depending on the specific error.
  1722. return ignores.Lines(), ignores.Patterns(), err
  1723. }
  1724. func (m *model) SetIgnores(folder string, content []string) error {
  1725. cfg, ok := m.cfg.Folder(folder)
  1726. if !ok {
  1727. return fmt.Errorf("folder %s does not exist", cfg.Description())
  1728. }
  1729. err := cfg.CheckPath()
  1730. if err == config.ErrPathMissing {
  1731. if err = cfg.CreateRoot(); err != nil {
  1732. return errors.Wrap(err, "failed to create folder root")
  1733. }
  1734. err = cfg.CheckPath()
  1735. }
  1736. if err != nil && err != config.ErrMarkerMissing {
  1737. return err
  1738. }
  1739. if err := ignore.WriteIgnores(cfg.Filesystem(), ".stignore", content); err != nil {
  1740. l.Warnln("Saving .stignore:", err)
  1741. return err
  1742. }
  1743. m.fmut.RLock()
  1744. runner, ok := m.folderRunners[folder]
  1745. m.fmut.RUnlock()
  1746. if ok {
  1747. return runner.Scan(nil)
  1748. }
  1749. return nil
  1750. }
  1751. // OnHello is called when an device connects to us.
  1752. // This allows us to extract some information from the Hello message
  1753. // and add it to a list of known devices ahead of any checks.
  1754. func (m *model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protocol.Hello) error {
  1755. if m.cfg.IgnoredDevice(remoteID) {
  1756. return errDeviceIgnored
  1757. }
  1758. cfg, ok := m.cfg.Device(remoteID)
  1759. if !ok {
  1760. if err := m.db.AddOrUpdatePendingDevice(remoteID, hello.DeviceName, addr.String()); err != nil {
  1761. l.Warnf("Failed to persist pending device entry to database: %v", err)
  1762. }
  1763. m.evLogger.Log(events.DeviceRejected, map[string]string{
  1764. "name": hello.DeviceName,
  1765. "device": remoteID.String(),
  1766. "address": addr.String(),
  1767. })
  1768. return errDeviceUnknown
  1769. }
  1770. if cfg.Paused {
  1771. return errDevicePaused
  1772. }
  1773. if len(cfg.AllowedNetworks) > 0 {
  1774. if !connections.IsAllowedNetwork(addr.String(), cfg.AllowedNetworks) {
  1775. return errNetworkNotAllowed
  1776. }
  1777. }
  1778. return nil
  1779. }
  1780. // GetHello is called when we are about to connect to some remote device.
  1781. func (m *model) GetHello(id protocol.DeviceID) protocol.HelloIntf {
  1782. name := ""
  1783. if _, ok := m.cfg.Device(id); ok {
  1784. // Set our name (from the config of our device ID) only if we already know about the other side device ID.
  1785. if myCfg, ok := m.cfg.Device(m.id); ok {
  1786. name = myCfg.Name
  1787. }
  1788. }
  1789. return &protocol.Hello{
  1790. DeviceName: name,
  1791. ClientName: m.clientName,
  1792. ClientVersion: m.clientVersion,
  1793. }
  1794. }
  1795. // AddConnection adds a new peer connection to the model. An initial index will
  1796. // be sent to the connected peer, thereafter index updates whenever the local
  1797. // folder changes.
  1798. func (m *model) AddConnection(conn protocol.Connection, hello protocol.Hello) {
  1799. deviceID := conn.ID()
  1800. device, ok := m.cfg.Device(deviceID)
  1801. if !ok {
  1802. l.Infoln("Trying to add connection to unknown device")
  1803. return
  1804. }
  1805. m.pmut.Lock()
  1806. if oldConn, ok := m.conn[deviceID]; ok {
  1807. l.Infoln("Replacing old connection", oldConn, "with", conn, "for", deviceID)
  1808. // There is an existing connection to this device that we are
  1809. // replacing. We must close the existing connection and wait for the
  1810. // close to complete before adding the new connection. We do the
  1811. // actual close without holding pmut as the connection will call
  1812. // back into Closed() for the cleanup.
  1813. closed := m.closed[deviceID]
  1814. m.pmut.Unlock()
  1815. oldConn.Close(errReplacingConnection)
  1816. <-closed
  1817. m.pmut.Lock()
  1818. }
  1819. m.conn[deviceID] = conn
  1820. closed := make(chan struct{})
  1821. m.closed[deviceID] = closed
  1822. m.deviceDownloads[deviceID] = newDeviceDownloadState()
  1823. m.indexSenders[deviceID] = newIndexSenderRegistry(conn, closed, m.Supervisor, m.evLogger)
  1824. // 0: default, <0: no limiting
  1825. switch {
  1826. case device.MaxRequestKiB > 0:
  1827. m.connRequestLimiters[deviceID] = newByteSemaphore(1024 * device.MaxRequestKiB)
  1828. case device.MaxRequestKiB == 0:
  1829. m.connRequestLimiters[deviceID] = newByteSemaphore(1024 * defaultPullerPendingKiB)
  1830. }
  1831. m.helloMessages[deviceID] = hello
  1832. event := map[string]string{
  1833. "id": deviceID.String(),
  1834. "deviceName": hello.DeviceName,
  1835. "clientName": hello.ClientName,
  1836. "clientVersion": hello.ClientVersion,
  1837. "type": conn.Type(),
  1838. }
  1839. addr := conn.RemoteAddr()
  1840. if addr != nil {
  1841. event["addr"] = addr.String()
  1842. }
  1843. m.evLogger.Log(events.DeviceConnected, event)
  1844. l.Infof(`Device %s client is "%s %s" named "%s" at %s`, deviceID, hello.ClientName, hello.ClientVersion, hello.DeviceName, conn)
  1845. conn.Start()
  1846. m.pmut.Unlock()
  1847. // Acquires fmut, so has to be done outside of pmut.
  1848. cm := m.generateClusterConfig(deviceID)
  1849. conn.ClusterConfig(cm)
  1850. if (device.Name == "" || m.cfg.Options().OverwriteRemoteDevNames) && hello.DeviceName != "" {
  1851. device.Name = hello.DeviceName
  1852. m.cfg.SetDevice(device)
  1853. m.cfg.Save()
  1854. }
  1855. m.deviceWasSeen(deviceID)
  1856. }
  1857. func (m *model) DownloadProgress(device protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) error {
  1858. m.fmut.RLock()
  1859. cfg, ok := m.folderCfgs[folder]
  1860. m.fmut.RUnlock()
  1861. if !ok || cfg.DisableTempIndexes || !cfg.SharedWith(device) {
  1862. return nil
  1863. }
  1864. m.pmut.RLock()
  1865. downloads := m.deviceDownloads[device]
  1866. m.pmut.RUnlock()
  1867. downloads.Update(folder, updates)
  1868. state := downloads.GetBlockCounts(folder)
  1869. m.evLogger.Log(events.RemoteDownloadProgress, map[string]interface{}{
  1870. "device": device.String(),
  1871. "folder": folder,
  1872. "state": state,
  1873. })
  1874. return nil
  1875. }
  1876. func (m *model) deviceWasSeen(deviceID protocol.DeviceID) {
  1877. m.fmut.RLock()
  1878. sr, ok := m.deviceStatRefs[deviceID]
  1879. m.fmut.RUnlock()
  1880. if ok {
  1881. sr.WasSeen()
  1882. }
  1883. }
  1884. func (m *model) requestGlobal(ctx context.Context, deviceID protocol.DeviceID, folder, name string, blockNo int, offset int64, size int, hash []byte, weakHash uint32, fromTemporary bool) ([]byte, error) {
  1885. m.pmut.RLock()
  1886. nc, ok := m.conn[deviceID]
  1887. m.pmut.RUnlock()
  1888. if !ok {
  1889. return nil, fmt.Errorf("requestGlobal: no such device: %s", deviceID)
  1890. }
  1891. l.Debugf("%v REQ(out): %s: %q / %q b=%d o=%d s=%d h=%x wh=%x ft=%t", m, deviceID, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
  1892. return nc.Request(ctx, folder, name, blockNo, offset, size, hash, weakHash, fromTemporary)
  1893. }
  1894. func (m *model) ScanFolders() map[string]error {
  1895. m.fmut.RLock()
  1896. folders := make([]string, 0, len(m.folderCfgs))
  1897. for folder := range m.folderCfgs {
  1898. folders = append(folders, folder)
  1899. }
  1900. m.fmut.RUnlock()
  1901. errors := make(map[string]error, len(m.folderCfgs))
  1902. errorsMut := sync.NewMutex()
  1903. wg := sync.NewWaitGroup()
  1904. wg.Add(len(folders))
  1905. for _, folder := range folders {
  1906. folder := folder
  1907. go func() {
  1908. err := m.ScanFolder(folder)
  1909. if err != nil {
  1910. errorsMut.Lock()
  1911. errors[folder] = err
  1912. errorsMut.Unlock()
  1913. }
  1914. wg.Done()
  1915. }()
  1916. }
  1917. wg.Wait()
  1918. return errors
  1919. }
  1920. func (m *model) ScanFolder(folder string) error {
  1921. return m.ScanFolderSubdirs(folder, nil)
  1922. }
  1923. func (m *model) ScanFolderSubdirs(folder string, subs []string) error {
  1924. m.fmut.RLock()
  1925. err := m.checkFolderRunningLocked(folder)
  1926. runner := m.folderRunners[folder]
  1927. m.fmut.RUnlock()
  1928. if err != nil {
  1929. return err
  1930. }
  1931. return runner.Scan(subs)
  1932. }
  1933. func (m *model) DelayScan(folder string, next time.Duration) {
  1934. m.fmut.RLock()
  1935. runner, ok := m.folderRunners[folder]
  1936. m.fmut.RUnlock()
  1937. if !ok {
  1938. return
  1939. }
  1940. runner.DelayScan(next)
  1941. }
  1942. // numHashers returns the number of hasher routines to use for a given folder,
  1943. // taking into account configuration and available CPU cores.
  1944. func (m *model) numHashers(folder string) int {
  1945. m.fmut.RLock()
  1946. folderCfg := m.folderCfgs[folder]
  1947. numFolders := len(m.folderCfgs)
  1948. m.fmut.RUnlock()
  1949. if folderCfg.Hashers > 0 {
  1950. // Specific value set in the config, use that.
  1951. return folderCfg.Hashers
  1952. }
  1953. if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
  1954. // Interactive operating systems; don't load the system too heavily by
  1955. // default.
  1956. return 1
  1957. }
  1958. // For other operating systems and architectures, lets try to get some
  1959. // work done... Divide the available CPU cores among the configured
  1960. // folders.
  1961. if perFolder := runtime.GOMAXPROCS(-1) / numFolders; perFolder > 0 {
  1962. return perFolder
  1963. }
  1964. return 1
  1965. }
  1966. // generateClusterConfig returns a ClusterConfigMessage that is correct for
  1967. // the given peer device
  1968. func (m *model) generateClusterConfig(device protocol.DeviceID) protocol.ClusterConfig {
  1969. var message protocol.ClusterConfig
  1970. m.fmut.RLock()
  1971. defer m.fmut.RUnlock()
  1972. for _, folderCfg := range m.cfg.FolderList() {
  1973. if !folderCfg.SharedWith(device) {
  1974. continue
  1975. }
  1976. var encryptionToken []byte
  1977. var hasEncryptionToken bool
  1978. if folderCfg.Type == config.FolderTypeReceiveEncrypted {
  1979. if encryptionToken, hasEncryptionToken = m.folderEncryptionPasswordTokens[folderCfg.ID]; !hasEncryptionToken {
  1980. // We haven't gotten a token for us yet and without
  1981. // one the other side can't validate us - pretend
  1982. // we don't have the folder yet.
  1983. continue
  1984. }
  1985. }
  1986. protocolFolder := protocol.Folder{
  1987. ID: folderCfg.ID,
  1988. Label: folderCfg.Label,
  1989. ReadOnly: folderCfg.Type == config.FolderTypeSendOnly,
  1990. IgnorePermissions: folderCfg.IgnorePerms,
  1991. IgnoreDelete: folderCfg.IgnoreDelete,
  1992. DisableTempIndexes: folderCfg.DisableTempIndexes,
  1993. }
  1994. fs := m.folderFiles[folderCfg.ID]
  1995. // Even if we aren't paused, if we haven't started the folder yet
  1996. // pretend we are. Otherwise the remote might get confused about
  1997. // the missing index info (and drop all the info). We will send
  1998. // another cluster config once the folder is started.
  1999. protocolFolder.Paused = folderCfg.Paused || fs == nil
  2000. for _, device := range folderCfg.Devices {
  2001. deviceCfg, _ := m.cfg.Device(device.DeviceID)
  2002. protocolDevice := protocol.Device{
  2003. ID: deviceCfg.DeviceID,
  2004. Name: deviceCfg.Name,
  2005. Addresses: deviceCfg.Addresses,
  2006. Compression: deviceCfg.Compression,
  2007. CertName: deviceCfg.CertName,
  2008. Introducer: deviceCfg.Introducer,
  2009. }
  2010. if deviceCfg.DeviceID == m.id && hasEncryptionToken {
  2011. protocolDevice.EncryptionPasswordToken = encryptionToken
  2012. } else if device.EncryptionPassword != "" {
  2013. protocolDevice.EncryptionPasswordToken = protocol.PasswordToken(folderCfg.ID, device.EncryptionPassword)
  2014. }
  2015. if fs != nil {
  2016. if deviceCfg.DeviceID == m.id {
  2017. protocolDevice.IndexID = fs.IndexID(protocol.LocalDeviceID)
  2018. protocolDevice.MaxSequence = fs.Sequence(protocol.LocalDeviceID)
  2019. } else {
  2020. protocolDevice.IndexID = fs.IndexID(deviceCfg.DeviceID)
  2021. protocolDevice.MaxSequence = fs.Sequence(deviceCfg.DeviceID)
  2022. }
  2023. }
  2024. protocolFolder.Devices = append(protocolFolder.Devices, protocolDevice)
  2025. }
  2026. message.Folders = append(message.Folders, protocolFolder)
  2027. }
  2028. return message
  2029. }
  2030. func (m *model) State(folder string) (string, time.Time, error) {
  2031. m.fmut.RLock()
  2032. runner, ok := m.folderRunners[folder]
  2033. m.fmut.RUnlock()
  2034. if !ok {
  2035. // The returned error should be an actual folder error, so returning
  2036. // errors.New("does not exist") or similar here would be
  2037. // inappropriate.
  2038. return "", time.Time{}, nil
  2039. }
  2040. state, changed, err := runner.getState()
  2041. return state.String(), changed, err
  2042. }
  2043. func (m *model) FolderErrors(folder string) ([]FileError, error) {
  2044. m.fmut.RLock()
  2045. err := m.checkFolderRunningLocked(folder)
  2046. runner := m.folderRunners[folder]
  2047. m.fmut.RUnlock()
  2048. if err != nil {
  2049. return nil, err
  2050. }
  2051. return runner.Errors(), nil
  2052. }
  2053. func (m *model) WatchError(folder string) error {
  2054. m.fmut.RLock()
  2055. err := m.checkFolderRunningLocked(folder)
  2056. runner := m.folderRunners[folder]
  2057. m.fmut.RUnlock()
  2058. if err != nil {
  2059. return nil // If the folder isn't running, there's no error to report.
  2060. }
  2061. return runner.WatchError()
  2062. }
  2063. func (m *model) Override(folder string) {
  2064. // Grab the runner and the file set.
  2065. m.fmut.RLock()
  2066. runner, ok := m.folderRunners[folder]
  2067. m.fmut.RUnlock()
  2068. if !ok {
  2069. return
  2070. }
  2071. // Run the override, taking updates as if they came from scanning.
  2072. runner.Override()
  2073. }
  2074. func (m *model) Revert(folder string) {
  2075. // Grab the runner and the file set.
  2076. m.fmut.RLock()
  2077. runner, ok := m.folderRunners[folder]
  2078. m.fmut.RUnlock()
  2079. if !ok {
  2080. return
  2081. }
  2082. // Run the revert, taking updates as if they came from scanning.
  2083. runner.Revert()
  2084. }
  2085. func (m *model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{} {
  2086. m.fmut.RLock()
  2087. files, ok := m.folderFiles[folder]
  2088. m.fmut.RUnlock()
  2089. if !ok {
  2090. return nil
  2091. }
  2092. output := make(map[string]interface{})
  2093. sep := string(filepath.Separator)
  2094. prefix = osutil.NativeFilename(prefix)
  2095. if prefix != "" && !strings.HasSuffix(prefix, sep) {
  2096. prefix = prefix + sep
  2097. }
  2098. snap := files.Snapshot()
  2099. defer snap.Release()
  2100. snap.WithPrefixedGlobalTruncated(prefix, func(fi protocol.FileIntf) bool {
  2101. f := fi.(db.FileInfoTruncated)
  2102. // Don't include the prefix itself.
  2103. if f.IsInvalid() || f.IsDeleted() || strings.HasPrefix(prefix, f.Name) {
  2104. return true
  2105. }
  2106. f.Name = strings.Replace(f.Name, prefix, "", 1)
  2107. var dir, base string
  2108. if f.IsDirectory() && !f.IsSymlink() {
  2109. dir = f.Name
  2110. } else {
  2111. dir = filepath.Dir(f.Name)
  2112. base = filepath.Base(f.Name)
  2113. }
  2114. if levels > -1 && strings.Count(f.Name, sep) > levels {
  2115. return true
  2116. }
  2117. last := output
  2118. if dir != "." {
  2119. for _, path := range strings.Split(dir, sep) {
  2120. directory, ok := last[path]
  2121. if !ok {
  2122. newdir := make(map[string]interface{})
  2123. last[path] = newdir
  2124. last = newdir
  2125. } else {
  2126. last = directory.(map[string]interface{})
  2127. }
  2128. }
  2129. }
  2130. if !dirsonly && base != "" {
  2131. last[base] = []interface{}{
  2132. f.ModTime(), f.FileSize(),
  2133. }
  2134. }
  2135. return true
  2136. })
  2137. return output
  2138. }
  2139. func (m *model) GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error) {
  2140. m.fmut.RLock()
  2141. err := m.checkFolderRunningLocked(folder)
  2142. ver := m.folderVersioners[folder]
  2143. m.fmut.RUnlock()
  2144. if err != nil {
  2145. return nil, err
  2146. }
  2147. if ver == nil {
  2148. return nil, errNoVersioner
  2149. }
  2150. return ver.GetVersions()
  2151. }
  2152. func (m *model) RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error) {
  2153. m.fmut.RLock()
  2154. err := m.checkFolderRunningLocked(folder)
  2155. fcfg := m.folderCfgs[folder]
  2156. ver := m.folderVersioners[folder]
  2157. m.fmut.RUnlock()
  2158. if err != nil {
  2159. return nil, err
  2160. }
  2161. if ver == nil {
  2162. return nil, errNoVersioner
  2163. }
  2164. restoreErrors := make(map[string]string)
  2165. for file, version := range versions {
  2166. if err := ver.Restore(file, version); err != nil {
  2167. restoreErrors[file] = err.Error()
  2168. }
  2169. }
  2170. // Trigger scan
  2171. if !fcfg.FSWatcherEnabled {
  2172. go func() { _ = m.ScanFolder(folder) }()
  2173. }
  2174. return restoreErrors, nil
  2175. }
  2176. func (m *model) Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
  2177. // The slightly unusual locking sequence here is because we need to hold
  2178. // pmut for the duration (as the value returned from foldersFiles can
  2179. // get heavily modified on Close()), but also must acquire fmut before
  2180. // pmut. (The locks can be *released* in any order.)
  2181. m.fmut.RLock()
  2182. m.pmut.RLock()
  2183. defer m.pmut.RUnlock()
  2184. fs, ok := m.folderFiles[folder]
  2185. cfg := m.folderCfgs[folder]
  2186. m.fmut.RUnlock()
  2187. if !ok {
  2188. return nil
  2189. }
  2190. var availabilities []Availability
  2191. snap := fs.Snapshot()
  2192. defer snap.Release()
  2193. for _, device := range snap.Availability(file.Name) {
  2194. if _, ok := m.remotePausedFolders[device]; !ok {
  2195. continue
  2196. }
  2197. if _, ok := m.remotePausedFolders[device][folder]; ok {
  2198. continue
  2199. }
  2200. _, ok := m.conn[device]
  2201. if ok {
  2202. availabilities = append(availabilities, Availability{ID: device, FromTemporary: false})
  2203. }
  2204. }
  2205. for _, device := range cfg.Devices {
  2206. if m.deviceDownloads[device.DeviceID].Has(folder, file.Name, file.Version, int(block.Offset/int64(file.BlockSize()))) {
  2207. availabilities = append(availabilities, Availability{ID: device.DeviceID, FromTemporary: true})
  2208. }
  2209. }
  2210. return availabilities
  2211. }
  2212. // BringToFront bumps the given files priority in the job queue.
  2213. func (m *model) BringToFront(folder, file string) {
  2214. m.fmut.RLock()
  2215. runner, ok := m.folderRunners[folder]
  2216. m.fmut.RUnlock()
  2217. if ok {
  2218. runner.BringToFront(file)
  2219. }
  2220. }
  2221. func (m *model) ResetFolder(folder string) {
  2222. l.Infof("Cleaning data for folder %q", folder)
  2223. db.DropFolder(m.db, folder)
  2224. }
  2225. func (m *model) String() string {
  2226. return fmt.Sprintf("model@%p", m)
  2227. }
  2228. func (m *model) VerifyConfiguration(from, to config.Configuration) error {
  2229. return nil
  2230. }
  2231. func (m *model) CommitConfiguration(from, to config.Configuration) bool {
  2232. // TODO: This should not use reflect, and should take more care to try to handle stuff without restart.
  2233. // Go through the folder configs and figure out if we need to restart or not.
  2234. // Tracks devices affected by any configuration change to resend ClusterConfig.
  2235. clusterConfigDevices := make(deviceIDSet, len(from.Devices)+len(to.Devices))
  2236. fromFolders := mapFolders(from.Folders)
  2237. toFolders := mapFolders(to.Folders)
  2238. for folderID, cfg := range toFolders {
  2239. if _, ok := fromFolders[folderID]; !ok {
  2240. // A folder was added.
  2241. if cfg.Paused {
  2242. l.Infoln("Paused folder", cfg.Description())
  2243. } else {
  2244. l.Infoln("Adding folder", cfg.Description())
  2245. if err := m.newFolder(cfg, to.Options.CacheIgnoredFiles); err != nil {
  2246. m.fatal(err)
  2247. return true
  2248. }
  2249. }
  2250. clusterConfigDevices.add(cfg.DeviceIDs())
  2251. }
  2252. }
  2253. removedFolders := make(map[string]struct{})
  2254. for folderID, fromCfg := range fromFolders {
  2255. toCfg, ok := toFolders[folderID]
  2256. if !ok {
  2257. // The folder was removed.
  2258. m.removeFolder(fromCfg)
  2259. clusterConfigDevices.add(fromCfg.DeviceIDs())
  2260. removedFolders[fromCfg.ID] = struct{}{}
  2261. continue
  2262. }
  2263. if fromCfg.Paused && toCfg.Paused {
  2264. continue
  2265. }
  2266. // This folder exists on both sides. Settings might have changed.
  2267. // Check if anything differs that requires a restart.
  2268. if !reflect.DeepEqual(fromCfg.RequiresRestartOnly(), toCfg.RequiresRestartOnly()) || from.Options.CacheIgnoredFiles != to.Options.CacheIgnoredFiles {
  2269. if err := m.restartFolder(fromCfg, toCfg, to.Options.CacheIgnoredFiles); err != nil {
  2270. m.fatal(err)
  2271. return true
  2272. }
  2273. clusterConfigDevices.add(fromCfg.DeviceIDs())
  2274. clusterConfigDevices.add(toCfg.DeviceIDs())
  2275. }
  2276. // Emit the folder pause/resume event
  2277. if fromCfg.Paused != toCfg.Paused {
  2278. eventType := events.FolderResumed
  2279. if toCfg.Paused {
  2280. eventType = events.FolderPaused
  2281. }
  2282. m.evLogger.Log(eventType, map[string]string{"id": toCfg.ID, "label": toCfg.Label})
  2283. }
  2284. }
  2285. // Removing a device. We actually don't need to do anything.
  2286. // Because folder config has changed (since the device lists do not match)
  2287. // Folders for that had device got "restarted", which involves killing
  2288. // connections to all devices that we were sharing the folder with.
  2289. // At some point model.Close() will get called for that device which will
  2290. // clean residue device state that is not part of any folder.
  2291. // Pausing a device, unpausing is handled by the connection service.
  2292. fromDevices := from.DeviceMap()
  2293. toDevices := to.DeviceMap()
  2294. closeDevices := make([]protocol.DeviceID, 0, len(to.Devices))
  2295. for deviceID, toCfg := range toDevices {
  2296. fromCfg, ok := fromDevices[deviceID]
  2297. if !ok {
  2298. sr := stats.NewDeviceStatisticsReference(m.db, deviceID.String())
  2299. m.fmut.Lock()
  2300. m.deviceStatRefs[deviceID] = sr
  2301. m.fmut.Unlock()
  2302. continue
  2303. }
  2304. delete(fromDevices, deviceID)
  2305. if fromCfg.Paused == toCfg.Paused {
  2306. continue
  2307. }
  2308. // Ignored folder was removed, reconnect to retrigger the prompt.
  2309. if !toCfg.Paused && len(fromCfg.IgnoredFolders) > len(toCfg.IgnoredFolders) {
  2310. closeDevices = append(closeDevices, deviceID)
  2311. }
  2312. if toCfg.Paused {
  2313. l.Infoln("Pausing", deviceID)
  2314. closeDevices = append(closeDevices, deviceID)
  2315. delete(clusterConfigDevices, deviceID)
  2316. m.evLogger.Log(events.DevicePaused, map[string]string{"device": deviceID.String()})
  2317. } else {
  2318. m.evLogger.Log(events.DeviceResumed, map[string]string{"device": deviceID.String()})
  2319. }
  2320. }
  2321. // Clean up after removed devices
  2322. removedDevices := make([]protocol.DeviceID, 0, len(fromDevices))
  2323. m.fmut.Lock()
  2324. for deviceID := range fromDevices {
  2325. delete(m.deviceStatRefs, deviceID)
  2326. removedDevices = append(removedDevices, deviceID)
  2327. delete(clusterConfigDevices, deviceID)
  2328. }
  2329. m.fmut.Unlock()
  2330. m.pmut.RLock()
  2331. for _, id := range closeDevices {
  2332. if conn, ok := m.conn[id]; ok {
  2333. go conn.Close(errDevicePaused)
  2334. }
  2335. }
  2336. for _, id := range removedDevices {
  2337. if conn, ok := m.conn[id]; ok {
  2338. go conn.Close(errDeviceRemoved)
  2339. }
  2340. }
  2341. m.pmut.RUnlock()
  2342. // Generating cluster-configs acquires fmut -> must happen outside of pmut.
  2343. m.resendClusterConfig(clusterConfigDevices.AsSlice())
  2344. ignoredDevices := observedDeviceSet(to.IgnoredDevices)
  2345. m.cleanPending(toDevices, toFolders, ignoredDevices, removedFolders)
  2346. m.globalRequestLimiter.setCapacity(1024 * to.Options.MaxConcurrentIncomingRequestKiB())
  2347. m.folderIOLimiter.setCapacity(to.Options.MaxFolderConcurrency())
  2348. // Some options don't require restart as those components handle it fine
  2349. // by themselves. Compare the options structs containing only the
  2350. // attributes that require restart and act apprioriately.
  2351. if !reflect.DeepEqual(from.Options.RequiresRestartOnly(), to.Options.RequiresRestartOnly()) {
  2352. l.Debugln(m, "requires restart, options differ")
  2353. return false
  2354. }
  2355. return true
  2356. }
  2357. func (m *model) cleanPending(existingDevices map[protocol.DeviceID]config.DeviceConfiguration, existingFolders map[string]config.FolderConfiguration, ignoredDevices deviceIDSet, removedFolders map[string]struct{}) {
  2358. pendingFolders, err := m.db.PendingFolders()
  2359. if err != nil {
  2360. l.Infof("Could not iterate through pending folder entries for cleanup: %v", err)
  2361. // Continue with pending devices below, loop is skipped.
  2362. }
  2363. for folderID, pf := range pendingFolders {
  2364. if _, ok := removedFolders[folderID]; ok {
  2365. // Forget pending folder device associations for recently removed
  2366. // folders as well, assuming the folder is no longer of interest
  2367. // at all (but might become pending again).
  2368. l.Debugf("Discarding pending removed folder %v from all devices", folderID)
  2369. m.db.RemovePendingFolder(folderID)
  2370. continue
  2371. }
  2372. for deviceID := range pf.OfferedBy {
  2373. if dev, ok := existingDevices[deviceID]; !ok {
  2374. l.Debugf("Discarding pending folder %v from unknown device %v", folderID, deviceID)
  2375. m.db.RemovePendingFolderForDevice(folderID, deviceID)
  2376. continue
  2377. } else if dev.IgnoredFolder(folderID) {
  2378. l.Debugf("Discarding now ignored pending folder %v for device %v", folderID, deviceID)
  2379. m.db.RemovePendingFolderForDevice(folderID, deviceID)
  2380. continue
  2381. }
  2382. if folderCfg, ok := existingFolders[folderID]; ok {
  2383. if folderCfg.SharedWith(deviceID) {
  2384. l.Debugf("Discarding now shared pending folder %v for device %v", folderID, deviceID)
  2385. m.db.RemovePendingFolderForDevice(folderID, deviceID)
  2386. }
  2387. }
  2388. }
  2389. }
  2390. pendingDevices, err := m.db.PendingDevices()
  2391. if err != nil {
  2392. l.Infof("Could not iterate through pending device entries for cleanup: %v", err)
  2393. return
  2394. }
  2395. for deviceID := range pendingDevices {
  2396. if _, ok := ignoredDevices[deviceID]; ok {
  2397. l.Debugf("Discarding now ignored pending device %v", deviceID)
  2398. m.db.RemovePendingDevice(deviceID)
  2399. continue
  2400. }
  2401. if _, ok := existingDevices[deviceID]; ok {
  2402. l.Debugf("Discarding now added pending device %v", deviceID)
  2403. m.db.RemovePendingDevice(deviceID)
  2404. continue
  2405. }
  2406. }
  2407. }
  2408. // checkFolderRunningLocked returns nil if the folder is up and running and a
  2409. // descriptive error if not.
  2410. // Need to hold (read) lock on m.fmut when calling this.
  2411. func (m *model) checkFolderRunningLocked(folder string) error {
  2412. _, ok := m.folderRunners[folder]
  2413. if ok {
  2414. return nil
  2415. }
  2416. if cfg, ok := m.cfg.Folder(folder); !ok {
  2417. return errFolderMissing
  2418. } else if cfg.Paused {
  2419. return ErrFolderPaused
  2420. }
  2421. return errFolderNotRunning
  2422. }
  2423. // PendingDevices lists unknown devices that tried to connect.
  2424. func (m *model) PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error) {
  2425. return m.db.PendingDevices()
  2426. }
  2427. // PendingFolders lists folders that we don't yet share with the offering devices. It
  2428. // returns the entries grouped by folder and filters for a given device unless the
  2429. // argument is specified as EmptyDeviceID.
  2430. func (m *model) PendingFolders(device protocol.DeviceID) (map[string]db.PendingFolder, error) {
  2431. return m.db.PendingFoldersForDevice(device)
  2432. }
  2433. // mapFolders returns a map of folder ID to folder configuration for the given
  2434. // slice of folder configurations.
  2435. func mapFolders(folders []config.FolderConfiguration) map[string]config.FolderConfiguration {
  2436. m := make(map[string]config.FolderConfiguration, len(folders))
  2437. for _, cfg := range folders {
  2438. m[cfg.ID] = cfg
  2439. }
  2440. return m
  2441. }
  2442. // mapDevices returns a map of device ID to nothing for the given slice of
  2443. // device IDs.
  2444. func mapDevices(devices []protocol.DeviceID) map[protocol.DeviceID]struct{} {
  2445. m := make(map[protocol.DeviceID]struct{}, len(devices))
  2446. for _, dev := range devices {
  2447. m[dev] = struct{}{}
  2448. }
  2449. return m
  2450. }
  2451. func observedDeviceSet(devices []config.ObservedDevice) deviceIDSet {
  2452. res := make(deviceIDSet, len(devices))
  2453. for _, dev := range devices {
  2454. res[dev.ID] = struct{}{}
  2455. }
  2456. return res
  2457. }
  2458. func readOffsetIntoBuf(fs fs.Filesystem, file string, offset int64, buf []byte) error {
  2459. fd, err := fs.Open(file)
  2460. if err != nil {
  2461. l.Debugln("readOffsetIntoBuf.Open", file, err)
  2462. return err
  2463. }
  2464. defer fd.Close()
  2465. _, err = fd.ReadAt(buf, offset)
  2466. if err != nil {
  2467. l.Debugln("readOffsetIntoBuf.ReadAt", file, err)
  2468. }
  2469. return err
  2470. }
  2471. // makeForgetUpdate takes an index update and constructs a download progress update
  2472. // causing to forget any progress for files which we've just been sent.
  2473. func makeForgetUpdate(files []protocol.FileInfo) []protocol.FileDownloadProgressUpdate {
  2474. updates := make([]protocol.FileDownloadProgressUpdate, 0, len(files))
  2475. for _, file := range files {
  2476. if file.IsSymlink() || file.IsDirectory() || file.IsDeleted() {
  2477. continue
  2478. }
  2479. updates = append(updates, protocol.FileDownloadProgressUpdate{
  2480. Name: file.Name,
  2481. Version: file.Version,
  2482. UpdateType: protocol.FileDownloadProgressUpdateTypeForget,
  2483. })
  2484. }
  2485. return updates
  2486. }
  2487. // folderDeviceSet is a set of (folder, deviceID) pairs
  2488. type folderDeviceSet map[string]map[protocol.DeviceID]struct{}
  2489. // set adds the (dev, folder) pair to the set
  2490. func (s folderDeviceSet) set(dev protocol.DeviceID, folder string) {
  2491. devs, ok := s[folder]
  2492. if !ok {
  2493. devs = make(map[protocol.DeviceID]struct{})
  2494. s[folder] = devs
  2495. }
  2496. devs[dev] = struct{}{}
  2497. }
  2498. // has returns true if the (dev, folder) pair is in the set
  2499. func (s folderDeviceSet) has(dev protocol.DeviceID, folder string) bool {
  2500. _, ok := s[folder][dev]
  2501. return ok
  2502. }
  2503. // hasDevice returns true if the device is set on any folder
  2504. func (s folderDeviceSet) hasDevice(dev protocol.DeviceID) bool {
  2505. for _, devices := range s {
  2506. if _, ok := devices[dev]; ok {
  2507. return true
  2508. }
  2509. }
  2510. return false
  2511. }
  2512. type fileInfoBatch struct {
  2513. infos []protocol.FileInfo
  2514. size int
  2515. flushFn func([]protocol.FileInfo) error
  2516. }
  2517. func newFileInfoBatch(fn func([]protocol.FileInfo) error) *fileInfoBatch {
  2518. return &fileInfoBatch{
  2519. infos: make([]protocol.FileInfo, 0, maxBatchSizeFiles),
  2520. flushFn: fn,
  2521. }
  2522. }
  2523. func (b *fileInfoBatch) append(f protocol.FileInfo) {
  2524. b.infos = append(b.infos, f)
  2525. b.size += f.ProtoSize()
  2526. }
  2527. func (b *fileInfoBatch) full() bool {
  2528. return len(b.infos) >= maxBatchSizeFiles || b.size >= maxBatchSizeBytes
  2529. }
  2530. func (b *fileInfoBatch) flushIfFull() error {
  2531. if b.full() {
  2532. return b.flush()
  2533. }
  2534. return nil
  2535. }
  2536. func (b *fileInfoBatch) flush() error {
  2537. if len(b.infos) == 0 {
  2538. return nil
  2539. }
  2540. if err := b.flushFn(b.infos); err != nil {
  2541. return err
  2542. }
  2543. b.reset()
  2544. return nil
  2545. }
  2546. func (b *fileInfoBatch) reset() {
  2547. b.infos = b.infos[:0]
  2548. b.size = 0
  2549. }
  2550. // syncMutexMap is a type safe wrapper for a sync.Map that holds mutexes
  2551. type syncMutexMap struct {
  2552. inner stdsync.Map
  2553. }
  2554. func (m *syncMutexMap) Get(key string) sync.Mutex {
  2555. v, _ := m.inner.LoadOrStore(key, sync.NewMutex())
  2556. return v.(sync.Mutex)
  2557. }
  2558. type deviceIDSet map[protocol.DeviceID]struct{}
  2559. func (s deviceIDSet) add(ids []protocol.DeviceID) {
  2560. for _, id := range ids {
  2561. if _, ok := s[id]; !ok {
  2562. s[id] = struct{}{}
  2563. }
  2564. }
  2565. }
  2566. func (s deviceIDSet) AsSlice() []protocol.DeviceID {
  2567. ids := make([]protocol.DeviceID, 0, len(s))
  2568. for id := range s {
  2569. ids = append(ids, id)
  2570. }
  2571. return ids
  2572. }
  2573. func encryptionTokenPath(cfg config.FolderConfiguration) string {
  2574. return filepath.Join(cfg.MarkerName, "syncthing-encryption_password_token")
  2575. }
  2576. type storedEncryptionToken struct {
  2577. FolderID string
  2578. Token []byte
  2579. }
  2580. func readEncryptionToken(cfg config.FolderConfiguration) ([]byte, error) {
  2581. fd, err := cfg.Filesystem().Open(encryptionTokenPath(cfg))
  2582. if err != nil {
  2583. return nil, err
  2584. }
  2585. defer fd.Close()
  2586. var stored storedEncryptionToken
  2587. if err := json.NewDecoder(fd).Decode(&stored); err != nil {
  2588. return nil, err
  2589. }
  2590. return stored.Token, nil
  2591. }
  2592. func writeEncryptionToken(token []byte, cfg config.FolderConfiguration) error {
  2593. tokenName := encryptionTokenPath(cfg)
  2594. fd, err := cfg.Filesystem().OpenFile(tokenName, fs.OptReadWrite|fs.OptCreate, 0666)
  2595. if err != nil {
  2596. return err
  2597. }
  2598. defer fd.Close()
  2599. return json.NewEncoder(fd).Encode(storedEncryptionToken{
  2600. FolderID: cfg.ID,
  2601. Token: token,
  2602. })
  2603. }