Compare commits

..
22 Commits
Author SHA1 Message Date
Simon FreiandJakob Borg c00c6b3957 build: Bump quic-go to 0.24.0 2021-12-30 13:07:01 +01:00
Gahl SarafandGitHub cc39341eb9 lib: Fix panic due to closed event subscriptions on shutdown (#8079) 2021-12-22 20:16:21 +01:00
ignacy123andGitHub bf7f82f7b2 cmd/syncthing/cli: Add command to show pending devices/folders (fixes #8068) (#8069) 2021-12-09 21:18:47 +01:00
greatroarandJakob Borg eb857dbc45 lib/osutil: Use x/sys/windows for SetLowPriority 2021-11-27 15:35:07 +01:00
greatroarandJakob Borg e7620e951d cmd/stdiscosrv: use strconv.Itoa 2021-11-27 15:35:07 +01:00
greatroarandJakob Borg 286a25ae49 lib/upgrade: Use strings.Reader instead of bytes.Buffer 2021-11-27 15:35:07 +01:00
greatroarandJakob Borg ae70046b49 lib/protocol: Remove unused sorting boilerplate 2021-11-27 15:35:07 +01:00
greatroarandJakob Borg c366933416 lib/sync: Make the clock a function pointer 2021-11-27 15:35:07 +01:00
greatroarandJakob Borg 6a9716e8a1 lib/model: Return index from deviceActivity.leastBusy
This way, we don't need a second loop over the Availabilities to remove
the selected item.
2021-11-26 12:07:43 +01:00
villekalliomakiandGitHub b84ee4d240 gui: Notice on folders with ignoreDelete enabled (fixes #8050) (#8054) 2021-11-25 14:04:59 +01:00
greatroarandJakob Borg 8a1e54d58a lib/fs: Optimize Canonicalize
When pathSep is a constant, the compiler precomputes pathSep+pathSep and
".."+pathSep instead of emitting function calls to compute "//" and
"../". Benchmark results in lib/osutil:

name                old time/op    new time/op    delta
TraversesSymlink-8    8.86µs ± 3%    8.53µs ± 4%  -3.79%  (p=0.000 n=18+20)

name                old alloc/op   new alloc/op   delta
TraversesSymlink-8    1.06kB ± 0%    1.06kB ± 0%    ~     (all equal)

name                old allocs/op  new allocs/op  delta
TraversesSymlink-8      15.0 ± 0%      15.0 ± 0%    ~     (all equal)
2021-11-23 21:25:29 +01:00
greatroarandJakob Borg 3e032c4da6 lib/fs: optimize Windows path checking/sanitizing
name                          old time/op    new time/op    delta
WindowsInvalidFilenameValid-8     875ns ± 1%     150ns ± 1%  -82.84%  (p=0.000 n=9+9)
WindowsInvalidFilenameNUL-8       276ns ± 4%     121ns ± 3%  -56.26%  (p=0.000 n=10+10)

name                          old alloc/op   new alloc/op   delta
WindowsInvalidFilenameValid-8     32.0B ± 0%     16.0B ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8       32.0B ± 0%     19.0B ± 0%  -40.62%  (p=0.000 n=10+10)

name                          old allocs/op  new allocs/op  delta
WindowsInvalidFilenameValid-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8        2.00 ± 0%      2.00 ± 0%     ~     (all equal)
2021-11-23 21:25:29 +01:00
Jakob BorgandGitHub 7c3b267645 meta: Add test for deprecated package ioutil (#8053) 2021-11-22 10:11:00 +01:00
tomasz1986andGitHub 7161a99b04 gui: Allow text wrapping in remove folder/device modals (#7976)
Remove the embedded CSS that prevents the lines from wrapping, resulting
in device and folder names being hidden on small screens.
2021-11-22 09:41:43 +01:00
Jakob BorgandGitHub 1754c93370 lib/config, lib/ignore: Write Windows line endings (fixes #7115) (#8052) 2021-11-22 09:38:24 +01:00
Jakob BorgandGitHub 4b750b6dc3 all: Remove usage of deprecated io/ioutil (#7971)
As of Go 1.16 io/ioutil is deprecated. This replaces usage with the
corresponding functions in package os and package io.
2021-11-22 08:59:47 +01:00
greatroarandGitHub bf89bffb0b lib/config: Decouple VerifyConfiguration from Committer (#7939)
... and remove 8/10 implementations, which were no-ops. This saves code
and time copying configurations.
2021-11-22 08:45:29 +01:00
Jakob BorgandGitHub e2288fe441 lib/relay: Send SNI when the address is a host name (fixes #8014) (#8015) 2021-11-22 08:31:03 +01:00
greatroarandGitHub 8265dac127 lib/nat: Fix race condition in Mapping (#8042)
The locking protocol in nat.Mapping was racy:

* Mapping.addressMap RLock'd, but then returned a map shared between
  caller and Mapping, so the lock didn't do anything.

* Operations inside Service.{verifyExistingMappings,acquireNewMappings}
  would lock the map for every update, but that means callers to
  Mapping.ExternalAddresses can be looping over the map while the
  Service methods are concurrently modifying it. When the Go runtime
  detects that happening, it panics.

* Mapping.expires was read and updated without locking.

The Service methods now lock the map once and release the lock only when
done.

Also, subscribers no longer get the added and removed addresses, because
none of them were using the information. This was changed for a previous
attempt to retain the fine-grained locking and not reverted because it
simplifies the code.
2021-11-22 08:29:44 +01:00
André ColombandGitHub 100870e142 cmd/syncthing: Implement generate as a subcommand with optional API credential setting (fixes #8021) (#8043)
Accept a subcommand as an alternative to the --generate option.  It
accepts a custom config directory through either the --home or
--config options, using the default location if neither is given.

Add the options --gui-user and --gui-password to "generate", but not
the "serve --generate" option form.  If either is given, an existing
config will not abort the command, but rather load, modify and save it
with the new credentials.  The password can be read from standard
input by passing only a single dash as argument.

Config modification is skipped if the value matches what's already in
the config.

* cmd/syncthing: Utilize lib/locations package in generate().
Instead of manually joining paths with "magic" file names, get them
from the centralized locations helper lib.

* cmd/syncthing: Simplify logging for --generate option.
Visible change: No more timestamp prefixes.
2021-11-18 22:57:59 +01:00
Jakob Borg 12fb7f2a0a lib/model: Correct "reverting folder" log entry 2021-11-17 12:52:10 +01:00
Jakob Borg f1bf4d899a lib/model: Correct handling of fakefs cache
We looked under one cache key, then stored under another...
2021-11-17 12:52:10 +01:00
115 changed files with 763 additions and 572 deletions
+7 -8
View File
@@ -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))
+1 -2
View File
@@ -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)
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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)
}
+2 -2
View File
@@ -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())
+2 -3
View File
@@ -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)
+2 -2
View File
@@ -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)
}
+1 -1
View File
@@ -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)
}
}
+3 -4
View File
@@ -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)
}
+1 -1
View File
@@ -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:
+2 -2
View File
@@ -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)
+3 -4
View File
@@ -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)
}
+2 -2
View File
@@ -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
}
+29
View File
@@ -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")),
},
},
}
+1
View File
@@ -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",
+2 -2
View File
@@ -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
}
+15
View File
@@ -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"`
}
+1 -2
View File
@@ -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
}
+2 -2
View File
@@ -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)
}
+144
View File
@@ -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
View File
@@ -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()
+3 -4
View File
@@ -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
View File
@@ -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 {
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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=
+7
View File
@@ -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>&nbsp;<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
View File
@@ -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
View File
@@ -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
}
+2 -2
View File
@@ -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")
+1 -2
View File
@@ -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
+2 -3
View File
@@ -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).
+1 -2
View File
@@ -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
}
+39 -5
View File
@@ -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
View File
@@ -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
-4
View File
@@ -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()
-4
View File
@@ -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 {
+1 -1
View File
@@ -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.
+1 -2
View File
@@ -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
}
+2 -2
View File
@@ -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")
-4
View File
@@ -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()
+1 -2
View File
@@ -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)
}
+1 -2
View File
@@ -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
View File
@@ -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
+6 -7
View File
@@ -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)
}
+1 -1
View File
@@ -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
+2 -3
View File
@@ -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 -9
View File
@@ -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
View File
@@ -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
}
+12
View File
@@ -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")
}
+2 -1
View File
@@ -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 {
+45 -7
View File
@@ -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")
}
}
+1 -2
View File
@@ -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})
}
+3 -3
View File
@@ -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)
}
+7 -8
View File
@@ -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) {
+14 -14
View File
@@ -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)
}
}
+1 -1
View File
@@ -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)
+5 -13
View File
@@ -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.")
+2 -3
View File
@@ -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",
}
+5 -1
View File
@@ -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()
+2
View File
@@ -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 (
+4 -5
View File
@@ -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)
}
-5
View File
@@ -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()
+2 -3
View File
@@ -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")
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+1 -2
View File
@@ -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)
}
+1 -1
View File
@@ -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)
+5 -6
View File
@@ -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)
}
+1 -2
View File
@@ -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)
}
+5 -29
View File
@@ -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
}
+4 -4
View File
@@ -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))
+14
View File
@@ -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'},
}
}
+2 -3
View File
@@ -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")
}
-15
View File
@@ -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]
}
+3 -3
View File
@@ -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
View File
@@ -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
+11 -1
View File
@@ -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()
+3 -4
View File
@@ -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
View File
@@ -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()
}
+9 -9
View File
@@ -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)
+5 -1
View File
@@ -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()
+1 -2
View File
@@ -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
View File
@@ -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
+5 -1
View File
@@ -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)
+4 -5
View File
@@ -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
View File
@@ -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()
-4
View File
@@ -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
-4
View File
@@ -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 {
+1 -2
View File
@@ -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)
}
}
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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)
}
+5 -4
View File
@@ -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)
}
+1 -2
View File
@@ -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 {
+4 -6
View File
@@ -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 {
+1 -2
View File
@@ -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