Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c00c6b3957 | ||
|
|
cc39341eb9 | ||
|
|
bf7f82f7b2 | ||
|
|
eb857dbc45 | ||
|
|
e7620e951d | ||
|
|
286a25ae49 | ||
|
|
ae70046b49 | ||
|
|
c366933416 | ||
|
|
6a9716e8a1 | ||
|
|
b84ee4d240 | ||
|
|
8a1e54d58a | ||
|
|
3e032c4da6 | ||
|
|
7c3b267645 | ||
|
|
7161a99b04 | ||
|
|
1754c93370 | ||
|
|
4b750b6dc3 | ||
|
|
bf89bffb0b | ||
|
|
e2288fe441 | ||
|
|
8265dac127 | ||
|
|
100870e142 | ||
|
|
12fb7f2a0a | ||
|
|
f1bf4d899a |
@@ -20,7 +20,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -723,7 +722,7 @@ func shouldBuildSyso(dir string) (string, error) {
|
||||
}
|
||||
|
||||
jsonPath := filepath.Join(dir, "versioninfo.json")
|
||||
err = ioutil.WriteFile(jsonPath, bs, 0644)
|
||||
err = os.WriteFile(jsonPath, bs, 0644)
|
||||
if err != nil {
|
||||
return "", errors.New("failed to create " + jsonPath + ": " + err.Error())
|
||||
}
|
||||
@@ -762,12 +761,12 @@ func shouldCleanupSyso(sysoFilePath string) {
|
||||
// exists. The permission bits are copied as well. If dst already exists and
|
||||
// the contents are identical to src the modification time is not updated.
|
||||
func copyFile(src, dst string, perm os.FileMode) error {
|
||||
in, err := ioutil.ReadFile(src)
|
||||
in, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := ioutil.ReadFile(dst)
|
||||
out, err := os.ReadFile(dst)
|
||||
if err != nil {
|
||||
// The destination probably doesn't exist, we should create
|
||||
// it.
|
||||
@@ -783,7 +782,7 @@ func copyFile(src, dst string, perm os.FileMode) error {
|
||||
|
||||
copy:
|
||||
os.MkdirAll(filepath.Dir(dst), 0777)
|
||||
if err := ioutil.WriteFile(dst, in, perm); err != nil {
|
||||
if err := os.WriteFile(dst, in, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -958,7 +957,7 @@ func rmr(paths ...string) {
|
||||
}
|
||||
|
||||
func getReleaseVersion() (string, error) {
|
||||
bs, err := ioutil.ReadFile("RELEASE")
|
||||
bs, err := os.ReadFile("RELEASE")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1290,11 +1289,11 @@ func zipFile(out string, files []archiveFile) {
|
||||
|
||||
if strings.HasSuffix(f.dst, ".txt") {
|
||||
// Text file. Read it and convert line endings.
|
||||
bs, err := ioutil.ReadAll(sf)
|
||||
bs, err := io.ReadAll(sf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\n', '\r'}, -1)
|
||||
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\r', '\n'}, -1)
|
||||
fh.UncompressedSize = uint32(len(bs))
|
||||
fh.UncompressedSize64 = uint64(len(bs))
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -58,7 +57,7 @@ func main() {
|
||||
func handleFailureFn(dsn, failureDir string) func(w http.ResponseWriter, req *http.Request) {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
lr := io.LimitReader(req.Body, maxRequestSize)
|
||||
bs, err := ioutil.ReadAll(lr)
|
||||
bs, err := io.ReadAll(lr)
|
||||
req.Body.Close()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
||||
@@ -9,7 +9,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -93,7 +93,7 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
|
||||
}
|
||||
|
||||
r := bytes.NewReader(report)
|
||||
ctx, err := stack.ParseDump(r, ioutil.Discard, false)
|
||||
ctx, err := stack.ParseDump(r, io.Discard, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -59,7 +59,7 @@ func TestParseVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseReport(t *testing.T) {
|
||||
bs, err := ioutil.ReadFile("_testdata/panic.log")
|
||||
bs, err := os.ReadFile("_testdata/panic.log")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -80,7 +80,7 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
|
||||
fmt.Println("Loading source:", resp.Status)
|
||||
return nil, 0
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
_ = resp.Body.Close()
|
||||
if err != nil {
|
||||
fmt.Println("Loading source:", err.Error())
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -96,7 +95,7 @@ func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWrite
|
||||
// Read at most maxRequestSize of report data.
|
||||
log.Println("Receiving report", reportID)
|
||||
lr := io.LimitReader(req.Body, maxRequestSize)
|
||||
bs, err := ioutil.ReadAll(lr)
|
||||
bs, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
log.Println("Reading report:", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
@@ -110,7 +109,7 @@ func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWrite
|
||||
gw.Close()
|
||||
|
||||
// Create an output file with the compressed report
|
||||
err = ioutil.WriteFile(fullPath, buf.Bytes(), 0644)
|
||||
err = os.WriteFile(fullPath, buf.Bytes(), 0644)
|
||||
if err != nil {
|
||||
log.Println("Saving report:", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
@@ -53,5 +53,5 @@ func compressAndWrite(bs []byte, fullPath string) error {
|
||||
gw.Close()
|
||||
|
||||
// Create an output file with the compressed report
|
||||
return ioutil.WriteFile(fullPath, buf.Bytes(), 0644)
|
||||
return os.WriteFile(fullPath, buf.Bytes(), 0644)
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
|
||||
|
||||
// If zero port was specified, use remote port.
|
||||
if port == "0" && remote.Port > 0 {
|
||||
port = fmt.Sprintf("%d", remote.Port)
|
||||
port = strconv.Itoa(remote.Port)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -560,7 +559,7 @@ func limit(addr string, cache *lru.Cache, lock sync.Mutex, intv time.Duration, b
|
||||
}
|
||||
|
||||
func loadRelays(file string) []*relay {
|
||||
content, err := ioutil.ReadFile(file)
|
||||
content, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Println("Failed to load relays: " + err.Error())
|
||||
return nil
|
||||
@@ -598,11 +597,11 @@ func saveRelays(file string, relays []*relay) error {
|
||||
for _, relay := range relays {
|
||||
content += relay.uri.String() + "\n"
|
||||
}
|
||||
return ioutil.WriteFile(file, []byte(content), 0777)
|
||||
return os.WriteFile(file, []byte(content), 0777)
|
||||
}
|
||||
|
||||
func createTestCertificate() tls.Certificate {
|
||||
tmpDir, err := ioutil.TempDir("", "relaypoolsrv")
|
||||
tmpDir, err := os.MkdirTemp("", "relaypoolsrv")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ func main() {
|
||||
go natSvc.Serve(ctx)
|
||||
defer cancel()
|
||||
found := make(chan struct{})
|
||||
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
|
||||
mapping.OnChanged(func() {
|
||||
select {
|
||||
case found <- struct{}{}:
|
||||
default:
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -56,7 +56,7 @@ func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certifi
|
||||
continue
|
||||
}
|
||||
|
||||
bs, err := ioutil.ReadAll(resp.Body)
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
log.Printf("Error joining pool %v: reading response: %v", pool, err)
|
||||
|
||||
@@ -9,7 +9,6 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
@@ -69,7 +68,7 @@ func gen() {
|
||||
}
|
||||
|
||||
func sign(keyname, dataname string) {
|
||||
privkey, err := ioutil.ReadFile(keyname)
|
||||
privkey, err := os.ReadFile(keyname)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -95,7 +94,7 @@ func sign(keyname, dataname string) {
|
||||
}
|
||||
|
||||
func verifyWithFile(signame, dataname, keyname string) {
|
||||
pubkey, err := ioutil.ReadFile(keyname)
|
||||
pubkey, err := os.ReadFile(keyname)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -103,7 +102,7 @@ func verifyWithFile(signame, dataname, keyname string) {
|
||||
}
|
||||
|
||||
func verifyWithKey(signame, dataname string, pubkey []byte) {
|
||||
sig, err := ioutil.ReadFile(signame)
|
||||
sig, err := os.ReadFile(signame)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package cli
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -151,7 +151,7 @@ func parseFlags(c *preCli) error {
|
||||
}
|
||||
}
|
||||
// We don't want kong to print anything nor os.Exit (e.g. on -h)
|
||||
parser, err := kong.New(c, kong.Writers(ioutil.Discard, ioutil.Discard), kong.Exit(func(int) {}))
|
||||
parser, err := kong.New(c, kong.Writers(io.Discard, io.Discard), kong.Exit(func(int) {}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2021 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var pendingCommand = cli.Command{
|
||||
Name: "pending",
|
||||
HideHelp: true,
|
||||
Usage: "Pending subcommand group",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "devices",
|
||||
Usage: "Show pending devices",
|
||||
Action: expects(0, indexDumpOutput("cluster/pending/devices")),
|
||||
},
|
||||
{
|
||||
Name: "folders",
|
||||
Usage: "Show pending folders",
|
||||
Action: expects(0, indexDumpOutput("cluster/pending/folders")),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -35,6 +35,7 @@ var showCommand = cli.Command{
|
||||
Usage: "Report about connections to other devices",
|
||||
Action: expects(0, indexDumpOutput("system/connections")),
|
||||
},
|
||||
pendingCommand,
|
||||
{
|
||||
Name: "usage",
|
||||
Usage: "Show usage report",
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func responseToBArray(response *http.Response) ([]byte, error) {
|
||||
bytes, err := ioutil.ReadAll(response.Body)
|
||||
bytes, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2021 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package cmdutil
|
||||
|
||||
// CommonOptions are reused among several subcommands
|
||||
type CommonOptions struct {
|
||||
buildCommonOptions
|
||||
ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"`
|
||||
HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"`
|
||||
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
package cmdutil
|
||||
|
||||
type buildServeOptions struct {
|
||||
type buildCommonOptions struct {
|
||||
HideConsole bool `hidden:""`
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package main
|
||||
package cmdutil
|
||||
|
||||
type buildServeOptions struct {
|
||||
type buildCommonOptions struct {
|
||||
HideConsole bool `name:"no-console" help:"Hide console window"`
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -62,7 +61,7 @@ func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
|
||||
// the log contents. A HEAD request is made to see if the log has already
|
||||
// been reported. If not, a PUT is made with the log contents.
|
||||
func uploadPanicLog(ctx context.Context, urlBase, file string) error {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
@@ -112,7 +112,7 @@ func (c *CLI) withContinue(err error) error {
|
||||
// error.
|
||||
func (c *CLI) getFolderID() (string, error) {
|
||||
tokenPath := filepath.Join(c.Path, c.TokenPath)
|
||||
bs, err := ioutil.ReadFile(tokenPath)
|
||||
bs, err := os.ReadFile(tokenPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading folder token: %w", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (C) 2021 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Package generate implements the `syncthing generate` subcommand.
|
||||
package generate
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/syncthing"
|
||||
)
|
||||
|
||||
type CLI struct {
|
||||
cmdutil.CommonOptions
|
||||
GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
|
||||
GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
|
||||
}
|
||||
|
||||
func (c *CLI) Run() error {
|
||||
log.SetFlags(0)
|
||||
|
||||
if c.HideConsole {
|
||||
osutil.HideConsole()
|
||||
}
|
||||
|
||||
if c.HomeDir != "" {
|
||||
if c.ConfDir != "" {
|
||||
return fmt.Errorf("--home must not be used together with --config")
|
||||
}
|
||||
c.ConfDir = c.HomeDir
|
||||
}
|
||||
if c.ConfDir == "" {
|
||||
c.ConfDir = locations.GetBaseDir(locations.ConfigBaseDir)
|
||||
}
|
||||
|
||||
// Support reading the password from a pipe or similar
|
||||
if c.GUIPassword == "-" {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
password, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed reading GUI password: %w", err)
|
||||
}
|
||||
c.GUIPassword = string(password)
|
||||
}
|
||||
|
||||
if err := Generate(c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder); err != nil {
|
||||
return fmt.Errorf("Failed to generate config and keys: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Generate(confDir, guiUser, guiPassword string, noDefaultFolder bool) error {
|
||||
dir, err := fs.ExpandTilde(confDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := syncthing.EnsureDir(dir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
locations.SetBaseDir(locations.ConfigBaseDir, dir)
|
||||
|
||||
var myID protocol.DeviceID
|
||||
certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err == nil {
|
||||
log.Println("WARNING: Key exists; will not overwrite.")
|
||||
} else {
|
||||
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create certificate: %w", err)
|
||||
}
|
||||
}
|
||||
myID = protocol.NewDeviceID(cert.Certificate[0])
|
||||
log.Println("Device ID:", myID)
|
||||
|
||||
cfgFile := locations.Get(locations.ConfigFile)
|
||||
var cfg config.Wrapper
|
||||
if _, err := os.Stat(cfgFile); err == nil {
|
||||
if guiUser == "" && guiPassword == "" {
|
||||
log.Println("WARNING: Config exists; will not overwrite.")
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg, _, err = config.Load(cfgFile, myID, events.NoopLogger); err != nil {
|
||||
return fmt.Errorf("load config: %w", err)
|
||||
}
|
||||
} else {
|
||||
if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder); err != nil {
|
||||
return fmt.Errorf("create config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go cfg.Serve(ctx)
|
||||
defer cancel()
|
||||
|
||||
var updateErr error
|
||||
waiter, err := cfg.Modify(func(cfg *config.Configuration) {
|
||||
updateErr = updateGUIAuthentication(&cfg.GUI, guiUser, guiPassword)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("modify config: %w", err)
|
||||
}
|
||||
|
||||
waiter.Wait()
|
||||
if updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
if err := cfg.Save(); err != nil {
|
||||
return fmt.Errorf("save config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateGUIAuthentication(guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
|
||||
if guiUser != "" && guiCfg.User != guiUser {
|
||||
guiCfg.User = guiUser
|
||||
log.Println("Updated GUI authentication user name:", guiUser)
|
||||
}
|
||||
|
||||
if guiPassword != "" && guiCfg.Password != guiPassword {
|
||||
if err := guiCfg.HashAndSetPassword(guiPassword); err != nil {
|
||||
return fmt.Errorf("Failed to set GUI authentication password: %w", err)
|
||||
}
|
||||
log.Println("Updated GUI authentication password.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+12
-77
@@ -12,7 +12,6 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof" // Need to import this to support STPROFILER.
|
||||
@@ -36,6 +35,7 @@ import (
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/cli"
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/decrypt"
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/generate"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/db"
|
||||
@@ -132,32 +132,30 @@ var (
|
||||
// commands and options here are top level commands to syncthing.
|
||||
// Cli is just a placeholder for the help text (see main).
|
||||
var entrypoint struct {
|
||||
Serve serveOptions `cmd:"" help:"Run Syncthing"`
|
||||
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
|
||||
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
|
||||
Serve serveOptions `cmd:"" help:"Run Syncthing"`
|
||||
Generate generate.CLI `cmd:"" help:"Generate key and config, then exit"`
|
||||
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
|
||||
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
|
||||
}
|
||||
|
||||
// serveOptions are the options for the `syncthing serve` command.
|
||||
type serveOptions struct {
|
||||
buildServeOptions
|
||||
cmdutil.CommonOptions
|
||||
AllowNewerConfig bool `help:"Allow loading newer than current config version"`
|
||||
Audit bool `help:"Write events to audit file"`
|
||||
AuditFile string `name:"auditfile" placeholder:"PATH" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)"`
|
||||
BrowserOnly bool `help:"Open GUI in browser"`
|
||||
ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"`
|
||||
DataDir string `name:"data" placeholder:"PATH" help:"Set data directory (database and logs)"`
|
||||
DeviceID bool `help:"Show the device ID"`
|
||||
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"`
|
||||
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"` //DEPRECATED: replaced by subcommand!
|
||||
GUIAddress string `name:"gui-address" placeholder:"URL" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")"`
|
||||
GUIAPIKey string `name:"gui-apikey" placeholder:"API-KEY" help:"Override GUI API key"`
|
||||
HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"`
|
||||
LogFile string `name:"logfile" default:"${logFile}" placeholder:"PATH" help:"Log file name (see below)"`
|
||||
LogFlags int `name:"logflags" default:"${logFlags}" placeholder:"BITS" help:"Select information in log line prefix (see below)"`
|
||||
LogMaxFiles int `placeholder:"N" default:"${logMaxFiles}" name:"log-max-old-files" help:"Number of old files to keep (zero to keep only current)"`
|
||||
LogMaxSize int `placeholder:"BYTES" default:"${logMaxSize}" help:"Maximum size of any file (zero to disable log rotation)"`
|
||||
NoBrowser bool `help:"Do not start browser"`
|
||||
NoRestart bool `env:"STNORESTART" help:"Do not restart Syncthing when exiting due to API/GUI command, upgrade, or crash"`
|
||||
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
|
||||
NoUpgrade bool `env:"STNOUPGRADE" help:"Disable automatic upgrades"`
|
||||
Paths bool `help:"Show configuration paths"`
|
||||
Paused bool `help:"Start with all devices and folders paused"`
|
||||
@@ -339,7 +337,7 @@ func (options serveOptions) Run() error {
|
||||
}
|
||||
|
||||
if options.GenerateDir != "" {
|
||||
if err := generate(options.GenerateDir, options.NoDefaultFolder); err != nil {
|
||||
if err := generate.Generate(options.GenerateDir, "", "", options.NoDefaultFolder); err != nil {
|
||||
l.Warnln("Failed to generate config and keys:", err)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
@@ -347,7 +345,7 @@ func (options serveOptions) Run() error {
|
||||
}
|
||||
|
||||
// Ensure that our home directory exists.
|
||||
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
|
||||
if err := syncthing.EnsureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
|
||||
l.Warnln("Failure on home directory:", err)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
@@ -413,8 +411,8 @@ func openGUI(myID protocol.DeviceID) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cfg.GUI().Enabled {
|
||||
if err := openURL(cfg.GUI().URL()); err != nil {
|
||||
if guiCfg := cfg.GUI(); guiCfg.Enabled {
|
||||
if err := openURL(guiCfg.URL()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@@ -423,46 +421,6 @@ func openGUI(myID protocol.DeviceID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func generate(generateDir string, noDefaultFolder bool) error {
|
||||
dir, err := fs.ExpandTilde(generateDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ensureDir(dir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var myID protocol.DeviceID
|
||||
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.")
|
||||
} else {
|
||||
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create certificate")
|
||||
}
|
||||
}
|
||||
myID = protocol.NewDeviceID(cert.Certificate[0])
|
||||
l.Infoln("Device ID:", myID)
|
||||
|
||||
cfgFile := filepath.Join(dir, "config.xml")
|
||||
if _, err := os.Stat(cfgFile); err == nil {
|
||||
l.Warnln("Config exists; will not overwrite.")
|
||||
return nil
|
||||
}
|
||||
cfg, err := syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cfg.Save()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "save config")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func debugFacilities() string {
|
||||
facilities := l.Facilities()
|
||||
|
||||
@@ -541,7 +499,7 @@ func upgradeViaRest() error {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
bs, err := ioutil.ReadAll(resp.Body)
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -800,29 +758,6 @@ func resetDB() error {
|
||||
return os.RemoveAll(locations.Get(locations.Database))
|
||||
}
|
||||
|
||||
func ensureDir(dir string, mode fs.FileMode) error {
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
err := fs.MkdirAll(".", mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fi, err := fs.Stat("."); err == nil {
|
||||
// Apprently the stat may fail even though the mkdirall passed. If it
|
||||
// does, we'll just assume things are in order and let other things
|
||||
// fail (like loading or creating the config...).
|
||||
currentMode := fi.Mode() & 0777
|
||||
if currentMode != mode {
|
||||
err := fs.Chmod(".", mode)
|
||||
// This can fail on crappy filesystems, nothing we can do about it.
|
||||
if err != nil {
|
||||
l.Warnln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func standbyMonitor(app *syncthing.App, cfg config.Wrapper) {
|
||||
restartDelay := 60 * time.Second
|
||||
now := time.Now()
|
||||
|
||||
@@ -8,7 +8,6 @@ package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
func TestRotatedFile(t *testing.T) {
|
||||
// Verify that log rotation happens.
|
||||
|
||||
dir, err := ioutil.TempDir("", "syncthing")
|
||||
dir, err := os.MkdirTemp("", "syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -179,7 +178,7 @@ func TestAutoClosedFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// The file should have both writes in it.
|
||||
bs, err := ioutil.ReadFile(file)
|
||||
bs, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -199,7 +198,7 @@ func TestAutoClosedFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// It should now contain three writes, as the file is always opened for appending
|
||||
bs, err = ioutil.ReadFile(file)
|
||||
bs, err = os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+2
-3
@@ -13,7 +13,6 @@ import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -162,7 +161,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalln("template:", err)
|
||||
}
|
||||
bs, err := ioutil.ReadAll(fd)
|
||||
bs, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
log.Fatalln("template:", err)
|
||||
}
|
||||
@@ -324,7 +323,7 @@ func newDataHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
|
||||
rep.Address = addr
|
||||
|
||||
lr := &io.LimitedReader{R: r.Body, N: 40 * 1024}
|
||||
bs, _ := ioutil.ReadAll(lr)
|
||||
bs, _ := io.ReadAll(lr)
|
||||
if err := json.Unmarshal(bs, &rep); err != nil {
|
||||
log.Println("decode:", err)
|
||||
if debug {
|
||||
|
||||
@@ -30,7 +30,7 @@ require (
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/lib/pq v1.10.3
|
||||
github.com/lucas-clemente/quic-go v0.23.0
|
||||
github.com/lucas-clemente/quic-go v0.24.0
|
||||
github.com/maruel/panicparse v1.6.1
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
|
||||
@@ -242,8 +242,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucas-clemente/quic-go v0.22.0/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q=
|
||||
github.com/lucas-clemente/quic-go v0.23.0 h1:5vFnKtZ6nHDFsc/F3uuiF4T3y/AXaQdxjUqiVw26GZE=
|
||||
github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g=
|
||||
github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
|
||||
@@ -428,6 +428,13 @@
|
||||
<div ng-if="model[folder.id].ignorePatterns">
|
||||
<a href="" ng-click="editFolderExisting(folder, '#folder-ignores')"><i class="small" translate>Reduced by ignore patterns</i></a>
|
||||
</div>
|
||||
<div ng-if="folder.ignoreDelete">
|
||||
<i class="small">
|
||||
<span translate style="white-space: normal;">Altered by ignoring deletes.</span>
|
||||
<br>
|
||||
<a href="https://docs.syncthing.net/advanced/folder-ignoredelete" target="_blank"><span class="fas fa-question-circle"></span> <span translate>Help</span></a>
|
||||
</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="model[folder.id].needTotalItems > 0">
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<modal id="remove-device-confirmation" status="warning" icon="fas fa-question-circle" heading="{{'Remove Device' | translate}}" large="no" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<p ng-model="currentDevice.name" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-name="{{currentDevice.name}}">Are you sure you want to remove device {%name%}?</span>
|
||||
<p ng-model="currentDevice.name" translate translate-value-name="{{currentDevice.name}}">
|
||||
Are you sure you want to remove device {%name%}?
|
||||
</p>
|
||||
<p ng-if="willBeReintroducedBy" translate translate-value-reintroducer="{{willBeReintroducedBy}}">
|
||||
{%reintroducer%} might reintroduce this device.
|
||||
</p>
|
||||
<p ng-if="willBeReintroducedBy" translate translate-value-reintroducer="{{willBeReintroducedBy}}">{%reintroducer%} might reintroduce this device.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="deleteDevice()">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<modal id="remove-folder-confirmation" status="warning" icon="fas fa-question-circle" heading="{{'Remove Folder' | translate}}" large="no" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<p style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-label="{{currentFolder.label}}">Are you sure you want to remove folder {%label%}?</span>
|
||||
<p translate translate-value-label="{{currentFolder.label}}">
|
||||
Are you sure you want to remove folder {%label%}?
|
||||
</p>
|
||||
<p translate>
|
||||
No files will be deleted as a result of this operation.
|
||||
|
||||
+9
-8
@@ -15,7 +15,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -94,6 +93,8 @@ type service struct {
|
||||
systemLog logger.Recorder
|
||||
}
|
||||
|
||||
var _ config.Verifier = &service{}
|
||||
|
||||
type Service interface {
|
||||
suture.Service
|
||||
config.Committer
|
||||
@@ -380,7 +381,7 @@ func (s *service) Serve(ctx context.Context) error {
|
||||
ReadTimeout: 15 * time.Second,
|
||||
// Prevent the HTTP server from logging stuff on its own. The things we
|
||||
// care about we log ourselves from the handlers.
|
||||
ErrorLog: log.New(ioutil.Discard, "", 0),
|
||||
ErrorLog: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
l.Infoln("GUI and API listening on", listener.Addr())
|
||||
@@ -1096,7 +1097,7 @@ func (s *service) getSystemError(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *service) postSystemError(w http.ResponseWriter, r *http.Request) {
|
||||
bs, _ := ioutil.ReadAll(r.Body)
|
||||
bs, _ := io.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
l.Warnln(string(bs))
|
||||
}
|
||||
@@ -1163,7 +1164,7 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
// Panic files
|
||||
if panicFiles, err := filepath.Glob(filepath.Join(locations.GetBaseDir(locations.ConfigBaseDir), "panic*")); err == nil {
|
||||
for _, f := range panicFiles {
|
||||
if panicFile, err := ioutil.ReadFile(f); err != nil {
|
||||
if panicFile, err := os.ReadFile(f); err != nil {
|
||||
l.Warnf("Support bundle: failed to load %s: %s", filepath.Base(f), err)
|
||||
} else {
|
||||
files = append(files, fileEntry{name: filepath.Base(f), data: panicFile})
|
||||
@@ -1172,7 +1173,7 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Archived log (default on Windows)
|
||||
if logFile, err := ioutil.ReadFile(locations.Get(locations.LogFile)); err == nil {
|
||||
if logFile, err := os.ReadFile(locations.Get(locations.LogFile)); err == nil {
|
||||
files = append(files, fileEntry{name: "log-ondisk.txt", data: logFile})
|
||||
}
|
||||
|
||||
@@ -1231,7 +1232,7 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
zipFilePath := filepath.Join(locations.GetBaseDir(locations.ConfigBaseDir), zipFileName)
|
||||
|
||||
// Write buffer zip to local zip file (back up)
|
||||
if err := ioutil.WriteFile(zipFilePath, zipFilesBuffer.Bytes(), 0600); err != nil {
|
||||
if err := os.WriteFile(zipFilePath, zipFilesBuffer.Bytes(), 0600); err != nil {
|
||||
l.Warnln("Support bundle: support bundle zip could not be created:", err)
|
||||
}
|
||||
|
||||
@@ -1321,7 +1322,7 @@ func (s *service) getDBIgnores(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *service) postDBIgnores(w http.ResponseWriter, r *http.Request) {
|
||||
qs := r.URL.Query()
|
||||
|
||||
bs, err := ioutil.ReadAll(r.Body)
|
||||
bs, err := io.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
@@ -1612,7 +1613,7 @@ func (s *service) getFolderVersions(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *service) postFolderVersionsRestore(w http.ResponseWriter, r *http.Request) {
|
||||
qs := r.URL.Query()
|
||||
|
||||
bs, err := ioutil.ReadAll(r.Body)
|
||||
bs, err := io.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
||||
+6
-7
@@ -13,7 +13,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -223,7 +222,7 @@ func expectURLToContain(t *testing.T, url, exp string) {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
data, err := io.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -508,7 +507,7 @@ func testHTTPRequest(t *testing.T, baseURL string, tc httpTestCase, apikey strin
|
||||
return
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error reading %s: %v", tc.URL, err)
|
||||
return
|
||||
@@ -1137,7 +1136,7 @@ func TestBrowse(t *testing.T) {
|
||||
|
||||
pathSep := string(os.PathSeparator)
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "syncthing")
|
||||
tmpDir, err := os.MkdirTemp("", "syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1146,7 +1145,7 @@ func TestBrowse(t *testing.T) {
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "dir"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(tmpDir, "file"), []byte("hello"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, "file"), []byte("hello"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(tmpDir, "MiXEDCase"), 0755); err != nil {
|
||||
@@ -1251,7 +1250,7 @@ func TestConfigChanges(t *testing.T) {
|
||||
APIKey: testAPIKey,
|
||||
},
|
||||
}
|
||||
tmpFile, err := ioutil.TempFile("", "syncthing-testConfig-")
|
||||
tmpFile, err := os.CreateTemp("", "syncthing-testConfig-")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -1393,7 +1392,7 @@ func runningInContainer() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
bs, err := ioutil.ReadFile("/proc/1/cgroup")
|
||||
bs, err := os.ReadFile("/proc/1/cgroup")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package auto_test
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestAssets(t *testing.T) {
|
||||
|
||||
var gr *gzip.Reader
|
||||
gr, _ = gzip.NewReader(strings.NewReader(idx.Content))
|
||||
html, _ := ioutil.ReadAll(gr)
|
||||
html, _ := io.ReadAll(gr)
|
||||
|
||||
if !bytes.Contains(html, []byte("<html")) {
|
||||
t.Fatal("No html in index.html")
|
||||
|
||||
@@ -9,7 +9,6 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
@@ -407,7 +406,7 @@ func (c *configMuxBuilder) adjustLDAP(w http.ResponseWriter, r *http.Request, ld
|
||||
|
||||
// Unmarshals the content of the given body and stores it in to (i.e. to must be a pointer).
|
||||
func unmarshalTo(body io.ReadCloser, to interface{}) error {
|
||||
bs, err := ioutil.ReadAll(body)
|
||||
bs, err := io.ReadAll(body)
|
||||
body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
@@ -31,7 +30,7 @@ func compress(s string) string {
|
||||
func decompress(p []byte) (out []byte) {
|
||||
r, err := gzip.NewReader(bytes.NewBuffer(p))
|
||||
if err == nil {
|
||||
out, err = ioutil.ReadAll(r)
|
||||
out, err = io.ReadAll(r)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -81,7 +80,7 @@ func testServe(t *testing.T, gzip bool) {
|
||||
t.Errorf("unexpected ETag %q", etag)
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
|
||||
// Content-Length is the number of bytes in the encoded (compressed) body
|
||||
// (https://stackoverflow.com/a/3819303).
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -163,7 +162,7 @@ func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, int, error) {
|
||||
}
|
||||
|
||||
func ReadJSON(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
|
||||
bs, err := ioutil.ReadAll(r)
|
||||
bs, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return Configuration{}, err
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@@ -502,7 +501,7 @@ func TestFolderPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFolderCheckPath(t *testing.T) {
|
||||
n, err := ioutil.TempDir("", "")
|
||||
n, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -595,6 +594,41 @@ func TestNewSaveLoad(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWindowsLineEndings(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("Windows specific")
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "syncthing-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
path := filepath.Join(dir, "config.xml")
|
||||
os.Remove(path)
|
||||
defer os.Remove(path)
|
||||
|
||||
intCfg := New(device1)
|
||||
cfg := wrap(path, intCfg, device1)
|
||||
defer cfg.stop()
|
||||
|
||||
if err := cfg.Save(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
bs, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
unixLineEndings := bytes.Count(bs, []byte("\n"))
|
||||
windowsLineEndings := bytes.Count(bs, []byte("\r\n"))
|
||||
if unixLineEndings == 0 || windowsLineEndings != unixLineEndings {
|
||||
t.Error("expected there to be a non-zero number of Windows line endings")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepare(t *testing.T) {
|
||||
var cfg Configuration
|
||||
|
||||
@@ -643,8 +677,8 @@ func TestCopy(t *testing.T) {
|
||||
t.Error("Config should have changed")
|
||||
}
|
||||
if !bytes.Equal(bsOrig, bsCopy) {
|
||||
// ioutil.WriteFile("a", bsOrig, 0644)
|
||||
// ioutil.WriteFile("b", bsCopy, 0644)
|
||||
// os.WriteFile("a", bsOrig, 0644)
|
||||
// os.WriteFile("b", bsCopy, 0644)
|
||||
t.Error("Copy should be unchanged")
|
||||
}
|
||||
}
|
||||
@@ -1266,7 +1300,7 @@ func copyToTmp(path string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
defer orig.Close()
|
||||
temp, err := ioutil.TempFile("", "syncthing-configTest-")
|
||||
temp, err := os.CreateTemp("", "syncthing-configTest-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+17
-8
@@ -31,14 +31,14 @@ const (
|
||||
|
||||
var errTooManyModifications = errors.New("too many concurrent config modifications")
|
||||
|
||||
// The Committer interface is implemented by objects that need to know about
|
||||
// or have a say in configuration changes.
|
||||
// The Committer and Verifier interfaces are implemented by objects
|
||||
// that need to know about or have a say in configuration changes.
|
||||
//
|
||||
// When the configuration is about to be changed, VerifyConfiguration() is
|
||||
// called for each subscribing object, with the old and new configuration. A
|
||||
// nil error is returned if the new configuration is acceptable (i.e. does not
|
||||
// contain any errors that would prevent it from being a valid config).
|
||||
// Otherwise an error describing the problem is returned.
|
||||
// called for each subscribing object that implements it, with copies of the
|
||||
// old and new configuration. A nil error is returned if the new configuration
|
||||
// is acceptable (i.e., does not contain any errors that would prevent it from
|
||||
// being a valid config). Otherwise an error describing the problem is returned.
|
||||
//
|
||||
// If any subscriber returns an error from VerifyConfiguration(), the
|
||||
// configuration change is not committed and an error is returned to whoever
|
||||
@@ -55,11 +55,16 @@ var errTooManyModifications = errors.New("too many concurrent config modificatio
|
||||
// configuration (e.g. calling Wrapper.SetFolder), that are also acquired in any
|
||||
// methods of the Committer interface.
|
||||
type Committer interface {
|
||||
VerifyConfiguration(from, to Configuration) error
|
||||
CommitConfiguration(from, to Configuration) (handled bool)
|
||||
String() string
|
||||
}
|
||||
|
||||
// A Verifier can determine if a new configuration is acceptable.
|
||||
// See the description for Committer, above.
|
||||
type Verifier interface {
|
||||
VerifyConfiguration(from, to Configuration) error
|
||||
}
|
||||
|
||||
// Waiter allows to wait for the given config operation to complete.
|
||||
type Waiter interface {
|
||||
Wait()
|
||||
@@ -300,6 +305,10 @@ func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
|
||||
}
|
||||
|
||||
for _, sub := range w.subs {
|
||||
sub, ok := sub.(Verifier)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
l.Debugln(sub, "verifying configuration")
|
||||
if err := sub.VerifyConfiguration(from.Copy(), to.Copy()); err != nil {
|
||||
l.Debugln(sub, "rejected config:", err)
|
||||
@@ -493,7 +502,7 @@ func (w *wrapper) Save() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := w.cfg.WriteXML(fd); err != nil {
|
||||
if err := w.cfg.WriteXML(osutil.LineEndingsWriter(fd)); err != nil {
|
||||
l.Debugln("WriteXML:", err)
|
||||
fd.Close()
|
||||
return err
|
||||
|
||||
@@ -122,10 +122,6 @@ func (lim *limiter) processDevicesConfigurationLocked(from, to config.Configurat
|
||||
}
|
||||
}
|
||||
|
||||
func (lim *limiter) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lim *limiter) CommitConfiguration(from, to config.Configuration) bool {
|
||||
// to ensure atomic update of configuration
|
||||
lim.mu.Lock()
|
||||
|
||||
@@ -706,10 +706,6 @@ func (s *service) logListenAddressesChangedEvent(l ListenerAddresses) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *service) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) CommitConfiguration(from, to config.Configuration) bool {
|
||||
newDevices := make(map[protocol.DeviceID]bool, len(to.Devices))
|
||||
for _, dev := range to.Devices {
|
||||
|
||||
@@ -76,7 +76,7 @@ func (t *tcpListener) serve(ctx context.Context) error {
|
||||
defer l.Infof("TCP listener (%v) shutting down", tcaddr)
|
||||
|
||||
mapping := t.natService.NewMapping(nat.TCP, tcaddr.IP, tcaddr.Port)
|
||||
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
|
||||
mapping.OnChanged(func() {
|
||||
t.notifyAddressesChanged(t)
|
||||
})
|
||||
// Should be called after t.mapping is nil'ed out.
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -173,7 +172,7 @@ func (c *globalClient) Lookup(ctx context.Context, device protocol.DeviceID) (ad
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bs, err := ioutil.ReadAll(resp.Body)
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package discover
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -232,7 +232,7 @@ func (s *fakeDiscoveryServer) handler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if r.Method == "POST" {
|
||||
s.announce, _ = ioutil.ReadAll(r.Body)
|
||||
s.announce, _ = io.ReadAll(r.Body)
|
||||
w.WriteHeader(204)
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -227,10 +227,6 @@ func (m *manager) Cache() map[protocol.DeviceID]CacheEntry {
|
||||
return res
|
||||
}
|
||||
|
||||
func (m *manager) VerifyConfiguration(_, _ config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) CommitConfiguration(_, to config.Configuration) (handled bool) {
|
||||
m.mut.Lock()
|
||||
defer m.mut.Unlock()
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -21,7 +20,7 @@ import (
|
||||
|
||||
func setup(t *testing.T) (*BasicFilesystem, string) {
|
||||
t.Helper()
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -530,7 +529,7 @@ func renameTestFile(name string, old string, new string) {
|
||||
func modifyTestFile(name string, file string, content string) {
|
||||
joined := filepath.Join(testDirAbs, name, file)
|
||||
|
||||
err := ioutil.WriteFile(joined, []byte(content), 0755)
|
||||
err := os.WriteFile(joined, []byte(content), 0755)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to modify test file %s: %s", joined, err))
|
||||
}
|
||||
|
||||
+2
-5
@@ -12,7 +12,6 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -89,11 +88,9 @@ func newFakeFilesystem(rootURI string, _ ...Option) *fakeFS {
|
||||
fakeFSMut.Lock()
|
||||
defer fakeFSMut.Unlock()
|
||||
|
||||
root := rootURI
|
||||
var params url.Values
|
||||
uri, err := url.Parse(rootURI)
|
||||
if err == nil {
|
||||
root = uri.Path
|
||||
params = uri.Query()
|
||||
}
|
||||
|
||||
@@ -157,7 +154,7 @@ func newFakeFilesystem(rootURI string, _ ...Option) *fakeFS {
|
||||
// the filesystem initially.
|
||||
fs.latency, _ = time.ParseDuration(params.Get("latency"))
|
||||
|
||||
fakeFSCache[root] = fs
|
||||
fakeFSCache[rootURI] = fs
|
||||
return fs
|
||||
}
|
||||
|
||||
@@ -789,7 +786,7 @@ func (f *fakeFile) readShortAt(p []byte, offs int64) (int, error) {
|
||||
diff := offs - minOffs
|
||||
if diff > 0 {
|
||||
lr := io.LimitReader(f.rng, diff)
|
||||
io.Copy(ioutil.Discard, lr)
|
||||
io.Copy(io.Discard, lr)
|
||||
}
|
||||
|
||||
f.offset = offs
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -88,7 +87,7 @@ func TestFakeFS(t *testing.T) {
|
||||
}
|
||||
|
||||
// Read
|
||||
bs0, err := ioutil.ReadAll(fd)
|
||||
bs0, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -101,7 +100,7 @@ func TestFakeFS(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bs1, err := ioutil.ReadAll(fd)
|
||||
bs1, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -139,7 +138,7 @@ func testFakeFSRead(t *testing.T, fs Filesystem) {
|
||||
|
||||
// Read
|
||||
fd.Seek(0, io.SeekStart)
|
||||
bs0, err := ioutil.ReadAll(fd)
|
||||
bs0, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -154,7 +153,7 @@ func testFakeFSRead(t *testing.T, fs Filesystem) {
|
||||
if n != len(buf0) {
|
||||
t.Fatal("short read")
|
||||
}
|
||||
buf1, err := ioutil.ReadAll(fd)
|
||||
buf1, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -252,7 +251,7 @@ func TestFakeFSCaseInsensitive(t *testing.T) {
|
||||
func createTestDir(t *testing.T) (string, bool) {
|
||||
t.Helper()
|
||||
|
||||
testDir, err := ioutil.TempDir("", "")
|
||||
testDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create temporary dir for testing: %s", err)
|
||||
}
|
||||
@@ -328,7 +327,7 @@ func testFakeFSCaseInsensitive(t *testing.T, fs Filesystem) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bs2, err := ioutil.ReadAll(fd2)
|
||||
bs2, err := io.ReadAll(fd2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ func IsInternal(file string) bool {
|
||||
// - /foo/bar -> foo/bar
|
||||
// - / -> "."
|
||||
func Canonicalize(file string) (string, error) {
|
||||
pathSep := string(PathSeparator)
|
||||
const pathSep = string(PathSeparator)
|
||||
|
||||
if strings.HasPrefix(file, pathSep+pathSep) {
|
||||
// The relative path may pretend to be an absolute path within
|
||||
|
||||
@@ -9,7 +9,6 @@ package fs
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -257,7 +256,7 @@ func TestCopyRange(tttt *testing.T) {
|
||||
paths = []string{""}
|
||||
}
|
||||
for _, path := range paths {
|
||||
testPath, err := ioutil.TempDir(path, "")
|
||||
testPath, err := os.MkdirTemp(path, "")
|
||||
if err != nil {
|
||||
tttt.Fatal(err)
|
||||
}
|
||||
@@ -273,7 +272,7 @@ func TestCopyRange(tttt *testing.T) {
|
||||
tt.Run(testCase.name, func(t *testing.T) {
|
||||
srcBuf := make([]byte, testCase.srcSize)
|
||||
dstBuf := make([]byte, testCase.dstSize)
|
||||
td, err := ioutil.TempDir(testPath, "")
|
||||
td, err := os.MkdirTemp(testPath, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package fs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -20,9 +19,9 @@ func TestMtimeFS(t *testing.T) {
|
||||
os.RemoveAll("testdata")
|
||||
defer os.RemoveAll("testdata")
|
||||
os.Mkdir("testdata", 0755)
|
||||
ioutil.WriteFile("testdata/exists0", []byte("hello"), 0644)
|
||||
ioutil.WriteFile("testdata/exists1", []byte("hello"), 0644)
|
||||
ioutil.WriteFile("testdata/exists2", []byte("hello"), 0644)
|
||||
os.WriteFile("testdata/exists0", []byte("hello"), 0644)
|
||||
os.WriteFile("testdata/exists1", []byte("hello"), 0644)
|
||||
os.WriteFile("testdata/exists2", []byte("hello"), 0644)
|
||||
|
||||
// a random time with nanosecond precision
|
||||
testTime := time.Unix(1234567890, 123456789)
|
||||
@@ -83,7 +82,7 @@ func TestMtimeFS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMtimeFSWalk(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -93,7 +92,7 @@ func TestMtimeFSWalk(t *testing.T) {
|
||||
mtimefs := newMtimeFS(underlying, make(mapStore))
|
||||
mtimefs.chtimes = failChtimes
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -137,7 +136,7 @@ func TestMtimeFSWalk(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMtimeFSOpen(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -147,7 +146,7 @@ func TestMtimeFSOpen(t *testing.T) {
|
||||
mtimefs := newMtimeFS(underlying, make(mapStore))
|
||||
mtimefs.chtimes = failChtimes
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -200,7 +199,7 @@ func TestMtimeFSInsensitive(t *testing.T) {
|
||||
os.RemoveAll("testdata")
|
||||
defer os.RemoveAll("testdata")
|
||||
os.Mkdir("testdata", 0755)
|
||||
ioutil.WriteFile("testdata/FiLe", []byte("hello"), 0644)
|
||||
os.WriteFile("testdata/FiLe", []byte("hello"), 0644)
|
||||
|
||||
// a random time with nanosecond precision
|
||||
testTime := time.Unix(1234567890, 123456789)
|
||||
|
||||
+26
-26
@@ -47,25 +47,13 @@ func getHomeDir() (string, error) {
|
||||
return os.UserHomeDir()
|
||||
}
|
||||
|
||||
var (
|
||||
windowsDisallowedCharacters = string([]rune{
|
||||
'<', '>', ':', '"', '|', '?', '*',
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
31,
|
||||
})
|
||||
windowsDisallowedNames = []string{"CON", "PRN", "AUX", "NUL",
|
||||
"COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
}
|
||||
)
|
||||
const windowsDisallowedCharacters = (`<>:"|?*` +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f")
|
||||
|
||||
func WindowsInvalidFilename(name string) error {
|
||||
// None of the path components should end in space or period, or be a
|
||||
// reserved name. COM0 and LPT0 are missing from the Microsoft docs,
|
||||
// but Windows Explorer treats them as invalid too.
|
||||
// (https://docs.microsoft.com/windows/win32/fileio/naming-a-file)
|
||||
// reserved name.
|
||||
for _, part := range strings.Split(name, `\`) {
|
||||
if len(part) == 0 {
|
||||
continue
|
||||
@@ -110,7 +98,7 @@ func WindowsInvalidFilename(name string) error {
|
||||
func SanitizePath(path string) string {
|
||||
var b strings.Builder
|
||||
|
||||
disallowed := `<>:"'/\|?*[]{};:!@$%&^#` + windowsDisallowedCharacters
|
||||
const disallowed = `'/\[]{};:!@$%&^#` + windowsDisallowedCharacters
|
||||
prev := ' '
|
||||
for _, c := range path {
|
||||
if !unicode.IsPrint(c) || c == unicode.ReplacementChar ||
|
||||
@@ -132,15 +120,27 @@ func SanitizePath(path string) string {
|
||||
}
|
||||
|
||||
func windowsIsReserved(part string) bool {
|
||||
upperCased := strings.ToUpper(part)
|
||||
for _, disallowed := range windowsDisallowedNames {
|
||||
if upperCased == disallowed {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(upperCased, disallowed+".") {
|
||||
// nul.txt.jpg is also disallowed
|
||||
return true
|
||||
}
|
||||
// nul.txt.jpg is also disallowed.
|
||||
dot := strings.IndexByte(part, '.')
|
||||
if dot != -1 {
|
||||
part = part[:dot]
|
||||
}
|
||||
|
||||
// Check length to skip allocating ToUpper.
|
||||
if len(part) != 3 && len(part) != 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
// COM0 and LPT0 are missing from the Microsoft docs,
|
||||
// but Windows Explorer treats them as invalid too.
|
||||
// (https://docs.microsoft.com/windows/win32/fileio/naming-a-file)
|
||||
switch strings.ToUpper(part) {
|
||||
case "CON", "PRN", "AUX", "NUL",
|
||||
"COM0", "COM1", "COM2", "COM3", "COM4",
|
||||
"COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4",
|
||||
"LPT5", "LPT6", "LPT7", "LPT8", "LPT9":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -117,3 +117,15 @@ func TestSanitizePathFuzz(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkWindowsInvalidFilename(b *testing.B, name string) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
WindowsInvalidFilename(name)
|
||||
}
|
||||
}
|
||||
func BenchmarkWindowsInvalidFilenameValid(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "License.txt.gz")
|
||||
}
|
||||
func BenchmarkWindowsInvalidFilenameNUL(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "nul.txt.gz")
|
||||
}
|
||||
|
||||
@@ -595,8 +595,9 @@ func WriteIgnores(filesystem fs.Filesystem, path string, content []string) error
|
||||
return err
|
||||
}
|
||||
|
||||
wr := osutil.LineEndingsWriter(fd)
|
||||
for _, line := range content {
|
||||
fmt.Fprintln(fd, line)
|
||||
fmt.Fprintln(wr, line)
|
||||
}
|
||||
|
||||
if err := fd.Close(); err != nil {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -232,7 +231,7 @@ func TestCaseSensitivity(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -425,7 +424,7 @@ flamingo
|
||||
*.crow
|
||||
`
|
||||
// Caches per file, hence write the patterns to a file.
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -466,7 +465,7 @@ flamingo
|
||||
}
|
||||
|
||||
func TestCacheReload(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -989,7 +988,7 @@ func TestIssue4689(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue4901(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1001,7 +1000,7 @@ func TestIssue4901(t *testing.T) {
|
||||
puppy
|
||||
`
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, ".stignore"), []byte(stignore), 0777); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(dir, ".stignore"), []byte(stignore), 0777); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
@@ -1020,7 +1019,7 @@ func TestIssue4901(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, "unicorn-lazor-death"), []byte(" "), 0777); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(dir, "unicorn-lazor-death"), []byte(" "), 0777); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
@@ -1193,3 +1192,42 @@ func TestEmptyPatterns(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWindowsLineEndings(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("Windows specific")
|
||||
}
|
||||
|
||||
lines := "foo\nbar\nbaz\n"
|
||||
|
||||
dir, err := os.MkdirTemp("", "syncthing-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
ffs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
m := New(ffs)
|
||||
if err := m.Parse(strings.NewReader(lines), ".stignore"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WriteIgnores(ffs, ".stignore", m.Lines()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fd, err := ffs.Open(".stignore")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bs, err := io.ReadAll(fd)
|
||||
fd.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
unixLineEndings := bytes.Count(bs, []byte("\n"))
|
||||
windowsLineEndings := bytes.Count(bs, []byte("\r\n"))
|
||||
if unixLineEndings == 0 || windowsLineEndings != unixLineEndings {
|
||||
t.Error("expected there to be a non-zero number of Windows line endings")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ package logger
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -75,7 +74,7 @@ func New() Logger {
|
||||
if os.Getenv("LOGGER_DISCARD") != "" {
|
||||
// Hack to completely disable logging, for example when running
|
||||
// benchmarks.
|
||||
return newLogger(ioutil.Discard)
|
||||
return newLogger(io.Discard)
|
||||
}
|
||||
return newLogger(controlStripper{os.Stdout})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package logger
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -186,12 +186,12 @@ func TestControlStripper(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkLog(b *testing.B) {
|
||||
l := newLogger(controlStripper{ioutil.Discard})
|
||||
l := newLogger(controlStripper{io.Discard})
|
||||
benchmarkLogger(b, l)
|
||||
}
|
||||
|
||||
func BenchmarkLogNoStripper(b *testing.B) {
|
||||
l := newLogger(ioutil.Discard)
|
||||
l := newLogger(io.Discard)
|
||||
benchmarkLogger(b, l)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,20 +26,19 @@ func newDeviceActivity() *deviceActivity {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *deviceActivity) leastBusy(availability []Availability) (Availability, bool) {
|
||||
// Returns the index of the least busy device, or -1 if all are too busy.
|
||||
func (m *deviceActivity) leastBusy(availability []Availability) int {
|
||||
m.mut.Lock()
|
||||
low := 2<<30 - 1
|
||||
found := false
|
||||
var selected Availability
|
||||
for _, info := range availability {
|
||||
if usage := m.act[info.ID]; usage < low {
|
||||
best := -1
|
||||
for i := range availability {
|
||||
if usage := m.act[availability[i].ID]; usage < low {
|
||||
low = usage
|
||||
selected = info
|
||||
found = true
|
||||
best = i
|
||||
}
|
||||
}
|
||||
m.mut.Unlock()
|
||||
return selected, found
|
||||
return best
|
||||
}
|
||||
|
||||
func (m *deviceActivity) using(availability Availability) {
|
||||
|
||||
@@ -19,42 +19,42 @@ func TestDeviceActivity(t *testing.T) {
|
||||
devices := []Availability{n0, n1, n2}
|
||||
na := newDeviceActivity()
|
||||
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should still be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
|
||||
lb, _ := na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
lb := na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
lb, _ = na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n2 {
|
||||
lb = na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 2 {
|
||||
t.Errorf("Least busy device should be n2 (%v) not %v", n2, lb)
|
||||
}
|
||||
|
||||
lb, _ = na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
lb = na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
|
||||
na.done(n1)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
|
||||
na.done(n2)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should still be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
|
||||
na.done(n0)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (f *receiveOnlyFolder) Revert() {
|
||||
}
|
||||
|
||||
func (f *receiveOnlyFolder) revert() error {
|
||||
l.Infof("Reverting folder %v", f.Description)
|
||||
l.Infof("Reverting folder %v", f.Description())
|
||||
|
||||
f.setState(FolderScanning)
|
||||
defer f.setState(FolderIdle)
|
||||
|
||||
@@ -1532,8 +1532,8 @@ loop:
|
||||
// Select the least busy device to pull the block from. If we found no
|
||||
// feasible device at all, fail the block (and in the long run, the
|
||||
// file).
|
||||
selected, found := activity.leastBusy(candidates)
|
||||
if !found {
|
||||
found := activity.leastBusy(candidates)
|
||||
if found == -1 {
|
||||
if lastError != nil {
|
||||
state.fail(errors.Wrap(lastError, "pull"))
|
||||
} else {
|
||||
@@ -1542,7 +1542,9 @@ loop:
|
||||
break
|
||||
}
|
||||
|
||||
candidates = removeAvailability(candidates, selected)
|
||||
selected := candidates[found]
|
||||
candidates[found] = candidates[len(candidates)-1]
|
||||
candidates = candidates[:len(candidates)-1]
|
||||
|
||||
// Fetch the block, while marking the selected device as in use so that
|
||||
// leastBusy can select another device when someone else asks.
|
||||
@@ -1804,16 +1806,6 @@ func (f *sendReceiveFolder) inConflict(current, replacement protocol.Vector) boo
|
||||
return false
|
||||
}
|
||||
|
||||
func removeAvailability(availabilities []Availability, availability Availability) []Availability {
|
||||
for i := range availabilities {
|
||||
if availabilities[i] == availability {
|
||||
availabilities[i] = availabilities[len(availabilities)-1]
|
||||
return availabilities[:len(availabilities)-1]
|
||||
}
|
||||
}
|
||||
return availabilities
|
||||
}
|
||||
|
||||
func (f *sendReceiveFolder) moveForConflict(name, lastModBy string, scanChan chan<- string) error {
|
||||
if isConflict(name) {
|
||||
l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.")
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -680,8 +679,8 @@ func TestIssue3164(t *testing.T) {
|
||||
ignDir := filepath.Join("issue3164", "oktodelete")
|
||||
subDir := filepath.Join(ignDir, "foobar")
|
||||
must(t, ffs.MkdirAll(subDir, 0777))
|
||||
must(t, ioutil.WriteFile(filepath.Join(tmpDir, subDir, "file"), []byte("Hello"), 0644))
|
||||
must(t, ioutil.WriteFile(filepath.Join(tmpDir, ignDir, "file"), []byte("Hello"), 0644))
|
||||
must(t, os.WriteFile(filepath.Join(tmpDir, subDir, "file"), []byte("Hello"), 0644))
|
||||
must(t, os.WriteFile(filepath.Join(tmpDir, ignDir, "file"), []byte("Hello"), 0644))
|
||||
file := protocol.FileInfo{
|
||||
Name: "issue3164",
|
||||
}
|
||||
|
||||
@@ -178,7 +178,11 @@ func (c *folderSummaryService) listenForUpdates(ctx context.Context) error {
|
||||
// This loop needs to be fast so we don't miss too many events.
|
||||
|
||||
select {
|
||||
case ev := <-sub.C():
|
||||
case ev, ok := <-sub.C():
|
||||
if !ok {
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
c.processUpdate(ev)
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
@@ -168,6 +168,8 @@ type model struct {
|
||||
foldersRunning int32
|
||||
}
|
||||
|
||||
var _ config.Verifier = &model{}
|
||||
|
||||
type folderFactory func(*model, *db.FileSet, *ignore.Matcher, config.FolderConfiguration, versioner.Versioner, events.Logger, *util.Semaphore) service
|
||||
|
||||
var (
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -2152,7 +2151,7 @@ func TestIssue2782(t *testing.T) {
|
||||
if err := os.MkdirAll(testDir+"/syncdir", 0755); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(testDir+"/syncdir/file", []byte("hello, world\n"), 0644); err != nil {
|
||||
if err := os.WriteFile(testDir+"/syncdir/file", []byte("hello, world\n"), 0644); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
if err := os.Symlink("syncdir", testDir+"/synclink"); err != nil {
|
||||
@@ -2763,7 +2762,7 @@ func TestVersionRestore(t *testing.T) {
|
||||
// In each file, we write the filename as the content
|
||||
// We verify that the content matches at the expected filenames
|
||||
// after the restore operation.
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
must(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
@@ -2900,7 +2899,7 @@ func TestVersionRestore(t *testing.T) {
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(fd)
|
||||
content, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -2930,7 +2929,7 @@ func TestVersionRestore(t *testing.T) {
|
||||
must(t, err)
|
||||
defer fd.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(fd)
|
||||
content, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -212,11 +212,6 @@ func (t *ProgressEmitter) computeProgressUpdates() []progressUpdate {
|
||||
return progressUpdates
|
||||
}
|
||||
|
||||
// VerifyConfiguration implements the config.Committer interface
|
||||
func (t *ProgressEmitter) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommitConfiguration implements the config.Committer interface
|
||||
func (t *ProgressEmitter) CommitConfiguration(_, to config.Configuration) bool {
|
||||
t.mut.Lock()
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -236,7 +235,7 @@ func TestRequestVersioningSymlinkAttack(t *testing.T) {
|
||||
|
||||
// Create a temporary directory that we will use as target to see if
|
||||
// we can escape to it
|
||||
tmpdir, err := ioutil.TempDir("", "syncthing-test")
|
||||
tmpdir, err := os.MkdirTemp("", "syncthing-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -681,7 +680,7 @@ func TestRequestSymlinkWindows(t *testing.T) {
|
||||
}
|
||||
|
||||
func equalContents(path string, contents []byte) error {
|
||||
if bs, err := ioutil.ReadFile(path); err != nil {
|
||||
if bs, err := os.ReadFile(path); err != nil {
|
||||
return err
|
||||
} else if !bytes.Equal(bs, contents) {
|
||||
return errors.New("incorrect data")
|
||||
|
||||
@@ -8,7 +8,6 @@ package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -76,7 +75,7 @@ func init() {
|
||||
}
|
||||
|
||||
func createTmpWrapper(cfg config.Configuration) (config.Wrapper, context.CancelFunc) {
|
||||
tmpFile, err := ioutil.TempFile("", "syncthing-testConfig-")
|
||||
tmpFile, err := os.CreateTemp("", "syncthing-testConfig-")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -215,7 +214,7 @@ func cleanupModelAndRemoveDir(m *testModel, dir string) {
|
||||
}
|
||||
|
||||
func createTmpDir() string {
|
||||
tmpDir, err := ioutil.TempDir("", "syncthing_testFolder-")
|
||||
tmpDir, err := os.MkdirTemp("", "syncthing_testFolder-")
|
||||
if err != nil {
|
||||
panic("Failed to create temporary testing dir")
|
||||
}
|
||||
|
||||
+31
-39
@@ -45,10 +45,6 @@ func NewService(id protocol.DeviceID, cfg config.Wrapper) *Service {
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Service) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
|
||||
s.mut.Lock()
|
||||
if !s.enabled && to.Options.NATEnabled {
|
||||
@@ -125,11 +121,15 @@ func (s *Service) process(ctx context.Context) (int, time.Duration) {
|
||||
|
||||
s.mut.RLock()
|
||||
for _, mapping := range s.mappings {
|
||||
if mapping.expires.Before(time.Now()) {
|
||||
mapping.mut.RLock()
|
||||
expires := mapping.expires
|
||||
mapping.mut.RUnlock()
|
||||
|
||||
if expires.Before(time.Now()) {
|
||||
toRenew = append(toRenew, mapping)
|
||||
} else {
|
||||
toUpdate = append(toUpdate, mapping)
|
||||
mappingRenewIn := time.Until(mapping.expires)
|
||||
mappingRenewIn := time.Until(expires)
|
||||
if mappingRenewIn < renewIn {
|
||||
renewIn = mappingRenewIn
|
||||
}
|
||||
@@ -206,41 +206,36 @@ func (s *Service) RemoveMapping(mapping *Mapping) {
|
||||
// Optionally takes renew flag which indicates whether or not we should renew
|
||||
// mappings with existing natds
|
||||
func (s *Service) updateMapping(ctx context.Context, mapping *Mapping, nats map[string]Device, renew bool) {
|
||||
var added, removed []Address
|
||||
|
||||
renewalTime := time.Duration(s.cfg.Options().NATRenewalM) * time.Minute
|
||||
|
||||
mapping.mut.Lock()
|
||||
|
||||
mapping.expires = time.Now().Add(renewalTime)
|
||||
change := s.verifyExistingLocked(ctx, mapping, nats, renew)
|
||||
add := s.acquireNewLocked(ctx, mapping, nats)
|
||||
|
||||
newAdded, newRemoved := s.verifyExistingMappings(ctx, mapping, nats, renew)
|
||||
added = append(added, newAdded...)
|
||||
removed = append(removed, newRemoved...)
|
||||
mapping.mut.Unlock()
|
||||
|
||||
newAdded, newRemoved = s.acquireNewMappings(ctx, mapping, nats)
|
||||
added = append(added, newAdded...)
|
||||
removed = append(removed, newRemoved...)
|
||||
|
||||
if len(added) > 0 || len(removed) > 0 {
|
||||
mapping.notify(added, removed)
|
||||
if change || add {
|
||||
mapping.notify()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) verifyExistingMappings(ctx context.Context, mapping *Mapping, nats map[string]Device, renew bool) ([]Address, []Address) {
|
||||
var added, removed []Address
|
||||
|
||||
func (s *Service) verifyExistingLocked(ctx context.Context, mapping *Mapping, nats map[string]Device, renew bool) (change bool) {
|
||||
leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
|
||||
|
||||
for id, address := range mapping.addressMap() {
|
||||
for id, address := range mapping.extAddresses {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, nil
|
||||
return false
|
||||
default:
|
||||
}
|
||||
|
||||
// Delete addresses for NATDevice's that do not exist anymore
|
||||
nat, ok := nats[id]
|
||||
if !ok {
|
||||
mapping.removeAddress(id)
|
||||
removed = append(removed, address)
|
||||
mapping.removeAddressLocked(id)
|
||||
change = true
|
||||
continue
|
||||
} else if renew {
|
||||
// Only perform renewals on the nat's that have the right local IP
|
||||
@@ -256,35 +251,32 @@ func (s *Service) verifyExistingMappings(ctx context.Context, mapping *Mapping,
|
||||
addr, err := s.tryNATDevice(ctx, nat, mapping.address.Port, address.Port, leaseTime)
|
||||
if err != nil {
|
||||
l.Debugf("Failed to renew %s -> mapping on %s", mapping, address, id)
|
||||
mapping.removeAddress(id)
|
||||
removed = append(removed, address)
|
||||
mapping.removeAddressLocked(id)
|
||||
change = true
|
||||
continue
|
||||
}
|
||||
|
||||
l.Debugf("Renewed %s -> %s mapping on %s", mapping, address, id)
|
||||
|
||||
if !addr.Equal(address) {
|
||||
mapping.removeAddress(id)
|
||||
mapping.setAddress(id, addr)
|
||||
removed = append(removed, address)
|
||||
added = append(added, address)
|
||||
mapping.removeAddressLocked(id)
|
||||
mapping.setAddressLocked(id, addr)
|
||||
change = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added, removed
|
||||
return change
|
||||
}
|
||||
|
||||
func (s *Service) acquireNewMappings(ctx context.Context, mapping *Mapping, nats map[string]Device) ([]Address, []Address) {
|
||||
var added, removed []Address
|
||||
|
||||
func (s *Service) acquireNewLocked(ctx context.Context, mapping *Mapping, nats map[string]Device) (change bool) {
|
||||
leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
|
||||
addrMap := mapping.addressMap()
|
||||
addrMap := mapping.extAddresses
|
||||
|
||||
for id, nat := range nats {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, nil
|
||||
return false
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -310,11 +302,11 @@ func (s *Service) acquireNewMappings(ctx context.Context, mapping *Mapping, nats
|
||||
|
||||
l.Debugf("Acquired %s -> %s mapping on %s", mapping, addr, id)
|
||||
|
||||
mapping.setAddress(id, addr)
|
||||
added = append(added, addr)
|
||||
mapping.setAddressLocked(id, addr)
|
||||
change = true
|
||||
}
|
||||
|
||||
return added, removed
|
||||
return change
|
||||
}
|
||||
|
||||
// tryNATDevice tries to acquire a port mapping for the given internal address to
|
||||
|
||||
+10
-24
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
type MappingChangeSubscriber func(*Mapping, []Address, []Address)
|
||||
type MappingChangeSubscriber func()
|
||||
|
||||
type Mapping struct {
|
||||
protocol Protocol
|
||||
@@ -26,55 +26,41 @@ type Mapping struct {
|
||||
mut sync.RWMutex
|
||||
}
|
||||
|
||||
func (m *Mapping) setAddress(id string, address Address) {
|
||||
m.mut.Lock()
|
||||
if existing, ok := m.extAddresses[id]; !ok || !existing.Equal(address) {
|
||||
l.Infof("New NAT port mapping: external %s address %s to local address %s.", m.protocol, address, m.address)
|
||||
m.extAddresses[id] = address
|
||||
}
|
||||
m.mut.Unlock()
|
||||
func (m *Mapping) setAddressLocked(id string, address Address) {
|
||||
l.Infof("New NAT port mapping: external %s address %s to local address %s.", m.protocol, address, m.address)
|
||||
m.extAddresses[id] = address
|
||||
}
|
||||
|
||||
func (m *Mapping) removeAddress(id string) {
|
||||
m.mut.Lock()
|
||||
func (m *Mapping) removeAddressLocked(id string) {
|
||||
addr, ok := m.extAddresses[id]
|
||||
if ok {
|
||||
l.Infof("Removing NAT port mapping: external %s address %s, NAT %s is no longer available.", m.protocol, addr, id)
|
||||
delete(m.extAddresses, id)
|
||||
}
|
||||
m.mut.Unlock()
|
||||
}
|
||||
|
||||
func (m *Mapping) clearAddresses() {
|
||||
m.mut.Lock()
|
||||
var removed []Address
|
||||
change := len(m.extAddresses) > 0
|
||||
for id, addr := range m.extAddresses {
|
||||
l.Debugf("Clearing mapping %s: ID: %s Address: %s", m, id, addr)
|
||||
removed = append(removed, addr)
|
||||
delete(m.extAddresses, id)
|
||||
}
|
||||
m.expires = time.Time{}
|
||||
m.mut.Unlock()
|
||||
if len(removed) > 0 {
|
||||
m.notify(nil, removed)
|
||||
if change {
|
||||
m.notify()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mapping) notify(added, removed []Address) {
|
||||
func (m *Mapping) notify() {
|
||||
m.mut.RLock()
|
||||
for _, subscriber := range m.subscribers {
|
||||
subscriber(m, added, removed)
|
||||
subscriber()
|
||||
}
|
||||
m.mut.RUnlock()
|
||||
}
|
||||
|
||||
func (m *Mapping) addressMap() map[string]Address {
|
||||
m.mut.RLock()
|
||||
addrMap := m.extAddresses
|
||||
m.mut.RUnlock()
|
||||
return addrMap
|
||||
}
|
||||
|
||||
func (m *Mapping) Protocol() Protocol {
|
||||
return m.protocol
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package nat
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -60,7 +59,7 @@ func TestMappingValidGateway(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMappingClearAddresses(t *testing.T) {
|
||||
tmpFile, err := ioutil.TempFile("", "syncthing-testConfig-")
|
||||
tmpFile, err := os.CreateTemp("", "syncthing-testConfig-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func CreateAtomic(path string) (*AtomicWriter, error) {
|
||||
// permissions.
|
||||
func CreateAtomicFilesystem(filesystem fs.Filesystem, path string) (*AtomicWriter, error) {
|
||||
// The security of this depends on the tempfile having secure
|
||||
// permissions, 0600, from the beginning. This is what ioutil.TempFile
|
||||
// permissions, 0600, from the beginning. This is what os.CreateTemp
|
||||
// does. We have a test that verifies that that is the case, should this
|
||||
// ever change in the standard library in the future.
|
||||
fd, err := TempFile(filesystem, filepath.Dir(path), TempPrefix)
|
||||
|
||||
@@ -8,7 +8,6 @@ package osutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -35,7 +34,7 @@ func TestCreateAtomicCreate(t *testing.T) {
|
||||
t.Fatal("written bytes", n, "!= 5")
|
||||
}
|
||||
|
||||
if _, err := ioutil.ReadFile("testdata/file"); err == nil {
|
||||
if _, err := os.ReadFile("testdata/file"); err == nil {
|
||||
t.Fatal("file should not exist")
|
||||
}
|
||||
|
||||
@@ -43,7 +42,7 @@ func TestCreateAtomicCreate(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bs, err := ioutil.ReadFile("testdata/file")
|
||||
bs, err := os.ReadFile("testdata/file")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -62,7 +61,7 @@ func TestCreateAtomicReplaceReadOnly(t *testing.T) {
|
||||
func testCreateAtomicReplace(t *testing.T, oldPerms os.FileMode) {
|
||||
t.Helper()
|
||||
|
||||
testdir, err := ioutil.TempDir("", "syncthing")
|
||||
testdir, err := os.MkdirTemp("", "syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -75,7 +74,7 @@ func testCreateAtomicReplace(t *testing.T, oldPerms os.FileMode) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(testfile, []byte("some old data"), oldPerms); err != nil {
|
||||
if err := os.WriteFile(testfile, []byte("some old data"), oldPerms); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -103,7 +102,7 @@ func testCreateAtomicReplace(t *testing.T, oldPerms os.FileMode) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bs, err := ioutil.ReadFile(testfile)
|
||||
bs, err := os.ReadFile(testfile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -24,7 +23,7 @@ func TestTempFilePermissions(t *testing.T) {
|
||||
oldMask := syscall.Umask(0)
|
||||
defer syscall.Umask(oldMask)
|
||||
|
||||
fd, err := ioutil.TempFile("", "test")
|
||||
fd, err := os.CreateTemp("", "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -7,43 +7,19 @@
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
|
||||
aboveNormalPriorityClass = 0x00008000
|
||||
belowNormalPriorityClass = 0x00004000
|
||||
highPriorityClass = 0x00000080
|
||||
idlePriorityClass = 0x00000040
|
||||
normalPriorityClass = 0x00000020
|
||||
processModeBackgroundBegin = 0x00100000
|
||||
processModeBackgroundEnd = 0x00200000
|
||||
realtimePriorityClass = 0x00000100
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// SetLowPriority lowers the process CPU scheduling priority, and possibly
|
||||
// I/O priority depending on the platform and OS.
|
||||
func SetLowPriority() error {
|
||||
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
setPriorityClass := modkernel32.NewProc("SetPriorityClass")
|
||||
|
||||
if err := setPriorityClass.Find(); err != nil {
|
||||
return errors.Wrap(err, "find proc")
|
||||
}
|
||||
|
||||
handle, err := syscall.GetCurrentProcess()
|
||||
handle, err := windows.GetCurrentProcess()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get process handler")
|
||||
return errors.Wrap(err, "get process handle")
|
||||
}
|
||||
defer syscall.CloseHandle(handle)
|
||||
defer windows.CloseHandle(handle)
|
||||
|
||||
res, _, err := setPriorityClass.Call(uintptr(handle), belowNormalPriorityClass)
|
||||
if res != 0 {
|
||||
// "If the function succeeds, the return value is nonzero."
|
||||
return nil
|
||||
}
|
||||
err = windows.SetPriorityClass(handle, windows.BELOW_NORMAL_PRIORITY_CLASS)
|
||||
return errors.Wrap(err, "set priority class") // wraps nil as nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package osutil_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -83,7 +83,7 @@ func TestIsDeleted(t *testing.T) {
|
||||
func TestRenameOrCopy(t *testing.T) {
|
||||
mustTempDir := func() string {
|
||||
t.Helper()
|
||||
tmpDir, err := ioutil.TempDir("", "")
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func TestRenameOrCopy(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buf, err := ioutil.ReadAll(fd)
|
||||
buf, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func TestRenameOrCopy(t *testing.T) {
|
||||
if fd, err := test.dst.Open("new"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if buf, err := ioutil.ReadAll(fd); err != nil {
|
||||
if buf, err := io.ReadAll(fd); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != content {
|
||||
t.Fatalf("expected %s got %s", content, string(buf))
|
||||
|
||||
@@ -9,6 +9,7 @@ package osutil
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type ReplacingWriter struct {
|
||||
@@ -46,3 +47,16 @@ func (w ReplacingWriter) Write(bs []byte) (int, error) {
|
||||
|
||||
return written, err
|
||||
}
|
||||
|
||||
// LineEndingsWriter returns a writer that writes platform-appropriate line
|
||||
// endings. (This is a no-op on non-Windows platforms.)
|
||||
func LineEndingsWriter(w io.Writer) io.Writer {
|
||||
if runtime.GOOS != "windows" {
|
||||
return w
|
||||
}
|
||||
return &ReplacingWriter{
|
||||
Writer: w,
|
||||
From: '\n',
|
||||
To: []byte{'\r', '\n'},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package osutil_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTraversesSymlink(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir(".", ".test-TraversesSymlink-")
|
||||
tmpDir, err := os.MkdirTemp(".", ".test-TraversesSymlink-")
|
||||
if err != nil {
|
||||
panic("Failed to create temporary testing dir")
|
||||
}
|
||||
@@ -71,7 +70,7 @@ func TestTraversesSymlink(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue4875(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", ".test-Issue4875-")
|
||||
tmpDir, err := os.MkdirTemp("", ".test-Issue4875-")
|
||||
if err != nil {
|
||||
panic("Failed to create temporary testing dir")
|
||||
}
|
||||
|
||||
@@ -214,18 +214,3 @@ func untypeoify(s string) string {
|
||||
s = strings.ReplaceAll(s, "8", "B")
|
||||
return s
|
||||
}
|
||||
|
||||
// DeviceIDs is a sortable slice of DeviceID
|
||||
type DeviceIDs []DeviceID
|
||||
|
||||
func (l DeviceIDs) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l DeviceIDs) Less(a, b int) bool {
|
||||
return l[a].Compare(l[b]) == -1
|
||||
}
|
||||
|
||||
func (l DeviceIDs) Swap(a, b int) {
|
||||
l[a], l[b] = l[b], l[a]
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -432,8 +432,8 @@ func testMarshal(t *testing.T, prefix string, m1, m2 message) bool {
|
||||
bs1, _ := json.MarshalIndent(m1, "", " ")
|
||||
bs2, _ := json.MarshalIndent(m2, "", " ")
|
||||
if !bytes.Equal(bs1, bs2) {
|
||||
ioutil.WriteFile(prefix+"-1.txt", bs1, 0644)
|
||||
ioutil.WriteFile(prefix+"-2.txt", bs2, 0644)
|
||||
os.WriteFile(prefix+"-1.txt", bs1, 0644)
|
||||
os.WriteFile(prefix+"-2.txt", bs2, 0644)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -14,7 +14,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -393,7 +392,7 @@ func (p *Process) Model(folder string) (Model, error) {
|
||||
}
|
||||
|
||||
func (p *Process) readResponse(resp *http.Response) ([]byte, error) {
|
||||
bs, err := ioutil.ReadAll(resp.Body)
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return bs, err
|
||||
|
||||
@@ -141,7 +141,17 @@ func (c *staticClient) connect(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
conn := tls.Client(tcpConn, c.config)
|
||||
// Copy the TLS config and set the server name we're connecting to. In
|
||||
// many cases this will be an IP address, in which case it's a no-op. In
|
||||
// other cases it will be a hostname, which will cause the TLS stack to
|
||||
// send SNI.
|
||||
cfg := c.config
|
||||
if host, _, err := net.SplitHostPort(c.uri.Host); err == nil {
|
||||
cfg = cfg.Clone()
|
||||
cfg.ServerName = host
|
||||
}
|
||||
|
||||
conn := tls.Client(tcpConn, cfg)
|
||||
|
||||
if err := conn.SetDeadline(time.Now().Add(c.connectTimeout)); err != nil {
|
||||
conn.Close()
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -376,7 +375,7 @@ func TestWalkSymlinkWindows(t *testing.T) {
|
||||
|
||||
func TestWalkRootSymlink(t *testing.T) {
|
||||
// Create a folder with a symlink in it
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
tmp, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -709,7 +708,7 @@ func TestStopWalk(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue4799(t *testing.T) {
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
tmp, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -771,7 +770,7 @@ func TestRecurseInclude(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIssue4841(t *testing.T) {
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
tmp, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+8
-18
@@ -19,11 +19,7 @@ import (
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
)
|
||||
|
||||
type clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
var defaultClock clock = (*standardClock)(nil)
|
||||
var timeNow = time.Now
|
||||
|
||||
type Mutex interface {
|
||||
Lock()
|
||||
@@ -86,7 +82,7 @@ func (h holder) String() string {
|
||||
if h.at == "" {
|
||||
return "not held"
|
||||
}
|
||||
return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, defaultClock.Now().Sub(h.time))
|
||||
return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, timeNow().Sub(h.time))
|
||||
}
|
||||
|
||||
type loggedMutex struct {
|
||||
@@ -101,7 +97,7 @@ func (m *loggedMutex) Lock() {
|
||||
|
||||
func (m *loggedMutex) Unlock() {
|
||||
currentHolder := m.holder.Load().(holder)
|
||||
duration := defaultClock.Now().Sub(currentHolder.time)
|
||||
duration := timeNow().Sub(currentHolder.time)
|
||||
if duration >= threshold {
|
||||
l.Debugf("Mutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
|
||||
}
|
||||
@@ -125,7 +121,7 @@ type loggedRWMutex struct {
|
||||
}
|
||||
|
||||
func (m *loggedRWMutex) Lock() {
|
||||
start := defaultClock.Now()
|
||||
start := timeNow()
|
||||
|
||||
atomic.StoreInt32(&m.logUnlockers, 1)
|
||||
m.RWMutex.Lock()
|
||||
@@ -153,7 +149,7 @@ func (m *loggedRWMutex) Lock() {
|
||||
|
||||
func (m *loggedRWMutex) Unlock() {
|
||||
currentHolder := m.holder.Load().(holder)
|
||||
duration := defaultClock.Now().Sub(currentHolder.time)
|
||||
duration := timeNow().Sub(currentHolder.time)
|
||||
if duration >= threshold {
|
||||
l.Debugf("RWMutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
|
||||
}
|
||||
@@ -205,9 +201,9 @@ type loggedWaitGroup struct {
|
||||
}
|
||||
|
||||
func (wg *loggedWaitGroup) Wait() {
|
||||
start := defaultClock.Now()
|
||||
start := timeNow()
|
||||
wg.WaitGroup.Wait()
|
||||
duration := defaultClock.Now().Sub(start)
|
||||
duration := timeNow().Sub(start)
|
||||
if duration >= threshold {
|
||||
l.Debugf("WaitGroup took %v at %s", duration, getHolder())
|
||||
}
|
||||
@@ -219,7 +215,7 @@ func getHolder() holder {
|
||||
return holder{
|
||||
at: fmt.Sprintf("%s:%d", file, line),
|
||||
goid: goid(),
|
||||
time: defaultClock.Now(),
|
||||
time: timeNow(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,9 +296,3 @@ func (w *TimeoutCondWaiter) Wait() bool {
|
||||
func (w *TimeoutCondWaiter) Stop() {
|
||||
w.timer.Stop()
|
||||
}
|
||||
|
||||
type standardClock struct{}
|
||||
|
||||
func (*standardClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ func TestTypes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMutex(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
@@ -97,10 +97,10 @@ func TestMutex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRWMutex(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
@@ -170,10 +170,10 @@ func TestRWMutex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWaitGroup(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
|
||||
@@ -38,7 +38,11 @@ func (s *auditService) Serve(ctx context.Context) error {
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev := <-sub.C():
|
||||
case ev, ok := <-sub.C():
|
||||
if !ok {
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
enc.Encode(ev)
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package syncthing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
|
||||
func tempCfgFilename(t *testing.T) string {
|
||||
t.Helper()
|
||||
f, err := ioutil.TempFile("", "syncthing-testConfig-")
|
||||
f, err := os.CreateTemp("", "syncthing-testConfig-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+25
-3
@@ -10,7 +10,6 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -24,6 +23,29 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
)
|
||||
|
||||
func EnsureDir(dir string, mode fs.FileMode) error {
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
|
||||
err := fs.MkdirAll(".", mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fi, err := fs.Stat("."); err == nil {
|
||||
// Apprently the stat may fail even though the mkdirall passed. If it
|
||||
// does, we'll just assume things are in order and let other things
|
||||
// fail (like loading or creating the config...).
|
||||
currentMode := fi.Mode() & 0777
|
||||
if currentMode != mode {
|
||||
err := fs.Chmod(".", mode)
|
||||
// This can fail on crappy filesystems, nothing we can do about it.
|
||||
if err != nil {
|
||||
l.Warnln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadOrGenerateCertificate(certFile, keyFile string) (tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
@@ -110,12 +132,12 @@ func archiveAndSaveConfig(cfg config.Wrapper, originalVersion int) error {
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
bs, err := ioutil.ReadFile(src)
|
||||
bs, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(dst, bs, 0600); err != nil {
|
||||
if err := os.WriteFile(dst, bs, 0600); err != nil {
|
||||
// Attempt to clean up
|
||||
os.Remove(dst)
|
||||
return err
|
||||
|
||||
@@ -31,7 +31,11 @@ func (s *verboseService) Serve(ctx context.Context) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case ev := <-sub.C():
|
||||
case ev, ok := <-sub.C():
|
||||
if !ok {
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
formatted := s.formatEvent(ev)
|
||||
if formatted != "" {
|
||||
l.Verboseln(formatted)
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@@ -284,7 +283,7 @@ func readTarGz(archiveName, dir string, r io.Reader) (string, error) {
|
||||
}
|
||||
|
||||
func readZip(archiveName, dir string, r io.Reader) (string, error) {
|
||||
body, err := ioutil.ReadAll(r)
|
||||
body, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -357,7 +356,7 @@ func archiveFileVisitor(dir string, tempFile *string, signature *[]byte, archive
|
||||
|
||||
case "release.sig":
|
||||
l.Debugf("found signature %s", archivePath)
|
||||
*signature, err = ioutil.ReadAll(io.LimitReader(filedata, maxSignatureSize))
|
||||
*signature, err = io.ReadAll(io.LimitReader(filedata, maxSignatureSize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -392,7 +391,7 @@ func verifyUpgrade(archiveName, tempName string, sig []byte) error {
|
||||
// multireader. This ensures that it is not only a bonafide syncthing
|
||||
// binary, but it is also of exactly the platform and version we expect.
|
||||
|
||||
mr := io.MultiReader(bytes.NewBufferString(archiveName+"\n"), fd)
|
||||
mr := io.MultiReader(strings.NewReader(archiveName+"\n"), fd)
|
||||
err = signature.Verify(SigningKey, sig, mr)
|
||||
fd.Close()
|
||||
|
||||
@@ -407,7 +406,7 @@ func verifyUpgrade(archiveName, tempName string, sig []byte) error {
|
||||
func writeBinary(dir string, inFile io.Reader) (filename string, err error) {
|
||||
// Write the binary to a temporary file.
|
||||
|
||||
outFile, err := ioutil.TempFile(dir, "syncthing")
|
||||
outFile, err := os.CreateTemp(dir, "syncthing")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -467,7 +467,7 @@ func soapRequest(ctx context.Context, url, service, function, message string) ([
|
||||
return resp, err
|
||||
}
|
||||
|
||||
resp, _ = ioutil.ReadAll(r.Body)
|
||||
resp, _ = io.ReadAll(r.Body)
|
||||
l.Debugf("SOAP Response: %s\n\n%s\n\n", r.Status, resp)
|
||||
|
||||
r.Body.Close()
|
||||
|
||||
@@ -188,10 +188,6 @@ func (h *failureHandler) addReport(data FailureData, evTime time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *failureHandler) VerifyConfiguration(_, _ config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *failureHandler) CommitConfiguration(from, to config.Configuration) bool {
|
||||
if from.Options.CREnabled != to.Options.CREnabled || from.Options.CRURL != to.Options.CRURL {
|
||||
h.optsChan <- to.Options
|
||||
|
||||
@@ -390,10 +390,6 @@ func (s *Service) Serve(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
|
||||
if from.Options.URAccepted != to.Options.URAccepted || from.Options.URUniqueID != to.Options.URUniqueID || from.Options.URURL != to.Options.URURL {
|
||||
select {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package versioner
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -85,7 +84,7 @@ func prepForRemoval(t *testing.T, file string) {
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(file, []byte("hello\n"), 0644); err != nil {
|
||||
if err := os.WriteFile(file, []byte("hello\n"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
package versioner
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -55,7 +55,7 @@ func TestSimpleVersioningVersionCount(t *testing.T) {
|
||||
t.Skip("Test takes some time, skipping.")
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
//defer os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package versioner
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -133,11 +133,11 @@ func TestCreateVersionPath(t *testing.T) {
|
||||
)
|
||||
|
||||
// Create a test dir and file
|
||||
tmpDir, err := ioutil.TempDir("", "")
|
||||
tmpDir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(tmpDir, archiveFile), []byte("sup"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, archiveFile), []byte("sup"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
package versioner
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -19,12 +20,12 @@ func TestTrashcanArchiveRestoreSwitcharoo(t *testing.T) {
|
||||
// This tests that trashcan versioner restoration correctly archives existing file, because trashcan versioner
|
||||
// files are untagged, archiving existing file to replace with a restored version technically should collide in
|
||||
// in names.
|
||||
tmpDir1, err := ioutil.TempDir("", "")
|
||||
tmpDir1, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpDir2, err := ioutil.TempDir("", "")
|
||||
tmpDir2, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -105,7 +106,7 @@ func readFile(t *testing.T, filesystem fs.Filesystem, name string) string {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer fd.Close()
|
||||
buf, err := ioutil.ReadAll(fd)
|
||||
buf, err := io.ReadAll(fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ package versioner
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -56,7 +55,7 @@ func TestVersionerCleanOut(t *testing.T) {
|
||||
oldTime := time.Now().Add(-8 * 24 * time.Hour)
|
||||
for file, shouldRemove := range testcases {
|
||||
os.MkdirAll(filepath.Dir(file), 0777)
|
||||
if err := ioutil.WriteFile(file, []byte("data"), 0644); err != nil {
|
||||
if err := os.WriteFile(file, []byte("data"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if shouldRemove {
|
||||
|
||||
@@ -162,8 +162,10 @@ func (a *aggregator) mainLoop(in <-chan fs.Event, out chan<- []string, cfg confi
|
||||
select {
|
||||
case event := <-in:
|
||||
a.newEvent(event, inProgress)
|
||||
case event := <-inProgressItemSubscription.C():
|
||||
updateInProgressSet(event, inProgress)
|
||||
case event, ok := <-inProgressItemSubscription.C():
|
||||
if ok {
|
||||
updateInProgressSet(event, inProgress)
|
||||
}
|
||||
case <-a.notifyTimer.C:
|
||||
a.actOnTimer(out)
|
||||
case interval := <-a.notifyTimerResetChan:
|
||||
@@ -419,10 +421,6 @@ func (a *aggregator) String() string {
|
||||
return fmt.Sprintf("aggregator/%s:", a.folderCfg.Description())
|
||||
}
|
||||
|
||||
func (a *aggregator) VerifyConfiguration(from, to config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *aggregator) CommitConfiguration(from, to config.Configuration) bool {
|
||||
for _, folderCfg := range to.Folders {
|
||||
if folderCfg.ID == a.folderID {
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
var payload = []byte("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")
|
||||
|
||||
func TestFinder(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "")
|
||||
f, err := os.CreateTemp("", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user