|
@@ -32,7 +32,7 @@ import (
|
|
)
|
|
)
|
|
|
|
|
|
func init() {
|
|
func init() {
|
|
- folderFactories[config.FolderTypeReadWrite] = newRWFolder
|
|
|
|
|
|
+ folderFactories[config.FolderTypeSendReceive] = newSendReceiveFolder
|
|
}
|
|
}
|
|
|
|
|
|
// A pullBlockState is passed to the puller routine for each block that needs
|
|
// A pullBlockState is passed to the puller routine for each block that needs
|
|
@@ -78,7 +78,7 @@ type dbUpdateJob struct {
|
|
jobType int
|
|
jobType int
|
|
}
|
|
}
|
|
|
|
|
|
-type rwFolder struct {
|
|
|
|
|
|
+type sendReceiveFolder struct {
|
|
folder
|
|
folder
|
|
|
|
|
|
mtimeFS *fs.MtimeFS
|
|
mtimeFS *fs.MtimeFS
|
|
@@ -109,8 +109,8 @@ type rwFolder struct {
|
|
initialScanCompleted chan (struct{}) // exposed for testing
|
|
initialScanCompleted chan (struct{}) // exposed for testing
|
|
}
|
|
}
|
|
|
|
|
|
-func newRWFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, mtimeFS *fs.MtimeFS) service {
|
|
|
|
- f := &rwFolder{
|
|
|
|
|
|
+func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, mtimeFS *fs.MtimeFS) service {
|
|
|
|
+ f := &sendReceiveFolder{
|
|
folder: folder{
|
|
folder: folder{
|
|
stateTracker: newStateTracker(cfg.ID),
|
|
stateTracker: newStateTracker(cfg.ID),
|
|
scan: newFolderScanner(cfg),
|
|
scan: newFolderScanner(cfg),
|
|
@@ -146,7 +146,7 @@ func newRWFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Ver
|
|
return f
|
|
return f
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) configureCopiersAndPullers(cfg config.FolderConfiguration) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) configureCopiersAndPullers(cfg config.FolderConfiguration) {
|
|
if f.copiers == 0 {
|
|
if f.copiers == 0 {
|
|
f.copiers = defaultCopiers
|
|
f.copiers = defaultCopiers
|
|
}
|
|
}
|
|
@@ -170,13 +170,13 @@ func (f *rwFolder) configureCopiersAndPullers(cfg config.FolderConfiguration) {
|
|
// Helper function to check whether either the ignorePerm flag has been
|
|
// Helper function to check whether either the ignorePerm flag has been
|
|
// set on the local host or the FlagNoPermBits has been set on the file/dir
|
|
// set on the local host or the FlagNoPermBits has been set on the file/dir
|
|
// which is being pulled.
|
|
// which is being pulled.
|
|
-func (f *rwFolder) ignorePermissions(file protocol.FileInfo) bool {
|
|
|
|
|
|
+func (f *sendReceiveFolder) ignorePermissions(file protocol.FileInfo) bool {
|
|
return f.ignorePerms || file.NoPermissions
|
|
return f.ignorePerms || file.NoPermissions
|
|
}
|
|
}
|
|
|
|
|
|
// Serve will run scans and pulls. It will return when Stop()ed or on a
|
|
// Serve will run scans and pulls. It will return when Stop()ed or on a
|
|
// critical error.
|
|
// critical error.
|
|
-func (f *rwFolder) Serve() {
|
|
|
|
|
|
+func (f *sendReceiveFolder) Serve() {
|
|
l.Debugln(f, "starting")
|
|
l.Debugln(f, "starting")
|
|
defer l.Debugln(f, "exiting")
|
|
defer l.Debugln(f, "exiting")
|
|
|
|
|
|
@@ -317,7 +317,7 @@ func (f *rwFolder) Serve() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) IndexUpdated() {
|
|
|
|
|
|
+func (f *sendReceiveFolder) IndexUpdated() {
|
|
select {
|
|
select {
|
|
case f.remoteIndex <- struct{}{}:
|
|
case f.remoteIndex <- struct{}{}:
|
|
default:
|
|
default:
|
|
@@ -328,15 +328,15 @@ func (f *rwFolder) IndexUpdated() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) String() string {
|
|
|
|
- return fmt.Sprintf("rwFolder/%s@%p", f.folderID, f)
|
|
|
|
|
|
+func (f *sendReceiveFolder) String() string {
|
|
|
|
+ return fmt.Sprintf("sendReceiveFolder/%s@%p", f.folderID, f)
|
|
}
|
|
}
|
|
|
|
|
|
// pullerIteration runs a single puller iteration for the given folder and
|
|
// pullerIteration runs a single puller iteration for the given folder and
|
|
// returns the number items that should have been synced (even those that
|
|
// returns the number items that should have been synced (even those that
|
|
// might have failed). One puller iteration handles all files currently
|
|
// might have failed). One puller iteration handles all files currently
|
|
// flagged as needed in the folder.
|
|
// flagged as needed in the folder.
|
|
-func (f *rwFolder) pullerIteration(ignores *ignore.Matcher) int {
|
|
|
|
|
|
+func (f *sendReceiveFolder) pullerIteration(ignores *ignore.Matcher) int {
|
|
pullChan := make(chan pullBlockState)
|
|
pullChan := make(chan pullBlockState)
|
|
copyChan := make(chan copyBlocksState)
|
|
copyChan := make(chan copyBlocksState)
|
|
finisherChan := make(chan *sharedPullerState)
|
|
finisherChan := make(chan *sharedPullerState)
|
|
@@ -603,7 +603,7 @@ nextFile:
|
|
}
|
|
}
|
|
|
|
|
|
// handleDir creates or updates the given directory
|
|
// handleDir creates or updates the given directory
|
|
-func (f *rwFolder) handleDir(file protocol.FileInfo) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) handleDir(file protocol.FileInfo) {
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// care not declare another err.
|
|
// care not declare another err.
|
|
var err error
|
|
var err error
|
|
@@ -705,7 +705,7 @@ func (f *rwFolder) handleDir(file protocol.FileInfo) {
|
|
}
|
|
}
|
|
|
|
|
|
// handleSymlink creates or updates the given symlink
|
|
// handleSymlink creates or updates the given symlink
|
|
-func (f *rwFolder) handleSymlink(file protocol.FileInfo) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) {
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// care not declare another err.
|
|
// care not declare another err.
|
|
var err error
|
|
var err error
|
|
@@ -779,7 +779,7 @@ func (f *rwFolder) handleSymlink(file protocol.FileInfo) {
|
|
}
|
|
}
|
|
|
|
|
|
// deleteDir attempts to delete the given directory
|
|
// deleteDir attempts to delete the given directory
|
|
-func (f *rwFolder) deleteDir(file protocol.FileInfo, matcher *ignore.Matcher) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, matcher *ignore.Matcher) {
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// care not declare another err.
|
|
// care not declare another err.
|
|
var err error
|
|
var err error
|
|
@@ -837,7 +837,7 @@ func (f *rwFolder) deleteDir(file protocol.FileInfo, matcher *ignore.Matcher) {
|
|
}
|
|
}
|
|
|
|
|
|
// deleteFile attempts to delete the given file
|
|
// deleteFile attempts to delete the given file
|
|
-func (f *rwFolder) deleteFile(file protocol.FileInfo) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) deleteFile(file protocol.FileInfo) {
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// care not declare another err.
|
|
// care not declare another err.
|
|
var err error
|
|
var err error
|
|
@@ -895,7 +895,7 @@ func (f *rwFolder) deleteFile(file protocol.FileInfo) {
|
|
|
|
|
|
// renameFile attempts to rename an existing file to a destination
|
|
// renameFile attempts to rename an existing file to a destination
|
|
// and set the right attributes on it.
|
|
// and set the right attributes on it.
|
|
-func (f *rwFolder) renameFile(source, target protocol.FileInfo) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo) {
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// Used in the defer closure below, updated by the function body. Take
|
|
// care not declare another err.
|
|
// care not declare another err.
|
|
var err error
|
|
var err error
|
|
@@ -1019,7 +1019,7 @@ func (f *rwFolder) renameFile(source, target protocol.FileInfo) {
|
|
|
|
|
|
// handleFile queues the copies and pulls as necessary for a single new or
|
|
// handleFile queues the copies and pulls as necessary for a single new or
|
|
// changed file.
|
|
// changed file.
|
|
-func (f *rwFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksState, finisherChan chan<- *sharedPullerState) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksState, finisherChan chan<- *sharedPullerState) {
|
|
curFile, hasCurFile := f.model.CurrentFolderFile(f.folderID, file.Name)
|
|
curFile, hasCurFile := f.model.CurrentFolderFile(f.folderID, file.Name)
|
|
|
|
|
|
if hasCurFile && len(curFile.Blocks) == len(file.Blocks) && scanner.BlocksEqual(curFile.Blocks, file.Blocks) {
|
|
if hasCurFile && len(curFile.Blocks) == len(file.Blocks) && scanner.BlocksEqual(curFile.Blocks, file.Blocks) {
|
|
@@ -1183,7 +1183,7 @@ func (f *rwFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocks
|
|
|
|
|
|
// shortcutFile sets file mode and modification time, when that's the only
|
|
// shortcutFile sets file mode and modification time, when that's the only
|
|
// thing that has changed.
|
|
// thing that has changed.
|
|
-func (f *rwFolder) shortcutFile(file protocol.FileInfo) error {
|
|
|
|
|
|
+func (f *sendReceiveFolder) shortcutFile(file protocol.FileInfo) error {
|
|
realName, err := rootedJoinedPath(f.dir, file.Name)
|
|
realName, err := rootedJoinedPath(f.dir, file.Name)
|
|
if err != nil {
|
|
if err != nil {
|
|
f.newError(file.Name, err)
|
|
f.newError(file.Name, err)
|
|
@@ -1210,7 +1210,7 @@ func (f *rwFolder) shortcutFile(file protocol.FileInfo) error {
|
|
|
|
|
|
// copierRoutine reads copierStates until the in channel closes and performs
|
|
// copierRoutine reads copierStates until the in channel closes and performs
|
|
// the relevant copies when possible, or passes it to the puller routine.
|
|
// the relevant copies when possible, or passes it to the puller routine.
|
|
-func (f *rwFolder) copierRoutine(in <-chan copyBlocksState, pullChan chan<- pullBlockState, out chan<- *sharedPullerState) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan chan<- pullBlockState, out chan<- *sharedPullerState) {
|
|
buf := make([]byte, protocol.BlockSize)
|
|
buf := make([]byte, protocol.BlockSize)
|
|
|
|
|
|
for state := range in {
|
|
for state := range in {
|
|
@@ -1348,7 +1348,7 @@ func (f *rwFolder) copierRoutine(in <-chan copyBlocksState, pullChan chan<- pull
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) pullerRoutine(in <-chan pullBlockState, out chan<- *sharedPullerState) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) pullerRoutine(in <-chan pullBlockState, out chan<- *sharedPullerState) {
|
|
for state := range in {
|
|
for state := range in {
|
|
if state.failed() != nil {
|
|
if state.failed() != nil {
|
|
out <- state.sharedPullerState
|
|
out <- state.sharedPullerState
|
|
@@ -1421,7 +1421,7 @@ func (f *rwFolder) pullerRoutine(in <-chan pullBlockState, out chan<- *sharedPul
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) performFinish(state *sharedPullerState) error {
|
|
|
|
|
|
+func (f *sendReceiveFolder) performFinish(state *sharedPullerState) error {
|
|
// Set the correct permission bits on the new file
|
|
// Set the correct permission bits on the new file
|
|
if !f.ignorePermissions(state.file) {
|
|
if !f.ignorePermissions(state.file) {
|
|
if err := os.Chmod(state.tempName, os.FileMode(state.file.Permissions&0777)); err != nil {
|
|
if err := os.Chmod(state.tempName, os.FileMode(state.file.Permissions&0777)); err != nil {
|
|
@@ -1483,7 +1483,7 @@ func (f *rwFolder) performFinish(state *sharedPullerState) error {
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) finisherRoutine(in <-chan *sharedPullerState) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) finisherRoutine(in <-chan *sharedPullerState) {
|
|
for state := range in {
|
|
for state := range in {
|
|
if closed, err := state.finalClose(); closed {
|
|
if closed, err := state.finalClose(); closed {
|
|
l.Debugln(f, "closing", state.file.Name)
|
|
l.Debugln(f, "closing", state.file.Name)
|
|
@@ -1514,17 +1514,17 @@ func (f *rwFolder) finisherRoutine(in <-chan *sharedPullerState) {
|
|
}
|
|
}
|
|
|
|
|
|
// Moves the given filename to the front of the job queue
|
|
// Moves the given filename to the front of the job queue
|
|
-func (f *rwFolder) BringToFront(filename string) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) BringToFront(filename string) {
|
|
f.queue.BringToFront(filename)
|
|
f.queue.BringToFront(filename)
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) Jobs() ([]string, []string) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) Jobs() ([]string, []string) {
|
|
return f.queue.Jobs()
|
|
return f.queue.Jobs()
|
|
}
|
|
}
|
|
|
|
|
|
// dbUpdaterRoutine aggregates db updates and commits them in batches no
|
|
// dbUpdaterRoutine aggregates db updates and commits them in batches no
|
|
// larger than 1000 items, and no more delayed than 2 seconds.
|
|
// larger than 1000 items, and no more delayed than 2 seconds.
|
|
-func (f *rwFolder) dbUpdaterRoutine() {
|
|
|
|
|
|
+func (f *sendReceiveFolder) dbUpdaterRoutine() {
|
|
const (
|
|
const (
|
|
maxBatchSize = 1000
|
|
maxBatchSize = 1000
|
|
maxBatchTime = 2 * time.Second
|
|
maxBatchTime = 2 * time.Second
|
|
@@ -1635,7 +1635,7 @@ loop:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) inConflict(current, replacement protocol.Vector) bool {
|
|
|
|
|
|
+func (f *sendReceiveFolder) inConflict(current, replacement protocol.Vector) bool {
|
|
if current.Concurrent(replacement) {
|
|
if current.Concurrent(replacement) {
|
|
// Obvious case
|
|
// Obvious case
|
|
return true
|
|
return true
|
|
@@ -1661,7 +1661,7 @@ func removeAvailability(availabilities []Availability, availability Availability
|
|
return availabilities
|
|
return availabilities
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) moveForConflict(name string) error {
|
|
|
|
|
|
+func (f *sendReceiveFolder) moveForConflict(name string) error {
|
|
if strings.Contains(filepath.Base(name), ".sync-conflict-") {
|
|
if strings.Contains(filepath.Base(name), ".sync-conflict-") {
|
|
l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.")
|
|
l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.")
|
|
if err := os.Remove(name); err != nil && !os.IsNotExist(err) {
|
|
if err := os.Remove(name); err != nil && !os.IsNotExist(err) {
|
|
@@ -1705,7 +1705,7 @@ func (f *rwFolder) moveForConflict(name string) error {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) newError(path string, err error) {
|
|
|
|
|
|
+func (f *sendReceiveFolder) newError(path string, err error) {
|
|
f.errorsMut.Lock()
|
|
f.errorsMut.Lock()
|
|
defer f.errorsMut.Unlock()
|
|
defer f.errorsMut.Unlock()
|
|
|
|
|
|
@@ -1719,13 +1719,13 @@ func (f *rwFolder) newError(path string, err error) {
|
|
f.errors[path] = err.Error()
|
|
f.errors[path] = err.Error()
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) clearErrors() {
|
|
|
|
|
|
+func (f *sendReceiveFolder) clearErrors() {
|
|
f.errorsMut.Lock()
|
|
f.errorsMut.Lock()
|
|
f.errors = make(map[string]string)
|
|
f.errors = make(map[string]string)
|
|
f.errorsMut.Unlock()
|
|
f.errorsMut.Unlock()
|
|
}
|
|
}
|
|
|
|
|
|
-func (f *rwFolder) currentErrors() []fileError {
|
|
|
|
|
|
+func (f *sendReceiveFolder) currentErrors() []fileError {
|
|
f.errorsMut.Lock()
|
|
f.errorsMut.Lock()
|
|
errors := make([]fileError, 0, len(f.errors))
|
|
errors := make([]fileError, 0, len(f.errors))
|
|
for path, err := range f.errors {
|
|
for path, err := range f.errors {
|