Prechádzať zdrojové kódy

all: Modernize error wrapping (#8491)

This replaces old style errors.Wrap with modern fmt.Errorf and removes
the (direct) dependency on github.com/pkg/errors. A couple of cases are
adjusted by hand as previously errors.Wrap(nil, ...) would return nil,
which is not what fmt.Errorf does.
Jakob Borg 3 rokov pred
rodič
commit
b10d106a55

+ 1 - 1
cmd/syncthing/cli/config.go

@@ -8,11 +8,11 @@ package cli
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 	"reflect"
 
 	"github.com/AudriusButkevicius/recli"
-	"github.com/pkg/errors"
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/urfave/cli"
 )

+ 3 - 3
cmd/syncthing/cli/main.go

@@ -8,6 +8,7 @@ package cli
 
 import (
 	"bufio"
+	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -15,7 +16,6 @@ import (
 
 	"github.com/alecthomas/kong"
 	"github.com/flynn-archive/go-shlex"
-	"github.com/pkg/errors"
 	"github.com/urfave/cli"
 
 	"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
@@ -51,7 +51,7 @@ func runInternal(c preCli, cliArgs []string) error {
 	// Not set as default above because the strings can be really long.
 	err := cmdutil.SetConfigDataLocationsFromFlags(c.HomeDir, c.ConfDir, c.DataDir)
 	if err != nil {
-		return errors.Wrap(err, "Command line options:")
+		return fmt.Errorf("Command line options: %w", err)
 	}
 	clientFactory := &apiClientFactory{
 		cfg: config.GUIConfiguration{
@@ -124,7 +124,7 @@ func runInternal(c preCli, cliArgs []string) error {
 					for scanner.Scan() {
 						input, err := shlex.Split(scanner.Text())
 						if err != nil {
-							return errors.Wrap(err, "parsing input")
+							return fmt.Errorf("parsing input: %w", err)
 						}
 						if len(input) == 0 {
 							continue

+ 1 - 2
cmd/syncthing/main.go

@@ -10,6 +10,7 @@ import (
 	"bytes"
 	"context"
 	"crypto/tls"
+	"errors"
 	"fmt"
 	"io"
 	"log"
@@ -50,8 +51,6 @@ import (
 	"github.com/syncthing/syncthing/lib/svcutil"
 	"github.com/syncthing/syncthing/lib/syncthing"
 	"github.com/syncthing/syncthing/lib/upgrade"
-
-	"github.com/pkg/errors"
 )
 
 const (

+ 1 - 1
go.mod

@@ -37,7 +37,7 @@ require (
 	github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
 	github.com/oschwald/geoip2-golang v1.5.0
 	github.com/pierrec/lz4/v4 v4.1.15
-	github.com/pkg/errors v0.9.1
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.12.2
 	github.com/prometheus/common v0.32.1 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect

+ 3 - 4
lib/config/config.go

@@ -10,6 +10,7 @@ package config
 import (
 	"encoding/json"
 	"encoding/xml"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -19,8 +20,6 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/build"
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/protocol"
@@ -116,13 +115,13 @@ func New(myID protocol.DeviceID) Configuration {
 func (cfg *Configuration) ProbeFreePorts() error {
 	port, err := getFreePort("127.0.0.1", DefaultGUIPort)
 	if err != nil {
-		return errors.Wrap(err, "get free port (GUI)")
+		return fmt.Errorf("get free port (GUI): %w", err)
 	}
 	cfg.GUI.RawAddress = fmt.Sprintf("127.0.0.1:%d", port)
 
 	port, err = getFreePort("0.0.0.0", DefaultTCPPort)
 	if err != nil {
-		return errors.Wrap(err, "get free port (BEP)")
+		return fmt.Errorf("get free port (BEP): %w", err)
 	}
 	if port == DefaultTCPPort {
 		cfg.Options.RawListenAddresses = []string{"default"}

+ 3 - 3
lib/connections/quic_dial.go

@@ -12,12 +12,12 @@ package connections
 import (
 	"context"
 	"crypto/tls"
+	"fmt"
 	"net"
 	"net/url"
 	"time"
 
 	"github.com/lucas-clemente/quic-go"
-	"github.com/pkg/errors"
 
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/connections/registry"
@@ -79,7 +79,7 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
 		if createdConn != nil {
 			_ = createdConn.Close()
 		}
-		return internalConn{}, errors.Wrap(err, "dial")
+		return internalConn{}, fmt.Errorf("dial: %w", err)
 	}
 
 	stream, err := session.OpenStreamSync(ctx)
@@ -89,7 +89,7 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
 		if createdConn != nil {
 			_ = createdConn.Close()
 		}
-		return internalConn{}, errors.Wrap(err, "open stream")
+		return internalConn{}, fmt.Errorf("open stream: %w", err)
 	}
 
 	return newInternalConn(&quicTlsConn{session, stream, createdConn}, connTypeQUICClient, quicPriority), nil

+ 1 - 2
lib/connections/relay_listen.go

@@ -9,12 +9,11 @@ package connections
 import (
 	"context"
 	"crypto/tls"
+	"errors"
 	"net/url"
 	"sync"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/connections/registry"
 	"github.com/syncthing/syncthing/lib/dialer"

+ 1 - 1
lib/connections/service.go

@@ -13,6 +13,7 @@ import (
 	"context"
 	"crypto/tls"
 	"crypto/x509"
+	"errors"
 	"fmt"
 	"math"
 	"net"
@@ -37,7 +38,6 @@ import (
 	_ "github.com/syncthing/syncthing/lib/pmp"
 	_ "github.com/syncthing/syncthing/lib/upnp"
 
-	"github.com/pkg/errors"
 	"github.com/thejerf/suture/v4"
 	"golang.org/x/time/rate"
 )

+ 3 - 3
lib/model/folder.go

@@ -8,6 +8,7 @@ package model
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"math/rand"
 	"path/filepath"
@@ -15,8 +16,6 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/db"
 	"github.com/syncthing/syncthing/lib/events"
@@ -317,7 +316,7 @@ func (f *folder) getHealthErrorAndLoadIgnores() error {
 	}
 	if f.Type != config.FolderTypeReceiveEncrypted {
 		if err := f.ignores.Load(".stignore"); err != nil && !fs.IsNotExist(err) {
-			return errors.Wrap(err, "loading ignores")
+			return fmt.Errorf("loading ignores: %w", err)
 		}
 	}
 	return nil
@@ -1060,6 +1059,7 @@ func (f *folder) monitorWatch(ctx context.Context) {
 				l.Warnf("Filesystem watching (kqueue) is enabled on %v with a lot of files/directories, and that requires a lot of resources and might slow down your system significantly", f.Description())
 			}
 		case <-ctx.Done():
+			aggrCancel() // for good measure and keeping the linters happy
 			return
 		}
 	}

+ 24 - 23
lib/model/folder_sendrecv.go

@@ -8,6 +8,7 @@ package model
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"io"
 	"path/filepath"
@@ -16,8 +17,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/build"
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/db"
@@ -593,7 +592,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, snap *db.Snapshot,
 		// Check that it is what we have in the database.
 		curFile, hasCurFile := snap.Get(protocol.LocalDeviceID, file.Name)
 		if err := f.scanIfItemChanged(file.Name, info, curFile, hasCurFile, scanChan); err != nil {
-			err = errors.Wrap(err, "handling dir")
+			err = fmt.Errorf("handling dir: %w", err)
 			f.newPullError(file.Name, err)
 			return
 		}
@@ -647,13 +646,13 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo, snap *db.Snapshot,
 		if err = f.inWritableDir(mkdir, file.Name); err == nil {
 			dbUpdateChan <- dbUpdateJob{file, dbUpdateHandleDir}
 		} else {
-			f.newPullError(file.Name, errors.Wrap(err, "creating directory"))
+			f.newPullError(file.Name, fmt.Errorf("creating directory: %w", err))
 		}
 		return
 	// Weird error when stat()'ing the dir. Probably won't work to do
 	// anything else with it if we can't even stat() it.
 	case err != nil:
-		f.newPullError(file.Name, errors.Wrap(err, "checking file to be replaced"))
+		f.newPullError(file.Name, fmt.Errorf("checking file to be replaced: %w", err))
 		return
 	}
 
@@ -675,7 +674,7 @@ func (f *sendReceiveFolder) checkParent(file string, scanChan chan<- string) boo
 	parent := filepath.Dir(file)
 
 	if err := osutil.TraversesSymlink(f.mtimefs, parent); err != nil {
-		f.newPullError(file, errors.Wrap(err, "checking parent dirs"))
+		f.newPullError(file, fmt.Errorf("checking parent dirs: %w", err))
 		return false
 	}
 
@@ -700,7 +699,7 @@ func (f *sendReceiveFolder) checkParent(file string, scanChan chan<- string) boo
 	}
 	l.Debugf("%v creating parent directory of %v", f, file)
 	if err := f.mtimefs.MkdirAll(parent, 0755); err != nil {
-		f.newPullError(file, errors.Wrap(err, "creating parent dir"))
+		f.newPullError(file, fmt.Errorf("creating parent dir: %w", err))
 		return false
 	}
 	if f.Type != config.FolderTypeReceiveEncrypted {
@@ -761,7 +760,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo, snap *db.Snaps
 	if err = f.inWritableDir(createLink, file.Name); err == nil {
 		dbUpdateChan <- dbUpdateJob{file, dbUpdateHandleSymlink}
 	} else {
-		f.newPullError(file.Name, errors.Wrap(err, "symlink create"))
+		f.newPullError(file.Name, fmt.Errorf("symlink create: %w", err))
 	}
 }
 
@@ -810,7 +809,7 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, snap *db.Snapshot,
 
 	defer func() {
 		if err != nil {
-			f.newPullError(file.Name, errors.Wrap(err, "delete dir"))
+			f.newPullError(file.Name, fmt.Errorf("delete dir: %w", err))
 		}
 		f.evLogger.Log(events.ItemFinished, map[string]interface{}{
 			"folder": f.folderID,
@@ -860,7 +859,7 @@ func (f *sendReceiveFolder) deleteFileWithCurrent(file, cur protocol.FileInfo, h
 
 	defer func() {
 		if err != nil {
-			f.newPullError(file.Name, errors.Wrap(err, "delete file"))
+			f.newPullError(file.Name, fmt.Errorf("delete file: %w", err))
 		}
 		f.evLogger.Log(events.ItemFinished, map[string]interface{}{
 			"folder": f.folderID,
@@ -1307,7 +1306,7 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
 		for _, block := range state.blocks {
 			select {
 			case <-f.ctx.Done():
-				state.fail(errors.Wrap(f.ctx.Err(), "folder stopped"))
+				state.fail(fmt.Errorf("folder stopped: %w", f.ctx.Err()))
 				break blocks
 			default:
 			}
@@ -1336,7 +1335,7 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
 
 					err = f.limitedWriteAt(dstFd, buf, block.Offset)
 					if err != nil {
-						state.fail(errors.Wrap(err, "dst write"))
+						state.fail(fmt.Errorf("dst write: %w", err))
 					}
 					if offset == block.Offset {
 						state.copiedFromOrigin()
@@ -1386,7 +1385,7 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
 						err = f.limitedWriteAt(dstFd, buf, block.Offset)
 					}
 					if err != nil {
-						state.fail(errors.Wrap(err, "dst write"))
+						state.fail(fmt.Errorf("dst write: %w", err))
 					}
 					if path == state.file.Name {
 						state.copiedFromOrigin()
@@ -1536,7 +1535,7 @@ loop:
 	for {
 		select {
 		case <-f.ctx.Done():
-			state.fail(errors.Wrap(f.ctx.Err(), "folder stopped"))
+			state.fail(fmt.Errorf("folder stopped: %w", f.ctx.Err()))
 			break loop
 		default:
 		}
@@ -1547,9 +1546,9 @@ loop:
 		found := activity.leastBusy(candidates)
 		if found == -1 {
 			if lastError != nil {
-				state.fail(errors.Wrap(lastError, "pull"))
+				state.fail(fmt.Errorf("pull: %w", lastError))
 			} else {
-				state.fail(errors.Wrap(errNoDevice, "pull"))
+				state.fail(fmt.Errorf("pull: %w", errNoDevice))
 			}
 			break
 		}
@@ -1587,7 +1586,7 @@ loop:
 		// Save the block data we got from the cluster
 		err = f.limitedWriteAt(fd, buf, state.block.Offset)
 		if err != nil {
-			state.fail(errors.Wrap(err, "save"))
+			state.fail(fmt.Errorf("save: %w", err))
 		} else {
 			state.pullDone(state.block)
 		}
@@ -1822,14 +1821,14 @@ func (f *sendReceiveFolder) moveForConflict(name, lastModBy string, scanChan cha
 	if isConflict(name) {
 		l.Infoln("Conflict for", name, "which is already a conflict copy; not copying again.")
 		if err := f.mtimefs.Remove(name); err != nil && !fs.IsNotExist(err) {
-			return errors.Wrap(err, contextRemovingOldItem)
+			return fmt.Errorf("%s: %w", contextRemovingOldItem, err)
 		}
 		return nil
 	}
 
 	if f.MaxConflicts == 0 {
 		if err := f.mtimefs.Remove(name); err != nil && !fs.IsNotExist(err) {
-			return errors.Wrap(err, contextRemovingOldItem)
+			return fmt.Errorf("%s: %w", contextRemovingOldItem, err)
 		}
 		return nil
 	}
@@ -1888,7 +1887,9 @@ func (f *sendReceiveFolder) newPullError(path string, err error) {
 // deleteItemOnDisk deletes the file represented by old that is about to be replaced by new.
 func (f *sendReceiveFolder) deleteItemOnDisk(item protocol.FileInfo, snap *db.Snapshot, scanChan chan<- string) (err error) {
 	defer func() {
-		err = errors.Wrap(err, contextRemovingOldItem)
+		if err != nil {
+			err = fmt.Errorf("%s: %w", contextRemovingOldItem, err)
+		}
 	}()
 
 	switch {
@@ -2056,7 +2057,7 @@ func (f *sendReceiveFolder) scanIfItemChanged(name string, stat fs.FileInfo, ite
 	// touching the item.
 	statItem, err := scanner.CreateFileInfo(stat, item.Name, f.mtimefs, f.SyncOwnership)
 	if err != nil {
-		return errors.Wrap(err, "comparing item on disk to db")
+		return fmt.Errorf("comparing item on disk to db: %w", err)
 	}
 
 	if !statItem.IsEquivalentOptional(item, protocol.FileInfoComparison{
@@ -2122,10 +2123,10 @@ func (f *sendReceiveFolder) copyOwnershipFromParent(path string) error {
 
 	info, err := f.mtimefs.Lstat(filepath.Dir(path))
 	if err != nil {
-		return errors.Wrap(err, "copy owner from parent")
+		return fmt.Errorf("copy owner from parent: %w", err)
 	}
 	if err := f.mtimefs.Lchown(path, strconv.Itoa(info.Owner()), strconv.Itoa(info.Group())); err != nil {
-		return errors.Wrap(err, "copy owner from parent")
+		return fmt.Errorf("copy owner from parent: %w", err)
 	}
 	return nil
 }

+ 5 - 5
lib/model/model.go

@@ -13,6 +13,7 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -24,7 +25,6 @@ import (
 	stdsync "sync"
 	"time"
 
-	"github.com/pkg/errors"
 	"github.com/thejerf/suture/v4"
 
 	"github.com/syncthing/syncthing/lib/build"
@@ -1127,10 +1127,10 @@ func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []prot
 
 	if cfg, ok := m.cfg.Folder(folder); !ok || !cfg.SharedWith(deviceID) {
 		l.Infof("%v for unexpected folder ID %q sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", op, folder, deviceID)
-		return errors.Wrap(ErrFolderMissing, folder)
+		return fmt.Errorf("%s: %w", folder, ErrFolderMissing)
 	} else if cfg.Paused {
 		l.Debugf("%v for paused folder (ID %q) sent from device %q.", op, folder, deviceID)
-		return errors.Wrap(ErrFolderPaused, folder)
+		return fmt.Errorf("%s: %w", folder, ErrFolderPaused)
 	}
 
 	m.pmut.RLock()
@@ -1142,7 +1142,7 @@ func (m *model) handleIndex(deviceID protocol.DeviceID, folder string, fs []prot
 		// connection
 		m.evLogger.Log(events.Failure, "index sender does not exist for connection on which indexes were received")
 		l.Debugf("%v for folder (ID %q) sent from device %q: missing index handler", op, folder, deviceID)
-		return errors.Wrap(errors.New("index handler missing"), folder)
+		return fmt.Errorf("index handler missing: %s", folder)
 	}
 
 	return indexHandler.ReceiveIndex(folder, fs, update, op)
@@ -2123,7 +2123,7 @@ func (m *model) setIgnores(cfg config.FolderConfiguration, content []string) err
 	err := cfg.CheckPath()
 	if err == config.ErrPathMissing {
 		if err = cfg.CreateRoot(); err != nil {
-			return errors.Wrap(err, "failed to create folder root")
+			return fmt.Errorf("failed to create folder root: %w", err)
 		}
 		err = cfg.CheckPath()
 	}

+ 1 - 1
lib/model/model_test.go

@@ -10,6 +10,7 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"math/rand"
@@ -24,7 +25,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/pkg/errors"
 	"github.com/syncthing/syncthing/lib/build"
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/db"

+ 3 - 4
lib/model/sharedpullerstate.go

@@ -8,11 +8,10 @@ package model
 
 import (
 	"encoding/binary"
+	"fmt"
 	"io"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/osutil"
 	"github.com/syncthing/syncthing/lib/protocol"
@@ -177,12 +176,12 @@ func (s *sharedPullerState) tempFileInWritableDir(_ string) error {
 		// what the umask dictates.
 
 		if err := s.fs.Chmod(s.tempName, mode); err != nil {
-			return errors.Wrap(err, "setting perms on temp file")
+			return fmt.Errorf("setting perms on temp file: %w", err)
 		}
 	}
 	fd, err := s.fs.OpenFile(s.tempName, flags, mode)
 	if err != nil {
-		return errors.Wrap(err, "opening temp file")
+		return fmt.Errorf("opening temp file: %w", err)
 	}
 
 	// Hide the temporary file

+ 1 - 1
lib/model/util.go

@@ -7,13 +7,13 @@
 package model
 
 import (
+	"errors"
 	"fmt"
 	"path/filepath"
 	"strings"
 	"sync"
 	"time"
 
-	"github.com/pkg/errors"
 	"github.com/syncthing/syncthing/lib/events"
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/ur"

+ 8 - 7
lib/osutil/lowprio_linux.go

@@ -10,10 +10,9 @@
 package osutil
 
 import (
+	"fmt"
 	"os"
 	"syscall"
-
-	"github.com/pkg/errors"
 )
 
 const ioprioClassShift = 13
@@ -82,20 +81,22 @@ func SetLowPriority() error {
 	// so we need this workaround...
 	if pgid, err := syscall.Getpgid(pidSelf); err != nil {
 		// This error really shouldn't happen
-		return errors.Wrap(err, "get process group")
+		return fmt.Errorf("get process group: %w", err)
 	} else if pgid != os.Getpid() {
 		// We are not process group leader. Elevate!
 		if err := syscall.Setpgid(pidSelf, 0); err != nil {
-			return errors.Wrap(err, "set process group")
+			return fmt.Errorf("set process group: %w", err)
 		}
 	}
 
 	if err := syscall.Setpriority(syscall.PRIO_PGRP, pidSelf, wantNiceLevel); err != nil {
-		return errors.Wrap(err, "set niceness")
+		return fmt.Errorf("set niceness: %w", err)
 	}
 
 	// Best effort, somewhere to the end of the scale (0 through 7 being the
 	// range).
-	err := ioprioSet(ioprioClassBE, 5)
-	return errors.Wrap(err, "set I/O priority") // wraps nil as nil
+	if err := ioprioSet(ioprioClassBE, 5); err != nil {
+		return fmt.Errorf("set I/O priority: %w", err)
+	}
+	return nil
 }

+ 5 - 4
lib/osutil/lowprio_unix.go

@@ -10,9 +10,8 @@
 package osutil
 
 import (
+	"fmt"
 	"syscall"
-
-	"github.com/pkg/errors"
 )
 
 // SetLowPriority lowers the process CPU scheduling priority, and possibly
@@ -30,6 +29,8 @@ func SetLowPriority() error {
 		return nil
 	}
 
-	err := syscall.Setpriority(syscall.PRIO_PROCESS, pidSelf, wantNiceLevel)
-	return errors.Wrap(err, "set niceness") // wraps nil as nil
+	if err := syscall.Setpriority(syscall.PRIO_PROCESS, pidSelf, wantNiceLevel); err != nil {
+		return fmt.Errorf("set niceness: %w", err)
+	}
+	return nil
 }

+ 7 - 4
lib/osutil/lowprio_windows.go

@@ -7,7 +7,8 @@
 package osutil
 
 import (
-	"github.com/pkg/errors"
+	"fmt"
+
 	"golang.org/x/sys/windows"
 )
 
@@ -16,10 +17,12 @@ import (
 func SetLowPriority() error {
 	handle, err := windows.GetCurrentProcess()
 	if err != nil {
-		return errors.Wrap(err, "get process handle")
+		return fmt.Errorf("get process handle: %w", err)
 	}
 	defer windows.CloseHandle(handle)
 
-	err = windows.SetPriorityClass(handle, windows.BELOW_NORMAL_PRIORITY_CLASS)
-	return errors.Wrap(err, "set priority class") // wraps nil as nil
+	if err := windows.SetPriorityClass(handle, windows.BELOW_NORMAL_PRIORITY_CLASS); err != nil {
+		return fmt.Errorf("set priority class: %w", err)
+	}
+	return nil
 }

+ 14 - 14
lib/protocol/protocol.go

@@ -15,6 +15,7 @@ import (
 	"context"
 	"crypto/sha256"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -24,7 +25,6 @@ import (
 	"time"
 
 	lz4 "github.com/pierrec/lz4/v4"
-	"github.com/pkg/errors"
 )
 
 const (
@@ -499,7 +499,7 @@ func (c *rawConnection) readMessageAfterHeader(hdr Header, fourByteBuf []byte) (
 	// First comes a 4 byte message length
 
 	if _, err := io.ReadFull(c.cr, fourByteBuf[:4]); err != nil {
-		return nil, errors.Wrap(err, "reading message length")
+		return nil, fmt.Errorf("reading message length: %w", err)
 	}
 	msgLen := int32(binary.BigEndian.Uint32(fourByteBuf))
 	if msgLen < 0 {
@@ -513,7 +513,7 @@ func (c *rawConnection) readMessageAfterHeader(hdr Header, fourByteBuf []byte) (
 	buf := BufferPool.Get(int(msgLen))
 	if _, err := io.ReadFull(c.cr, buf); err != nil {
 		BufferPool.Put(buf)
-		return nil, errors.Wrap(err, "reading message")
+		return nil, fmt.Errorf("reading message: %w", err)
 	}
 
 	// ... which might be compressed
@@ -526,7 +526,7 @@ func (c *rawConnection) readMessageAfterHeader(hdr Header, fourByteBuf []byte) (
 		decomp, err := lz4Decompress(buf)
 		BufferPool.Put(buf)
 		if err != nil {
-			return nil, errors.Wrap(err, "decompressing message")
+			return nil, fmt.Errorf("decompressing message: %w", err)
 		}
 		buf = decomp
 
@@ -543,7 +543,7 @@ func (c *rawConnection) readMessageAfterHeader(hdr Header, fourByteBuf []byte) (
 	}
 	if err := msg.Unmarshal(buf); err != nil {
 		BufferPool.Put(buf)
-		return nil, errors.Wrap(err, "unmarshalling message")
+		return nil, fmt.Errorf("unmarshalling message: %w", err)
 	}
 	BufferPool.Put(buf)
 
@@ -554,7 +554,7 @@ func (c *rawConnection) readHeader(fourByteBuf []byte) (Header, error) {
 	// First comes a 2 byte header length
 
 	if _, err := io.ReadFull(c.cr, fourByteBuf[:2]); err != nil {
-		return Header{}, errors.Wrap(err, "reading length")
+		return Header{}, fmt.Errorf("reading length: %w", err)
 	}
 	hdrLen := int16(binary.BigEndian.Uint16(fourByteBuf))
 	if hdrLen < 0 {
@@ -566,14 +566,14 @@ func (c *rawConnection) readHeader(fourByteBuf []byte) (Header, error) {
 	buf := BufferPool.Get(int(hdrLen))
 	if _, err := io.ReadFull(c.cr, buf); err != nil {
 		BufferPool.Put(buf)
-		return Header{}, errors.Wrap(err, "reading header")
+		return Header{}, fmt.Errorf("reading header: %w", err)
 	}
 
 	var hdr Header
 	err := hdr.Unmarshal(buf)
 	BufferPool.Put(buf)
 	if err != nil {
-		return Header{}, errors.Wrap(err, "unmarshalling header")
+		return Header{}, fmt.Errorf("unmarshalling header: %w", err)
 	}
 
 	return hdr, nil
@@ -594,7 +594,7 @@ func (c *rawConnection) handleIndexUpdate(im IndexUpdate) error {
 func checkIndexConsistency(fs []FileInfo) error {
 	for _, f := range fs {
 		if err := checkFileInfoConsistency(f); err != nil {
-			return errors.Wrapf(err, "%q", f.Name)
+			return fmt.Errorf("%q: %w", f.Name, err)
 		}
 	}
 	return nil
@@ -757,7 +757,7 @@ func (c *rawConnection) writeMessage(msg message) error {
 
 	// Message
 	if _, err := msg.MarshalTo(buf[2+hdrSize+4:]); err != nil {
-		return errors.Wrap(err, "marshalling message")
+		return fmt.Errorf("marshalling message: %w", err)
 	}
 
 	if c.shouldCompressMessage(msg) {
@@ -771,7 +771,7 @@ func (c *rawConnection) writeMessage(msg message) error {
 	binary.BigEndian.PutUint16(buf, uint16(hdrSize))
 	// Header
 	if _, err := hdr.MarshalTo(buf[2:]); err != nil {
-		return errors.Wrap(err, "marshalling header")
+		return fmt.Errorf("marshalling header: %w", err)
 	}
 	// Message length
 	binary.BigEndian.PutUint32(buf[2+hdrSize:], uint32(size))
@@ -780,7 +780,7 @@ func (c *rawConnection) writeMessage(msg message) error {
 
 	l.Debugf("wrote %d bytes on the wire (2 bytes length, %d bytes header, 4 bytes message length, %d bytes message), err=%v", n, hdrSize, size, err)
 	if err != nil {
-		return errors.Wrap(err, "writing message")
+		return fmt.Errorf("writing message: %w", err)
 	}
 	return nil
 }
@@ -817,7 +817,7 @@ func (c *rawConnection) writeCompressedMessage(msg message, marshaled []byte) (o
 	binary.BigEndian.PutUint16(buf, uint16(hdrSize))
 	// Header
 	if _, err := hdr.MarshalTo(buf[2:]); err != nil {
-		return true, errors.Wrap(err, "marshalling header")
+		return true, fmt.Errorf("marshalling header: %w", err)
 	}
 	// Message length
 	binary.BigEndian.PutUint32(buf[2+hdrSize:], uint32(compressedSize))
@@ -825,7 +825,7 @@ func (c *rawConnection) writeCompressedMessage(msg message, marshaled []byte) (o
 	n, err := c.cw.Write(buf[:totSize])
 	l.Debugf("wrote %d bytes on the wire (2 bytes length, %d bytes header, 4 bytes message length, %d bytes message (%d uncompressed)), err=%v", n, hdrSize, compressedSize, len(marshaled), err)
 	if err != nil {
-		return true, errors.Wrap(err, "writing message")
+		return true, fmt.Errorf("writing message: %w", err)
 	}
 	return true, nil
 }

+ 2 - 3
lib/relay/client/static.go

@@ -5,13 +5,12 @@ package client
 import (
 	"context"
 	"crypto/tls"
+	"errors"
 	"fmt"
 	"net"
 	"net/url"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/dialer"
 	syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/relay/protocol"
@@ -213,7 +212,7 @@ func performHandshakeAndValidation(conn *tls.Conn, uri *url.URL) error {
 	if relayIDs != "" {
 		relayID, err := syncthingprotocol.DeviceIDFromString(relayIDs)
 		if err != nil {
-			return errors.Wrap(err, "relay address contains invalid verification id")
+			return fmt.Errorf("relay address contains invalid verification id: %w", err)
 		}
 
 		certs := cs.PeerCertificates

+ 5 - 6
lib/syncthing/utils.go

@@ -8,12 +8,11 @@ package syncthing
 
 import (
 	"crypto/tls"
+	"errors"
 	"fmt"
 	"io"
 	"os"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/db/backend"
 	"github.com/syncthing/syncthing/lib/events"
@@ -93,17 +92,17 @@ func LoadConfigAtStartup(path string, cert tls.Certificate, evLogger events.Logg
 	if fs.IsNotExist(err) {
 		cfg, err = DefaultConfig(path, myID, evLogger, noDefaultFolder, skipPortProbing)
 		if err != nil {
-			return nil, errors.Wrap(err, "failed to generate default config")
+			return nil, fmt.Errorf("failed to generate default config: %w", err)
 		}
 		err = cfg.Save()
 		if err != nil {
-			return nil, errors.Wrap(err, "failed to save default config")
+			return nil, fmt.Errorf("failed to save default config: %w", err)
 		}
 		l.Infof("Default config saved. Edit %s to taste (with Syncthing stopped) or use the GUI", cfg.ConfigPath())
 	} else if err == io.EOF {
 		return nil, errors.New("failed to load config: unexpected end of file. Truncated or empty configuration?")
 	} else if err != nil {
-		return nil, errors.Wrap(err, "failed to load config")
+		return nil, fmt.Errorf("failed to load config: %w", err)
 	}
 
 	if originalVersion != config.CurrentVersion {
@@ -115,7 +114,7 @@ func LoadConfigAtStartup(path string, cert tls.Certificate, evLogger events.Logg
 		}
 		err = archiveAndSaveConfig(cfg, originalVersion)
 		if err != nil {
-			return nil, errors.Wrap(err, "config archive")
+			return nil, fmt.Errorf("config archive: %w", err)
 		}
 	}
 

+ 11 - 11
lib/tlsutil/tlsutil.go

@@ -14,13 +14,13 @@ import (
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/pem"
+	"errors"
+	"fmt"
 	"math/big"
 	"net"
 	"os"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/rand"
 )
 
@@ -90,7 +90,7 @@ func SecureDefaultWithTLS12() *tls.Config {
 func generateCertificate(commonName string, lifetimeDays int) (*pem.Block, *pem.Block, error) {
 	priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
 	if err != nil {
-		return nil, nil, errors.Wrap(err, "generate key")
+		return nil, nil, fmt.Errorf("generate key: %w", err)
 	}
 
 	notBefore := time.Now().Truncate(24 * time.Hour)
@@ -117,13 +117,13 @@ func generateCertificate(commonName string, lifetimeDays int) (*pem.Block, *pem.
 
 	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
 	if err != nil {
-		return nil, nil, errors.Wrap(err, "create cert")
+		return nil, nil, fmt.Errorf("create cert: %w", err)
 	}
 
 	certBlock := &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}
 	keyBlock, err := pemBlockForKey(priv)
 	if err != nil {
-		return nil, nil, errors.Wrap(err, "save key")
+		return nil, nil, fmt.Errorf("save key: %w", err)
 	}
 
 	return certBlock, keyBlock, nil
@@ -138,24 +138,24 @@ func NewCertificate(certFile, keyFile string, commonName string, lifetimeDays in
 
 	certOut, err := os.Create(certFile)
 	if err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save cert")
+		return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
 	}
 	if err = pem.Encode(certOut, certBlock); err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save cert")
+		return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
 	}
 	if err = certOut.Close(); err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save cert")
+		return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
 	}
 
 	keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
 	if err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save key")
+		return tls.Certificate{}, fmt.Errorf("save key: %w", err)
 	}
 	if err = pem.Encode(keyOut, keyBlock); err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save key")
+		return tls.Certificate{}, fmt.Errorf("save key: %w", err)
 	}
 	if err = keyOut.Close(); err != nil {
-		return tls.Certificate{}, errors.Wrap(err, "save key")
+		return tls.Certificate{}, fmt.Errorf("save key: %w", err)
 	}
 
 	return tls.X509KeyPair(pem.EncodeToMemory(certBlock), pem.EncodeToMemory(keyBlock))

+ 1 - 2
lib/upnp/upnp.go

@@ -37,6 +37,7 @@ import (
 	"bytes"
 	"context"
 	"encoding/xml"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -46,8 +47,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/build"
 	"github.com/syncthing/syncthing/lib/dialer"
 	"github.com/syncthing/syncthing/lib/nat"

+ 4 - 4
lib/versioner/util.go

@@ -8,14 +8,14 @@ package versioner
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"path/filepath"
 	"regexp"
 	"sort"
 	"strings"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/syncthing/syncthing/lib/config"
 	"github.com/syncthing/syncthing/lib/fs"
 	"github.com/syncthing/syncthing/lib/osutil"
@@ -200,11 +200,11 @@ func restoreFile(method fs.CopyRangeMethod, src, dst fs.Filesystem, filePath str
 		case info.IsSymlink():
 			// Remove existing symlinks (as we don't want to archive them)
 			if err := dst.Remove(filePath); err != nil {
-				return errors.Wrap(err, "removing existing symlink")
+				return fmt.Errorf("removing existing symlink: %w", err)
 			}
 		case info.IsRegular():
 			if err := archiveFile(method, dst, src, filePath, tagger); err != nil {
-				return errors.Wrap(err, "archiving existing file")
+				return fmt.Errorf("archiving existing file: %w", err)
 			}
 		default:
 			panic("bug: unknown item type")