mirror of
https://github.com/syncthing/syncthing.git
synced 2025-12-24 06:28:10 -05:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c00c6b3957 | ||
|
|
cc39341eb9 | ||
|
|
bf7f82f7b2 | ||
|
|
eb857dbc45 | ||
|
|
e7620e951d | ||
|
|
286a25ae49 | ||
|
|
ae70046b49 | ||
|
|
c366933416 | ||
|
|
6a9716e8a1 | ||
|
|
b84ee4d240 | ||
|
|
8a1e54d58a | ||
|
|
3e032c4da6 |
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
cmd/syncthing/cli/pending.go
Normal file
29
cmd/syncthing/cli/pending.go
Normal 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")),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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
go.mod
2
go.mod
@@ -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
|
||||
|
||||
4
go.sum
4
go.sum
@@ -242,8 +242,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucas-clemente/quic-go v0.22.0/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q=
|
||||
github.com/lucas-clemente/quic-go v0.23.0 h1:5vFnKtZ6nHDFsc/F3uuiF4T3y/AXaQdxjUqiVw26GZE=
|
||||
github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g=
|
||||
github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
|
||||
@@ -428,6 +428,13 @@
|
||||
<div ng-if="model[folder.id].ignorePatterns">
|
||||
<a href="" ng-click="editFolderExisting(folder, '#folder-ignores')"><i class="small" translate>Reduced by ignore patterns</i></a>
|
||||
</div>
|
||||
<div ng-if="folder.ignoreDelete">
|
||||
<i class="small">
|
||||
<span translate style="white-space: normal;">Altered by ignoring deletes.</span>
|
||||
<br>
|
||||
<a href="https://docs.syncthing.net/advanced/folder-ignoredelete" target="_blank"><span class="fas fa-question-circle"></span> <span translate>Help</span></a>
|
||||
</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="model[folder.id].needTotalItems > 0">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,25 +47,13 @@ func getHomeDir() (string, error) {
|
||||
return os.UserHomeDir()
|
||||
}
|
||||
|
||||
var (
|
||||
windowsDisallowedCharacters = string([]rune{
|
||||
'<', '>', ':', '"', '|', '?', '*',
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
31,
|
||||
})
|
||||
windowsDisallowedNames = []string{"CON", "PRN", "AUX", "NUL",
|
||||
"COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
}
|
||||
)
|
||||
const windowsDisallowedCharacters = (`<>:"|?*` +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f")
|
||||
|
||||
func WindowsInvalidFilename(name string) error {
|
||||
// None of the path components should end in space or period, or be a
|
||||
// reserved name. COM0 and LPT0 are missing from the Microsoft docs,
|
||||
// but Windows Explorer treats them as invalid too.
|
||||
// (https://docs.microsoft.com/windows/win32/fileio/naming-a-file)
|
||||
// reserved name.
|
||||
for _, part := range strings.Split(name, `\`) {
|
||||
if len(part) == 0 {
|
||||
continue
|
||||
@@ -110,7 +98,7 @@ func WindowsInvalidFilename(name string) error {
|
||||
func SanitizePath(path string) string {
|
||||
var b strings.Builder
|
||||
|
||||
disallowed := `<>:"'/\|?*[]{};:!@$%&^#` + windowsDisallowedCharacters
|
||||
const disallowed = `'/\[]{};:!@$%&^#` + windowsDisallowedCharacters
|
||||
prev := ' '
|
||||
for _, c := range path {
|
||||
if !unicode.IsPrint(c) || c == unicode.ReplacementChar ||
|
||||
@@ -132,15 +120,27 @@ func SanitizePath(path string) string {
|
||||
}
|
||||
|
||||
func windowsIsReserved(part string) bool {
|
||||
upperCased := strings.ToUpper(part)
|
||||
for _, disallowed := range windowsDisallowedNames {
|
||||
if upperCased == disallowed {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(upperCased, disallowed+".") {
|
||||
// nul.txt.jpg is also disallowed
|
||||
return true
|
||||
}
|
||||
// nul.txt.jpg is also disallowed.
|
||||
dot := strings.IndexByte(part, '.')
|
||||
if dot != -1 {
|
||||
part = part[:dot]
|
||||
}
|
||||
|
||||
// Check length to skip allocating ToUpper.
|
||||
if len(part) != 3 && len(part) != 4 {
|
||||
return false
|
||||
}
|
||||
|
||||
// COM0 and LPT0 are missing from the Microsoft docs,
|
||||
// but Windows Explorer treats them as invalid too.
|
||||
// (https://docs.microsoft.com/windows/win32/fileio/naming-a-file)
|
||||
switch strings.ToUpper(part) {
|
||||
case "CON", "PRN", "AUX", "NUL",
|
||||
"COM0", "COM1", "COM2", "COM3", "COM4",
|
||||
"COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4",
|
||||
"LPT5", "LPT6", "LPT7", "LPT8", "LPT9":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -117,3 +117,15 @@ func TestSanitizePathFuzz(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkWindowsInvalidFilename(b *testing.B, name string) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
WindowsInvalidFilename(name)
|
||||
}
|
||||
}
|
||||
func BenchmarkWindowsInvalidFilenameValid(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "License.txt.gz")
|
||||
}
|
||||
func BenchmarkWindowsInvalidFilenameNUL(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "nul.txt.gz")
|
||||
}
|
||||
|
||||
@@ -26,20 +26,19 @@ func newDeviceActivity() *deviceActivity {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *deviceActivity) leastBusy(availability []Availability) (Availability, bool) {
|
||||
// Returns the index of the least busy device, or -1 if all are too busy.
|
||||
func (m *deviceActivity) leastBusy(availability []Availability) int {
|
||||
m.mut.Lock()
|
||||
low := 2<<30 - 1
|
||||
found := false
|
||||
var selected Availability
|
||||
for _, info := range availability {
|
||||
if usage := m.act[info.ID]; usage < low {
|
||||
best := -1
|
||||
for i := range availability {
|
||||
if usage := m.act[availability[i].ID]; usage < low {
|
||||
low = usage
|
||||
selected = info
|
||||
found = true
|
||||
best = i
|
||||
}
|
||||
}
|
||||
m.mut.Unlock()
|
||||
return selected, found
|
||||
return best
|
||||
}
|
||||
|
||||
func (m *deviceActivity) using(availability Availability) {
|
||||
|
||||
@@ -19,42 +19,42 @@ func TestDeviceActivity(t *testing.T) {
|
||||
devices := []Availability{n0, n1, n2}
|
||||
na := newDeviceActivity()
|
||||
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should still be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
|
||||
lb, _ := na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
lb := na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
lb, _ = na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n2 {
|
||||
lb = na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 2 {
|
||||
t.Errorf("Least busy device should be n2 (%v) not %v", n2, lb)
|
||||
}
|
||||
|
||||
lb, _ = na.leastBusy(devices)
|
||||
na.using(lb)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
lb = na.leastBusy(devices)
|
||||
na.using(devices[lb])
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
|
||||
na.done(n1)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
|
||||
na.done(n2)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n1 {
|
||||
if lb := na.leastBusy(devices); lb != 1 {
|
||||
t.Errorf("Least busy device should still be n1 (%v) not %v", n1, lb)
|
||||
}
|
||||
|
||||
na.done(n0)
|
||||
if lb, ok := na.leastBusy(devices); !ok || lb != n0 {
|
||||
if lb := na.leastBusy(devices); lb != 0 {
|
||||
t.Errorf("Least busy device should be n0 (%v) not %v", n0, lb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -19,11 +19,7 @@ import (
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
)
|
||||
|
||||
type clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
var defaultClock clock = (*standardClock)(nil)
|
||||
var timeNow = time.Now
|
||||
|
||||
type Mutex interface {
|
||||
Lock()
|
||||
@@ -86,7 +82,7 @@ func (h holder) String() string {
|
||||
if h.at == "" {
|
||||
return "not held"
|
||||
}
|
||||
return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, defaultClock.Now().Sub(h.time))
|
||||
return fmt.Sprintf("at %s goid: %d for %s", h.at, h.goid, timeNow().Sub(h.time))
|
||||
}
|
||||
|
||||
type loggedMutex struct {
|
||||
@@ -101,7 +97,7 @@ func (m *loggedMutex) Lock() {
|
||||
|
||||
func (m *loggedMutex) Unlock() {
|
||||
currentHolder := m.holder.Load().(holder)
|
||||
duration := defaultClock.Now().Sub(currentHolder.time)
|
||||
duration := timeNow().Sub(currentHolder.time)
|
||||
if duration >= threshold {
|
||||
l.Debugf("Mutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
|
||||
}
|
||||
@@ -125,7 +121,7 @@ type loggedRWMutex struct {
|
||||
}
|
||||
|
||||
func (m *loggedRWMutex) Lock() {
|
||||
start := defaultClock.Now()
|
||||
start := timeNow()
|
||||
|
||||
atomic.StoreInt32(&m.logUnlockers, 1)
|
||||
m.RWMutex.Lock()
|
||||
@@ -153,7 +149,7 @@ func (m *loggedRWMutex) Lock() {
|
||||
|
||||
func (m *loggedRWMutex) Unlock() {
|
||||
currentHolder := m.holder.Load().(holder)
|
||||
duration := defaultClock.Now().Sub(currentHolder.time)
|
||||
duration := timeNow().Sub(currentHolder.time)
|
||||
if duration >= threshold {
|
||||
l.Debugf("RWMutex held for %v. Locked at %s unlocked at %s", duration, currentHolder.at, getHolder().at)
|
||||
}
|
||||
@@ -205,9 +201,9 @@ type loggedWaitGroup struct {
|
||||
}
|
||||
|
||||
func (wg *loggedWaitGroup) Wait() {
|
||||
start := defaultClock.Now()
|
||||
start := timeNow()
|
||||
wg.WaitGroup.Wait()
|
||||
duration := defaultClock.Now().Sub(start)
|
||||
duration := timeNow().Sub(start)
|
||||
if duration >= threshold {
|
||||
l.Debugf("WaitGroup took %v at %s", duration, getHolder())
|
||||
}
|
||||
@@ -219,7 +215,7 @@ func getHolder() holder {
|
||||
return holder{
|
||||
at: fmt.Sprintf("%s:%d", file, line),
|
||||
goid: goid(),
|
||||
time: defaultClock.Now(),
|
||||
time: timeNow(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,9 +296,3 @@ func (w *TimeoutCondWaiter) Wait() bool {
|
||||
func (w *TimeoutCondWaiter) Stop() {
|
||||
w.timer.Stop()
|
||||
}
|
||||
|
||||
type standardClock struct{}
|
||||
|
||||
func (*standardClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ func TestTypes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMutex(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
@@ -97,10 +97,10 @@ func TestMutex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRWMutex(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
@@ -170,10 +170,10 @@ func TestRWMutex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWaitGroup(t *testing.T) {
|
||||
oldClock := defaultClock
|
||||
oldClock := timeNow
|
||||
clock := newTestClock()
|
||||
defaultClock = clock
|
||||
defer func() { defaultClock = oldClock }()
|
||||
timeNow = clock.Now
|
||||
defer func() { timeNow = oldClock }()
|
||||
|
||||
debug = true
|
||||
l.SetDebug("sync", true)
|
||||
|
||||
@@ -38,7 +38,11 @@ func (s *auditService) Serve(ctx context.Context) error {
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev := <-sub.C():
|
||||
case ev, ok := <-sub.C():
|
||||
if !ok {
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
enc.Encode(ev)
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -391,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()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user