2015-10-27 11:37:03 +01:00
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
2017-02-09 07:52:18 +01:00
// You can obtain one at https://mozilla.org/MPL/2.0/.
2015-10-27 11:37:03 +01:00
package config
import (
2017-10-24 07:58:55 +00:00
"errors"
2016-11-17 17:12:41 +02:00
"fmt"
2015-10-27 11:37:03 +01:00
"runtime"
2017-08-19 14:36:56 +00:00
"github.com/syncthing/syncthing/lib/fs"
2015-10-27 11:37:03 +01:00
"github.com/syncthing/syncthing/lib/protocol"
)
2017-10-24 07:58:55 +00:00
var (
errPathMissing = errors . New ( "folder path missing" )
errMarkerMissing = errors . New ( "folder marker missing" )
)
2015-10-27 11:37:03 +01:00
type FolderConfiguration struct {
ID string `xml:"id,attr" json:"id"`
2016-03-11 09:48:46 +00:00
Label string `xml:"label,attr" json:"label"`
2017-08-19 14:36:56 +00:00
FilesystemType fs . FilesystemType `xml:"filesystemType" json:"filesystemType"`
Path string `xml:"path,attr" json:"path"`
2016-05-04 11:26:36 +00:00
Type FolderType `xml:"type,attr" json:"type"`
2015-10-27 11:37:03 +01:00
Devices [] FolderDeviceConfiguration `xml:"device" json:"devices"`
RescanIntervalS int `xml:"rescanIntervalS,attr" json:"rescanIntervalS"`
2017-10-20 14:52:55 +00:00
FSWatcherEnabled bool `xml:"fsWatcherEnabled,attr" json:"fsWatcherEnabled"`
FSWatcherDelayS int `xml:"fsWatcherDelayS,attr" json:"fsWatcherDelayS"`
2015-10-27 11:37:03 +01:00
IgnorePerms bool `xml:"ignorePerms,attr" json:"ignorePerms"`
AutoNormalize bool `xml:"autoNormalize,attr" json:"autoNormalize"`
2017-04-12 09:01:19 +00:00
MinDiskFree Size `xml:"minDiskFree" json:"minDiskFree"`
2015-10-27 11:37:03 +01:00
Versioning VersioningConfiguration `xml:"versioning" json:"versioning"`
Copiers int `xml:"copiers" json:"copiers"` // This defines how many files are handled concurrently.
Pullers int `xml:"pullers" json:"pullers"` // Defines how many blocks are fetched at the same time, possibly between separate copier routines.
Hashers int `xml:"hashers" json:"hashers"` // Less than one sets the value to the number of cores. These are CPU bound due to hashing.
Order PullOrder `xml:"order" json:"order"`
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
MaxConflicts int `xml:"maxConflicts" json:"maxConflicts"`
2015-11-21 16:30:53 +01:00
DisableSparseFiles bool `xml:"disableSparseFiles" json:"disableSparseFiles"`
2016-04-15 10:59:41 +00:00
DisableTempIndexes bool `xml:"disableTempIndexes" json:"disableTempIndexes"`
2016-12-21 18:41:25 +00:00
Paused bool `xml:"paused" json:"paused"`
2017-01-04 21:04:13 +00:00
WeakHashThresholdPct int `xml:"weakHashThresholdPct" json:"weakHashThresholdPct"` // Use weak hash if more than X percent of the file has changed. Set to -1 to always use weak hash.
2015-10-27 11:37:03 +01:00
2017-08-19 14:36:56 +00:00
cachedFilesystem fs . Filesystem
2016-05-04 10:47:33 +00:00
2017-04-12 09:01:19 +00:00
DeprecatedReadOnly bool `xml:"ro,attr,omitempty" json:"-"`
2017-04-27 14:46:19 +09:00
DeprecatedMinDiskFreePct float64 `xml:"minDiskFreePct,omitempty" json:"-"`
2015-10-27 11:37:03 +01:00
}
type FolderDeviceConfiguration struct {
2016-11-07 16:40:48 +00:00
DeviceID protocol . DeviceID `xml:"id,attr" json:"deviceID"`
IntroducedBy protocol . DeviceID `xml:"introducedBy,attr" json:"introducedBy"`
2015-10-27 11:37:03 +01:00
}
2017-08-19 14:36:56 +00:00
func NewFolderConfiguration ( id string , fsType fs . FilesystemType , path string ) FolderConfiguration {
2015-11-07 09:47:31 +01:00
f := FolderConfiguration {
2017-08-19 14:36:56 +00:00
ID : id ,
FilesystemType : fsType ,
Path : path ,
2015-11-07 09:47:31 +01:00
}
f . prepare ()
return f
}
2015-10-27 11:37:03 +01:00
func ( f FolderConfiguration ) Copy () FolderConfiguration {
c := f
c . Devices = make ([] FolderDeviceConfiguration , len ( f . Devices ))
copy ( c . Devices , f . Devices )
2015-10-27 11:53:42 +01:00
c . Versioning = f . Versioning . Copy ()
2015-10-27 11:37:03 +01:00
return c
}
2017-08-19 14:36:56 +00:00
func ( f FolderConfiguration ) Filesystem () fs . Filesystem {
2015-10-27 11:37:03 +01:00
// This is intentionally not a pointer method, because things like
2017-08-19 14:36:56 +00:00
// cfg.Folders["default"].Filesystem() should be valid.
if f . cachedFilesystem == nil && f . Path != "" {
l . Infoln ( "bug: uncached filesystem call (should only happen in tests)" )
return fs . NewFilesystem ( f . FilesystemType , f . Path )
2015-10-27 11:37:03 +01:00
}
2017-08-19 14:36:56 +00:00
return f . cachedFilesystem
2015-10-27 11:37:03 +01:00
}
func ( f * FolderConfiguration ) CreateMarker () error {
2017-10-24 07:58:55 +00:00
if err := f . CheckPath (); err != errMarkerMissing {
return err
2015-10-27 11:37:03 +01:00
}
2017-10-24 07:58:55 +00:00
permBits := fs . FileMode ( 0777 )
if runtime . GOOS == "windows" {
// Windows has no umask so we must chose a safer set of bits to
// begin with.
permBits = 0700
}
fs := f . Filesystem ()
err := fs . Mkdir ( ".stfolder" , permBits )
if err != nil {
return err
}
if dir , err := fs . Open ( "." ); err != nil {
l . Debugln ( "folder marker: open . failed:" , err )
} else if err := dir . Sync (); err != nil {
l . Debugln ( "folder marker: fsync . failed:" , err )
}
fs . Hide ( ".stfolder" )
2015-10-27 11:37:03 +01:00
return nil
}
2017-10-24 07:58:55 +00:00
// CheckPath returns nil if the folder root exists and contains the marker file
func ( f * FolderConfiguration ) CheckPath () error {
fi , err := f . Filesystem (). Stat ( "." )
if err != nil || ! fi . IsDir () {
return errPathMissing
}
_ , err = f . Filesystem (). Stat ( ".stfolder" )
if err != nil {
return errMarkerMissing
}
return nil
2015-10-27 11:37:03 +01:00
}
2017-04-23 23:50:56 +00:00
func ( f * FolderConfiguration ) CreateRoot () ( err error ) {
// Directory permission bits. Will be filtered down to something
// sane by umask on Unixes.
2017-08-19 14:36:56 +00:00
permBits := fs . FileMode ( 0777 )
2017-04-23 23:50:56 +00:00
if runtime . GOOS == "windows" {
// Windows has no umask so we must chose a safer set of bits to
// begin with.
permBits = 0700
}
2017-08-19 14:36:56 +00:00
filesystem := f . Filesystem ()
if _ , err = filesystem . Stat ( "." ); fs . IsNotExist ( err ) {
if err = filesystem . MkdirAll ( "." , permBits ); err != nil {
l . Warnf ( "Creating directory for %v: %v" , f . Description (), err )
2017-04-23 23:50:56 +00:00
}
}
return err
}
2016-11-17 17:12:41 +02:00
func ( f FolderConfiguration ) Description () string {
2016-12-19 10:12:06 +01:00
if f . Label == "" {
return f . ID
}
2016-11-17 17:12:41 +02:00
return fmt . Sprintf ( "%q (%s)" , f . Label , f . ID )
}
2015-10-27 11:37:03 +01:00
func ( f * FolderConfiguration ) DeviceIDs () [] protocol . DeviceID {
deviceIDs := make ([] protocol . DeviceID , len ( f . Devices ))
for i , n := range f . Devices {
deviceIDs [ i ] = n . DeviceID
}
return deviceIDs
}
2015-11-05 08:01:47 +00:00
func ( f * FolderConfiguration ) prepare () {
2017-08-19 14:36:56 +00:00
if f . Path != "" {
f . cachedFilesystem = fs . NewFilesystem ( f . FilesystemType , f . Path )
2015-11-05 08:01:47 +00:00
}
if f . RescanIntervalS > MaxRescanIntervalS {
f . RescanIntervalS = MaxRescanIntervalS
} else if f . RescanIntervalS < 0 {
f . RescanIntervalS = 0
}
2016-05-09 11:30:19 +00:00
2017-10-20 14:52:55 +00:00
if f . FSWatcherDelayS <= 0 {
f . FSWatcherEnabled = false
f . FSWatcherDelayS = 10
}
2016-05-09 11:30:19 +00:00
if f . Versioning . Params == nil {
f . Versioning . Params = make ( map [ string ] string )
}
2017-01-04 21:04:13 +00:00
if f . WeakHashThresholdPct == 0 {
f . WeakHashThresholdPct = 25
}
2015-11-05 08:01:47 +00:00
}
2015-10-27 11:37:03 +01:00
type FolderDeviceConfigurationList [] FolderDeviceConfiguration
func ( l FolderDeviceConfigurationList ) Less ( a , b int ) bool {
return l [ a ]. DeviceID . Compare ( l [ b ]. DeviceID ) == - 1
}
func ( l FolderDeviceConfigurationList ) Swap ( a , b int ) {
l [ a ], l [ b ] = l [ b ], l [ a ]
}
func ( l FolderDeviceConfigurationList ) Len () int {
return len ( l )
}
2017-10-24 07:58:55 +00:00
func ( f * FolderConfiguration ) CheckFreeSpace () ( err error ) {
return checkFreeSpace ( f . MinDiskFree , f . Filesystem ())
}