diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go
index 7966668e..8160266a 100644
--- a/cmd/syncthing/gui.go
+++ b/cmd/syncthing/gui.go
@@ -63,7 +63,7 @@ func init() {
func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) error {
var err error
- cert, err := loadCert(confDir, "https-")
+ cert, err := tls.LoadX509KeyPair(locations[locHttpsCertFile], locations[locHttpsKeyFile])
if err != nil {
l.Infoln("Loading HTTPS certificate:", err)
l.Infoln("Creating new HTTPS certificate")
@@ -76,8 +76,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
name = tlsDefaultCommonName
}
- newCertificate(confDir, "https-", name)
- cert, err = loadCert(confDir, "https-")
+ cert, err = newCertificate(locations[locHttpsCertFile], locations[locHttpsKeyFile], name)
}
if err != nil {
return err
diff --git a/cmd/syncthing/gui_csrf.go b/cmd/syncthing/gui_csrf.go
index 988200ea..f9116ec3 100644
--- a/cmd/syncthing/gui_csrf.go
+++ b/cmd/syncthing/gui_csrf.go
@@ -11,7 +11,6 @@ import (
"fmt"
"net/http"
"os"
- "path/filepath"
"strings"
"sync"
"time"
@@ -92,7 +91,7 @@ func newCsrfToken() string {
}
func saveCsrfTokens() {
- name := filepath.Join(confDir, "csrftokens.txt")
+ name := locations[locCsrfTokens]
tmp := fmt.Sprintf("%s.tmp.%d", name, time.Now().UnixNano())
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
@@ -117,8 +116,7 @@ func saveCsrfTokens() {
}
func loadCsrfTokens() {
- name := filepath.Join(confDir, "csrftokens.txt")
- f, err := os.Open(name)
+ f, err := os.Open(locations[locCsrfTokens])
if err != nil {
return
}
diff --git a/cmd/syncthing/locations.go b/cmd/syncthing/locations.go
new file mode 100644
index 00000000..8f57ce44
--- /dev/null
+++ b/cmd/syncthing/locations.go
@@ -0,0 +1,109 @@
+// Copyright (C) 2015 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/syncthing/syncthing/internal/osutil"
+)
+
+type locationEnum string
+
+// Use strings as keys to make printout and serialization of the locations map
+// more meaningful.
+const (
+ locConfigFile locationEnum = "config"
+ locCertFile = "certFile"
+ locKeyFile = "keyFile"
+ locHttpsCertFile = "httpsCertFile"
+ locHttpsKeyFile = "httpsKeyFile"
+ locDatabase = "database"
+ locLogFile = "logFile"
+ locCsrfTokens = "csrfTokens"
+ locPanicLog = "panicLog"
+ locDefFolder = "defFolder"
+)
+
+// Platform dependent directories
+var baseDirs = map[string]string{
+ "config": defaultConfigDir(), // Overridden by -home flag
+ "home": homeDir(), // User's home directory, *not* -home flag
+}
+
+// Use the variables from baseDirs here
+var locations = map[locationEnum]string{
+ locConfigFile: "${config}/config.xml",
+ locCertFile: "${config}/cert.pem",
+ locKeyFile: "${config}/key.pem",
+ locHttpsCertFile: "${config}/https-cert.pem",
+ locHttpsKeyFile: "${config}/https-key.pem",
+ locDatabase: "${config}/index-v0.11.0.db",
+ locLogFile: "${config}/syncthing.log", // -logfile on Windows
+ locCsrfTokens: "${config}/csrftokens.txt",
+ locPanicLog: "${config}/panic-20060102-150405.log", // passed through time.Format()
+ locDefFolder: "${home}/Sync",
+}
+
+// expandLocations replaces the variables in the location map with actual
+// directory locations.
+func expandLocations() error {
+ for key, dir := range locations {
+ for varName, value := range baseDirs {
+ dir = strings.Replace(dir, "${"+varName+"}", value, -1)
+ }
+ var err error
+ dir, err = osutil.ExpandTilde(dir)
+ if err != nil {
+ return err
+ }
+ locations[key] = dir
+ }
+ return nil
+}
+
+// defaultConfigDir returns the default configuration directory, as figured
+// out by various the environment variables present on each platform, or dies
+// trying.
+func defaultConfigDir() string {
+ switch runtime.GOOS {
+ case "windows":
+ if p := os.Getenv("LocalAppData"); p != "" {
+ return filepath.Join(p, "Syncthing")
+ }
+ return filepath.Join(os.Getenv("AppData"), "Syncthing")
+
+ case "darwin":
+ dir, err := osutil.ExpandTilde("~/Library/Application Support/Syncthing")
+ if err != nil {
+ l.Fatalln(err)
+ }
+ return dir
+
+ default:
+ if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
+ return filepath.Join(xdgCfg, "syncthing")
+ }
+ dir, err := osutil.ExpandTilde("~/.config/syncthing")
+ if err != nil {
+ l.Fatalln(err)
+ }
+ return dir
+ }
+}
+
+// homeDir returns the user's home directory, or dies trying.
+func homeDir() string {
+ home, err := osutil.ExpandTilde("~")
+ if err != nil {
+ l.Fatalln(err)
+ }
+ return home
+}
diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go
index 94b65336..eea9f9d8 100644
--- a/cmd/syncthing/main.go
+++ b/cmd/syncthing/main.go
@@ -199,17 +199,11 @@ var (
)
func main() {
- defConfDir, err := getDefaultConfDir()
- if err != nil {
- l.Fatalln("home:", err)
- }
-
if runtime.GOOS == "windows" {
// On Windows, we use a log file by default. Setting the -logfile flag
- // to the empty string disables this behavior.
+ // to "-" disables this behavior.
- logFile = filepath.Join(defConfDir, "syncthing.log")
- flag.StringVar(&logFile, "logfile", logFile, "Log file name (blank for stdout)")
+ flag.StringVar(&logFile, "logfile", "", "Log file name (use \"-\" for stdout)")
// We also add an option to hide the console window
flag.BoolVar(&noConsole, "no-console", false, "Hide console window")
@@ -229,23 +223,30 @@ func main() {
flag.BoolVar(&showVersion, "version", false, "Show version")
flag.StringVar(&upgradeTo, "upgrade-to", upgradeTo, "Force upgrade directly from specified URL")
- flag.Usage = usageFor(flag.CommandLine, usage, fmt.Sprintf(extraUsage, defConfDir))
+ flag.Usage = usageFor(flag.CommandLine, usage, fmt.Sprintf(extraUsage, baseDirs["config"]))
flag.Parse()
if noConsole {
osutil.HideConsole()
}
- if confDir == "" {
+ if confDir != "" {
// Not set as default above because the string can be really long.
- confDir = defConfDir
+ baseDirs["config"] = confDir
}
- if confDir != defConfDir && filepath.Dir(logFile) == defConfDir {
- // The user changed the config dir with -home, but not the log file
- // location. In this case we assume they meant for the logfile to
- // still live in it's default location *relative to the config dir*.
- logFile = filepath.Join(confDir, "syncthing.log")
+ if runtime.GOOS == "windows" {
+ if logFile == "" {
+ // Use the default log file location
+ logFile = locations[locLogFile]
+ } else if logFile == "-" {
+ // Don't use a logFile
+ logFile = ""
+ }
+ }
+
+ if err := expandLocations(); err != nil {
+ l.Fatalln(err)
}
if showVersion {
@@ -272,13 +273,13 @@ func main() {
}
}
- cert, err := loadCert(dir, "")
+ certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
+ cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
} else {
- newCertificate(dir, "", tlsDefaultCommonName)
- cert, err = loadCert(dir, "")
+ cert, err = newCertificate(certFile, keyFile, tlsDefaultCommonName)
myID = protocol.NewDeviceID(cert.Certificate[0])
if err != nil {
l.Fatalln("load cert:", err)
@@ -304,17 +305,12 @@ func main() {
return
}
- confDir, err := osutil.ExpandTilde(confDir)
- if err != nil {
- l.Fatalln("home:", err)
- }
-
- if info, err := os.Stat(confDir); err == nil && !info.IsDir() {
- l.Fatalln("Config directory", confDir, "is not a directory")
+ if info, err := os.Stat(baseDirs["config"]); err == nil && !info.IsDir() {
+ l.Fatalln("Config directory", baseDirs["config"], "is not a directory")
}
// Ensure that our home directory exists.
- ensureDir(confDir, 0700)
+ ensureDir(baseDirs["config"], 0700)
if upgradeTo != "" {
err := upgrade.ToURL(upgradeTo)
@@ -340,7 +336,7 @@ func main() {
if doUpgrade {
// Use leveldb database locks to protect against concurrent upgrades
- _, err = leveldb.OpenFile(filepath.Join(confDir, "index"), &opt.Options{OpenFilesCacheCapacity: 100})
+ _, err = leveldb.OpenFile(locations[locDatabase], &opt.Options{OpenFilesCacheCapacity: 100})
if err != nil {
l.Fatalln("Cannot upgrade, database seems to be locked. Is another copy of Syncthing already running?")
}
@@ -374,13 +370,12 @@ func syncthingMain() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
- events.Default.Log(events.Starting, map[string]string{"home": confDir})
+ events.Default.Log(events.Starting, map[string]string{"home": baseDirs["config"]})
// Ensure that that we have a certificate and key.
- cert, err = loadCert(confDir, "")
+ cert, err = tls.LoadX509KeyPair(locations[locCertFile], locations[locKeyFile])
if err != nil {
- newCertificate(confDir, "", tlsDefaultCommonName)
- cert, err = loadCert(confDir, "")
+ cert, err = newCertificate(locations[locCertFile], locations[locKeyFile], tlsDefaultCommonName)
if err != nil {
l.Fatalln("load cert:", err)
}
@@ -398,7 +393,7 @@ func syncthingMain() {
// Prepare to be able to save configuration
- cfgFile := filepath.Join(confDir, "config.xml")
+ cfgFile := locations[locConfigFile]
var myName string
@@ -493,7 +488,7 @@ func syncthingMain() {
l.Infoln("Local networks:", strings.Join(networks, ", "))
}
- dbFile := filepath.Join(confDir, "index")
+ dbFile := locations[locDatabase]
dbOpts := &opt.Options{OpenFilesCacheCapacity: 100}
ldb, err := leveldb.OpenFile(dbFile, dbOpts)
if err != nil && errors.IsCorrupted(err) {
@@ -668,16 +663,11 @@ func setupGUI(cfg *config.Wrapper, m *model.Model) {
}
func defaultConfig(myName string) config.Configuration {
- defaultFolder, err := osutil.ExpandTilde("~/Sync")
- if err != nil {
- l.Fatalln("home:", err)
- }
-
newCfg := config.New(myID)
newCfg.Folders = []config.FolderConfiguration{
{
ID: "default",
- Path: defaultFolder,
+ Path: locations[locDefFolder],
RescanIntervalS: 60,
Devices: []config.FolderDeviceConfiguration{{DeviceID: myID}},
},
@@ -814,12 +804,7 @@ func renewUPnP(port int) {
}
func resetFolders() {
- confDir, err := osutil.ExpandTilde(confDir)
- if err != nil {
- log.Fatal(err)
- }
-
- cfgFile := filepath.Join(confDir, "config.xml")
+ cfgFile := locations[locConfigFile]
cfg, err := config.Load(cfgFile, myID)
if err != nil {
log.Fatal(err)
@@ -835,8 +820,7 @@ func resetFolders() {
}
}
- idx := filepath.Join(confDir, "index")
- os.RemoveAll(idx)
+ os.RemoveAll(locations[locDatabase])
}
func restart() {
@@ -882,25 +866,6 @@ func ensureDir(dir string, mode int) {
}
}
-func getDefaultConfDir() (string, error) {
- switch runtime.GOOS {
- case "windows":
- if p := os.Getenv("LocalAppData"); p != "" {
- return filepath.Join(p, "Syncthing"), nil
- }
- return filepath.Join(os.Getenv("AppData"), "Syncthing"), nil
-
- case "darwin":
- return osutil.ExpandTilde("~/Library/Application Support/Syncthing")
-
- default:
- if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
- return filepath.Join(xdgCfg, "syncthing"), nil
- }
- return osutil.ExpandTilde("~/.config/syncthing")
- }
-}
-
// getFreePort returns a free TCP port fort listening on. The ports given are
// tried in succession and the first to succeed is returned. If none succeed,
// a random high port is returned.
diff --git a/cmd/syncthing/monitor.go b/cmd/syncthing/monitor.go
index 2826d738..ced8b0ad 100644
--- a/cmd/syncthing/monitor.go
+++ b/cmd/syncthing/monitor.go
@@ -12,7 +12,6 @@ import (
"os"
"os/exec"
"os/signal"
- "path/filepath"
"runtime"
"strings"
"sync"
@@ -164,7 +163,7 @@ func copyStderr(stderr io.ReadCloser, dst io.Writer) {
dst.Write([]byte(line))
if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
- panicFd, err = os.Create(filepath.Join(confDir, time.Now().Format("panic-20060102-150405.log")))
+ panicFd, err = os.Create(time.Now().Format(locations[locPanicLog]))
if err != nil {
l.Warnln("Create panic log:", err)
continue
diff --git a/cmd/syncthing/tls.go b/cmd/syncthing/tls.go
index fcae10f2..6faafbe5 100644
--- a/cmd/syncthing/tls.go
+++ b/cmd/syncthing/tls.go
@@ -19,7 +19,6 @@ import (
mr "math/rand"
"net"
"os"
- "path/filepath"
"time"
)
@@ -28,13 +27,7 @@ const (
tlsDefaultCommonName = "syncthing"
)
-func loadCert(dir string, prefix string) (tls.Certificate, error) {
- cf := filepath.Join(dir, prefix+"cert.pem")
- kf := filepath.Join(dir, prefix+"key.pem")
- return tls.LoadX509KeyPair(cf, kf)
-}
-
-func newCertificate(dir, prefix, name string) {
+func newCertificate(certFile, keyFile, name string) (tls.Certificate, error) {
l.Infof("Generating RSA key and certificate for %s...", name)
priv, err := rsa.GenerateKey(rand.Reader, tlsRSABits)
@@ -63,7 +56,7 @@ func newCertificate(dir, prefix, name string) {
l.Fatalln("create cert:", err)
}
- certOut, err := os.Create(filepath.Join(dir, prefix+"cert.pem"))
+ certOut, err := os.Create(certFile)
if err != nil {
l.Fatalln("save cert:", err)
}
@@ -76,7 +69,7 @@ func newCertificate(dir, prefix, name string) {
l.Fatalln("save cert:", err)
}
- keyOut, err := os.OpenFile(filepath.Join(dir, prefix+"key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
l.Fatalln("save key:", err)
}
@@ -88,6 +81,8 @@ func newCertificate(dir, prefix, name string) {
if err != nil {
l.Fatalln("save key:", err)
}
+
+ return tls.LoadX509KeyPair(certFile, keyFile)
}
type DowngradingListener struct {
diff --git a/test/.gitignore b/test/.gitignore
index 51d37e13..9dc35dcb 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -15,5 +15,5 @@ dirs-*
csrftokens.txt
s4d
http
-index
+h*/index*
*.syncthing-reset*
diff --git a/test/cli_test.go b/test/cli_test.go
index b377a690..c7e5004c 100644
--- a/test/cli_test.go
+++ b/test/cli_test.go
@@ -17,7 +17,7 @@ import (
)
func TestCLIReset(t *testing.T) {
- dirs := []string{"s1", "s12-1", "h1/index"}
+ dirs := []string{"s1", "s12-1", "h1/index-v0.11.0.db"}
// Create directories that reset will remove
diff --git a/test/conflict_test.go b/test/conflict_test.go
index 2f9c6ed2..608e7975 100644
--- a/test/conflict_test.go
+++ b/test/conflict_test.go
@@ -18,7 +18,7 @@ import (
func TestConflict(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
@@ -64,16 +64,11 @@ func TestConflict(t *testing.T) {
// startup, UPnP etc complete and make sure the sender has the full index
// before they connect.
for i := 0; i < 20; i++ {
- resp, err := sender.post("/rest/scan?folder=default", nil)
+ err := sender.rescan("default")
if err != nil {
time.Sleep(time.Second)
continue
}
- if resp.StatusCode != 200 {
- resp.Body.Close()
- time.Sleep(time.Second)
- continue
- }
break
}
diff --git a/test/filetype_test.go b/test/filetype_test.go
index 4d68f1f8..98ef8ac1 100644
--- a/test/filetype_test.go
+++ b/test/filetype_test.go
@@ -61,7 +61,7 @@ func TestFileTypeChangeStaggeredVersioning(t *testing.T) {
func testFileTypeChange(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/h2/config.xml b/test/h2/config.xml
index 3563865b..d7740200 100644
--- a/test/h2/config.xml
+++ b/test/h2/config.xml
@@ -3,7 +3,9 @@
-
+
+
+
false
1
16
diff --git a/test/httpstress_test.go b/test/httpstress_test.go
index 257624bb..a6e77ed3 100644
--- a/test/httpstress_test.go
+++ b/test/httpstress_test.go
@@ -23,7 +23,7 @@ import (
func TestStressHTTP(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s2", "h2/index")
+ err := removeAll("s2", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/ignore_test.go b/test/ignore_test.go
index 37c96a3f..a62c091a 100644
--- a/test/ignore_test.go
+++ b/test/ignore_test.go
@@ -22,7 +22,7 @@ func TestIgnores(t *testing.T) {
// Clean and start a syncthing instance
log.Println("Cleaning...")
- err := removeAll("s1", "h1/index")
+ err := removeAll("s1", "h1/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/manypeers_test.go b/test/manypeers_test.go
index a794b9f0..690a2d66 100644
--- a/test/manypeers_test.go
+++ b/test/manypeers_test.go
@@ -22,7 +22,7 @@ import (
func TestManyPeers(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/parallell_scan_test.go b/test/parallell_scan_test.go
index 5c4d1fae..4d0c1ed9 100644
--- a/test/parallell_scan_test.go
+++ b/test/parallell_scan_test.go
@@ -18,7 +18,7 @@ import (
func TestParallellScan(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "h1/index")
+ err := removeAll("s1", "h1/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/reconnect_test.go b/test/reconnect_test.go
index f4c834c5..3447fc90 100644
--- a/test/reconnect_test.go
+++ b/test/reconnect_test.go
@@ -32,7 +32,7 @@ func TestRestartSenderAndReceiverDuringTransfer(t *testing.T) {
func testRestartDuringTransfer(t *testing.T, restartSender, restartReceiver bool, senderDelay, receiverDelay time.Duration) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/symlink_test.go b/test/symlink_test.go
index 2b180eb4..e5d85c66 100644
--- a/test/symlink_test.go
+++ b/test/symlink_test.go
@@ -86,7 +86,7 @@ func TestSymlinksStaggeredVersioning(t *testing.T) {
func testSymlinks(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/sync_test.go b/test/sync_test.go
index a37ee856..e8b824bc 100644
--- a/test/sync_test.go
+++ b/test/sync_test.go
@@ -79,7 +79,7 @@ func testSyncCluster(t *testing.T) {
err := removeAll("s1", "s12-1",
"s2", "s12-2", "s23-2",
"s3", "s23-3",
- "h1/index", "h2/index", "h3/index")
+ "h1/index*", "h2/index*", "h3/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/transfer-bench_test.go b/test/transfer-bench_test.go
index 5170457a..de850266 100644
--- a/test/transfer-bench_test.go
+++ b/test/transfer-bench_test.go
@@ -16,7 +16,7 @@ import (
func TestBenchmarkTransfer(t *testing.T) {
log.Println("Cleaning...")
- err := removeAll("s1", "s2", "h1/index", "h2/index")
+ err := removeAll("s1", "s2", "h1/index*", "h2/index*")
if err != nil {
t.Fatal(err)
}
diff --git a/test/util.go b/test/util.go
index 7bdd9e2f..47194456 100644
--- a/test/util.go
+++ b/test/util.go
@@ -241,17 +241,23 @@ func (i *inifiteReader) Read(bs []byte) (int, error) {
// rm -rf
func removeAll(dirs ...string) error {
for _, dir := range dirs {
- // Set any non-writeable files and dirs to writeable. This is necessary for os.RemoveAll to work on Windows.
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.Mode()&0700 != 0700 {
- os.Chmod(path, 0777)
- }
- return nil
- })
- os.RemoveAll(dir)
+ files, err := filepath.Glob(dir)
+ if err != nil {
+ return err
+ }
+ for _, file := range files {
+ // Set any non-writeable files and dirs to writeable. This is necessary for os.RemoveAll to work on Windows.
+ filepath.Walk(file, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.Mode()&0700 != 0700 {
+ os.Chmod(path, 0777)
+ }
+ return nil
+ })
+ os.RemoveAll(file)
+ }
}
return nil
}