Compare commits

...

19 Commits

Author SHA1 Message Date
Syncthing Release Automation
81c99e07db chore(gui, man, authors): update docs, translations, and contributors 2025-10-27 03:59:48 +00:00
André Colomb
5279330c1d chore(gui): add Azerbaijani (az) and Kurdish (ckb) l10n templates. (#10442)
Based on user requests from Weblate:

* `@miryusifrahimov` for Azerbaijani
* `@halbast` für Kurdish (Central)

Both seem to be legit and have previously contributed translations on
Weblate.

Signed-off-by: André Colomb <src@andre.colomb.de>
2025-10-26 17:55:03 +01:00
Jakob Borg
194b59b3ed chore: job for adding org members 2025-10-24 08:10:30 +02:00
Jakob Borg
8e796ddb94 chore: linter: errorlint
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
7c9d06b4d2 chore: linter: embeddedstructfieldcheck
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
df8d8c276e chore: linter: staticcheck
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
98cf5872e9 chore: linter: perfsprint
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
c883f49a24 chore: linter: usestdlibvars
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
d84280107c chore: linter: canonicalheader
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
d97fd638bc chore: linter: dupword
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
a1069a0d70 chore: linter: intrange
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
465804161b chore: linter: staticcheck
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Jakob Borg
d08f483811 chore: linter: unused
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-10-23 22:48:54 +02:00
Marcus B Spencer
655b4568c1 fix(fs): only apply case option to fakefs in stress test (#10440)
Fixes a regression introduced in #10439, mentioned in [a comment](https://github.com/syncthing/syncthing/pull/10439#issuecomment-3436515824) made by @imsodin:

> That might not be the greatest way to do this, but nevertheless it afaik means that the benchmarks now do case checking once when it shouldn't happen at all, and twice otherwise.

Benchmarks do approximately as well as before the regression, and I think most of them are random chance:

```
                                             │ ../oldold.txt │             ../new.txt             │
                                             │    sec/op     │   sec/op     vs base               │
WalkCaseFakeFS100k/rawfs-8                       654.6m ± 1%   652.6m ± 3%       ~ (p=0.971 n=10)
WalkCaseFakeFS100k/casefs-8                       1.049 ± 2%    1.071 ± 3%       ~ (p=0.190 n=10)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8      1.053 ± 3%    1.081 ± 5%       ~ (p=0.165 n=10)
geomean                                          897.7m        910.8m       +1.46%

                                             │ ../oldold.txt │              ../new.txt               │
                                             │    B/entry    │   B/entry     vs base                 │
WalkCaseFakeFS100k/rawfs-8                      1.274Ki ± 0%   1.274Ki ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                     1.771Ki ± 0%   1.771Ki ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8    1.772Ki ± 0%   1.772Ki ± 0%       ~ (p=1.000 n=10) ¹
geomean                                         1.587Ki        1.587Ki       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt  │               ../new.txt                │
                                             │ DirNames/entry │ DirNames/entry  vs base                 │
WalkCaseFakeFS100k/rawfs-8                        512.5m ± 0%      512.5m ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                        1.025 ± 0%       1.025 ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8       1.025 ± 0%       1.025 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                           813.5m           813.5m       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt │              ../new.txt              │
                                             │  DirNames/op  │ DirNames/op  vs base                 │
WalkCaseFakeFS100k/rawfs-8                       51.25k ± 0%   51.25k ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                      102.5k ± 0%   102.5k ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8     102.5k ± 0%   102.5k ± 0%       ~ (p=1.000 n=10) ¹
geomean                                          81.35k        81.35k       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt │              ../new.txt              │
                                             │  Lstat/entry  │ Lstat/entry  vs base                 │
WalkCaseFakeFS100k/rawfs-8                        5.535 ± 0%    5.535 ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                       5.535 ± 0%    5.535 ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8      5.540 ± 0%    5.540 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                           5.537         5.537       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt │              ../new.txt              │
                                             │   Lstat/op    │  Lstat/op    vs base                 │
WalkCaseFakeFS100k/rawfs-8                       553.5k ± 0%   553.5k ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                      553.5k ± 0%   553.5k ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8     554.0k ± 0%   554.0k ± 0%       ~ (p=1.000 n=10) ¹
geomean                                          553.7k        553.7k       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt │              ../new.txt               │
                                             │ allocs/entry  │ allocs/entry  vs base                 │
WalkCaseFakeFS100k/rawfs-8                        19.00 ± 0%     19.00 ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-8                       35.35 ± 0%     35.35 ± 0%       ~ (p=1.000 n=10) ¹
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8      35.38 ± 0%     35.38 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                           28.75          28.75       +0.00%
¹ all samples are equal

                                             │ ../oldold.txt │             ../new.txt             │
                                             │   sec/entry   │  sec/entry   vs base               │
WalkCaseFakeFS100k/rawfs-8                       4.328µ ± 1%   4.315µ ± 3%       ~ (p=0.971 n=10)
WalkCaseFakeFS100k/casefs-8                      6.936µ ± 2%   7.082µ ± 3%       ~ (p=0.171 n=10)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8     6.965µ ± 3%   7.147µ ± 5%       ~ (p=0.165 n=10)
geomean                                          5.935µ        6.022µ       +1.46%

                                             │ ../oldold.txt │             ../new.txt              │
                                             │     B/op      │     B/op      vs base               │
WalkCaseFakeFS100k/rawfs-8                      188.3Mi ± 0%   188.3Mi ± 0%  -0.00% (p=0.006 n=10)
WalkCaseFakeFS100k/casefs-8                     261.5Mi ± 0%   261.5Mi ± 0%       ~ (p=0.142 n=10)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8    261.7Mi ± 0%   261.7Mi ± 0%       ~ (p=0.315 n=10)
geomean                                         234.4Mi        234.4Mi       -0.00%

                                             │ ../oldold.txt │             ../new.txt             │
                                             │   allocs/op   │  allocs/op   vs base               │
WalkCaseFakeFS100k/rawfs-8                       2.873M ± 0%   2.873M ± 0%  -0.00% (p=0.026 n=10)
WalkCaseFakeFS100k/casefs-8                      5.346M ± 0%   5.346M ± 0%       ~ (p=0.136 n=10)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8     5.351M ± 0%   5.351M ± 0%       ~ (p=0.305 n=10)
geomean                                          4.348M        4.348M       -0.00%
```

Signed-off-by: Marcus B Spencer <marcus@marcusspencer.us>
2025-10-23 13:12:03 -05:00
Marcus B Spencer
c6a887865f fix(fs): apply case option to fakefs in casefs tests (#10439)
Required for the casefs tests/benchmarks to test the casefs.

Benchmarks do significantly worse (as expected).

```
                                             │ ../old.txt  │             ../new.txt             │
                                             │   sec/op    │   sec/op     vs base               │
WalkCaseFakeFS100k/rawfs-8                     626.5m ± 5%   993.4m ± 1%  +58.56% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                     1.011 ± 1%    1.425 ± 1%  +40.94% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8    1.014 ± 2%    1.439 ± 1%  +41.97% (p=0.002 n=6)
geomean                                        862.9m         1.268       +46.94%

                                             │  ../old.txt  │             ../new.txt              │
                                             │   B/entry    │   B/entry     vs base               │
WalkCaseFakeFS100k/rawfs-8                     1.274Ki ± 0%   1.766Ki ± 0%  +38.54% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                    1.771Ki ± 0%   2.354Ki ± 0%  +32.98% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8   1.772Ki ± 0%   2.356Ki ± 0%  +32.95% (p=0.002 n=6)
geomean                                        1.587Ki        2.140Ki       +34.80%

                                             │   ../old.txt   │               ../new.txt               │
                                             │ DirNames/entry │ DirNames/entry  vs base                │
WalkCaseFakeFS100k/rawfs-8                        512.5m ± 0%     1025.0m ± 0%  +100.00% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                        1.025 ± 0%       1.537 ± 0%   +49.95% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8       1.025 ± 0%       1.537 ± 0%   +49.95% (p=0.002 n=6)
geomean                                           813.5m            1.343        +65.06%

                                             │ ../old.txt  │              ../new.txt              │
                                             │ DirNames/op │ DirNames/op   vs base                │
WalkCaseFakeFS100k/rawfs-8                     51.25k ± 0%   102.49k ± 0%  +100.00% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                    102.5k ± 0%    153.7k ± 0%   +50.00% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8   102.5k ± 0%    153.7k ± 0%   +50.00% (p=0.002 n=6)
geomean                                        81.35k         134.3k        +65.10%

                                             │  ../old.txt  │             ../new.txt              │
                                             │ allocs/entry │ allocs/entry  vs base               │
WalkCaseFakeFS100k/rawfs-8                       19.00 ± 0%     35.35 ± 0%  +86.05% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                      35.35 ± 0%     54.40 ± 0%  +53.89% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8     35.38 ± 0%     54.46 ± 0%  +53.93% (p=0.002 n=6)
geomean                                          28.75          47.14       +63.95%

                                             │ ../old.txt  │             ../new.txt             │
                                             │  sec/entry  │  sec/entry   vs base               │
WalkCaseFakeFS100k/rawfs-8                     4.143µ ± 5%   6.568µ ± 1%  +58.55% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                    6.686µ ± 1%   9.424µ ± 1%  +40.95% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8   6.703µ ± 2%   9.517µ ± 1%  +41.97% (p=0.002 n=6)
geomean                                        5.705µ        8.383µ       +46.94%

                                             │  ../old.txt  │             ../new.txt              │
                                             │     B/op     │     B/op      vs base               │
WalkCaseFakeFS100k/rawfs-8                     188.3Mi ± 0%   260.8Mi ± 0%  +38.51% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                    261.5Mi ± 0%   347.7Mi ± 0%  +32.98% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8   261.7Mi ± 0%   348.0Mi ± 0%  +32.96% (p=0.002 n=6)
geomean                                        234.4Mi        316.0Mi       +34.79%

                                             │ ../old.txt  │             ../new.txt             │
                                             │  allocs/op  │  allocs/op   vs base               │
WalkCaseFakeFS100k/rawfs-8                     2.873M ± 0%   5.346M ± 0%  +86.04% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-8                    5.346M ± 0%   8.228M ± 0%  +53.91% (p=0.002 n=6)
WalkCaseFakeFS100k/casefs-otherOpEvery1000-8   5.351M ± 0%   8.236M ± 0%  +53.92% (p=0.002 n=6)
geomean                                        4.348M        7.129M       +63.96%
```

Signed-off-by: Marcus B Spencer <marcus@marcusspencer.us>
2025-10-23 08:40:42 +00:00
Marcus B Spencer
b4565c87ee fix(fs): store getExpireAdd mutex in caseCache (fixes #9836) (#10430)
In #9701 there was a change that put the mutex used for `getExpireAdd` directly in `defaultRealCaser`, which is erroneous because multiple filesystems can share the same `caseCache`.

### Purpose

Fixes #9836 and [Slow sync sending files from Android](https://forum.syncthing.net/t/slow-sync-sending-files-from-android/24208?u=marbens). There may be other issues caused by `getExpireAdd` conflicting with itself, though.

### Testing

Unit tests pass and the case cache and conflict detection _seem_ to behave correctly.

Signed-off-by: Marcus B Spencer <marcus@marcusspencer.us>
2025-10-18 21:56:03 +02:00
Simon Frei
20d2406a0e chore(upnp): remove incorrect embedding of nat.Service (fixes #10426) (#10428) 2025-10-13 07:11:00 +02:00
Marcus B Spencer
d3d3fc2d0e fix(policy): only allow approvals by non-author contributors (#10419)
This replaces `allow_contributor` with `allow_non_author_contributor`,
because the former allows authors to approve their own pull requests.

From https://github.com/syncthing/syncthing/pull/9818#issue-2651431707:

> This adds `allow_contributor: true` which allows approvals by contributors to the PR (*but still not the author themself*, which is a different thing).

This statement conflicts with [the policybot README](c013552248/README.md), which says:

> If true, the approvals of someone who has committed to the pull request are
> considered when calculating the status.
> *The pull request author is considered a contributor.*

Signed-off-by: Marcus B Spencer <marcus@marcusspencer.us>
2025-10-06 08:42:58 +02:00
bt90
f8c44923c7 docs(docker): make host network mode the default (#10416)
Signed-off-by: bt90 <btom1990@googlemail.com>
2025-09-29 15:20:44 -04:00
115 changed files with 289 additions and 298 deletions

20
.github/workflows/org-members.yaml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Org membership recommendations
on:
workflow_dispatch:
schedule:
- cron: '0 0 1 * *'
jobs:
run-recommendation:
runs-on: ubuntu-latest
name: Check for a recommendation
steps:
- uses: docker://ghcr.io/calmh/github-org-members:latest
env:
GITHUB_ORGANISATION: syncthing
GITHUB_TOKEN: ${{ secrets.GOM_GITHUB_TOKEN }}
GOM_IGNORE_USERS: ${{ secrets.GOM_IGNORE_USERS }}
GOM_ALSO_REPOS: ${{ secrets.GOM_ALSO_REPOS }}

View File

@@ -70,6 +70,12 @@ linters:
# Rollback errors can be ignored
- linters: [errcheck]
source: Rollback
# Embedded fields named in selectors may add clarity
- linters: [staticcheck]
text: QF1008
# Don't necessarily rewrite !(foo || bar) to !foo && !bar
- linters: [staticcheck]
text: QF1001
settings:
sloglint:
context: "scope"

View File

@@ -52,7 +52,7 @@ approval_rules:
- syncthing/maintainers
options:
ignore_update_merges: true
allow_contributor: true
allow_non_author_contributor: true
# Regular pull requests require approval by an active contributor
- name: is approved by a syncthing contributor
@@ -62,7 +62,7 @@ approval_rules:
- syncthing/contributors
options:
ignore_update_merges: true
allow_contributor: true
allow_non_author_contributor: true
# Changes to some files (translations, dependencies, compatibility) do not
# require approval if they were proposed by a contributor and have a

View File

@@ -32,6 +32,7 @@ Evgeny Kuznetsov <evgeny@kuznetsov.md>
greatroar <61184462+greatroar@users.noreply.github.com>
Lars K.W. Gohlke (lkwg82) <lkwg82@gmx.de>
Lode Hoste (Zillode) <zillode@zillode.be>
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
Michael Ploujnikov (plouj) <ploujj@gmail.com>
Ross Smith II (rasa) <ross@smithii.com>
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
@@ -198,7 +199,6 @@ Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
Marcel Meyer <mm.marcelmeyer@gmail.com>
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
Marcus Legendre <marcus.legendre@gmail.com>
Mario Majila <mariustshipichik@gmail.com>
Mark Pulford (mpx) <mark@kyne.com.au>

View File

@@ -23,52 +23,7 @@ example `UMASK=002`.
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp -p 21027:21027/udp \
-v /wherever/st-sync:/var/syncthing \
--hostname=my-syncthing \
syncthing/syncthing:latest
```
**Docker compose**
```yml
---
version: "3"
services:
syncthing:
image: syncthing/syncthing
container_name: syncthing
hostname: my-syncthing
environment:
- PUID=1000
- PGID=1000
volumes:
- /wherever/st-sync:/var/syncthing
ports:
- 8384:8384 # Web UI
- 22000:22000/tcp # TCP file transfers
- 22000:22000/udp # QUIC file transfers
- 21027:21027/udp # Receive local discovery broadcasts
restart: unless-stopped
healthcheck:
test: curl -fkLsS -m 2 127.0.0.1:8384/rest/noauth/health | grep -o --color=never OK || exit 1
interval: 1m
timeout: 10s
retries: 3
```
## Discovery
Note that Docker's default network mode prevents local IP addresses from
being discovered, as Syncthing is only able to see the internal IP of the
container on the `172.17.0.0/16` subnet. This will result in poor transfer rates
if local device addresses are not manually configured.
It is therefore advisable to use the [host network mode](https://docs.docker.com/network/host/) instead:
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run --network=host \
$ docker run --network=host -e STGUIADDRESS= \
-v /wherever/st-sync:/var/syncthing \
syncthing/syncthing:latest
```
@@ -85,6 +40,7 @@ services:
environment:
- PUID=1000
- PGID=1000
- STGUIADDRESS=
volumes:
- /wherever/st-sync:/var/syncthing
network_mode: host
@@ -96,27 +52,27 @@ services:
retries: 3
```
## Discovery
Please note that Docker's default network mode prevents local IP addresses
from being discovered, as Syncthing can only see the internal IP address of
the container on the `172.17.0.0/16` subnet. This would likely break the ability
for nodes to establish LAN connections properly, resulting in poor transfer
rates unless local device addresses are configured manually.
It is therefore strongly recommended to stick to the [host network mode](https://docs.docker.com/network/host/),
as shown above.
Be aware that syncthing alone is now in control of what interfaces and ports it
listens on. You can edit the syncthing configuration to change the defaults if
there are conflicts.
## GUI Security
By default Syncthing inside the Docker image listens on 0.0.0.0:8384 to
allow GUI connections via the Docker proxy. This is set by the
`STGUIADDRESS` environment variable in the Dockerfile, as it differs from
what Syncthing would otherwise use by default. This means you should set up
authentication in the GUI, like for any other externally reachable Syncthing
instance. If you do not require the GUI, or you use host networking, you can
unset the `STGUIADDRESS` variable to have Syncthing fall back to listening
on 127.0.0.1:
```
$ docker pull syncthing/syncthing
$ docker run -e STGUIADDRESS= \
-v /wherever/st-sync:/var/syncthing \
syncthing/syncthing:latest
```
With the environment variable unset Syncthing will follow what is set in the
configuration file / GUI settings dialog.
By default Syncthing inside the Docker image listens on `0.0.0.0:8384`. This
allows GUI connections when running without host network mode. The example
above unsets the `STGUIADDRESS` environment variable to have Syncthing fall
back to listening on what has been configured in the configuration file or the
GUI settings dialog. By default this is the localhost IP address `127.0.0.1`.
If you configure your GUI to be externally reachable, make sure you set up
authentication and enable TLS.

View File

@@ -118,7 +118,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
bs, err := io.ReadAll(lr)
req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -130,7 +130,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
var reports []ur.FailureReport
err = json.Unmarshal(bs, &reports)
if err != nil {
http.Error(w, err.Error(), 400)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if len(reports) == 0 {
@@ -141,7 +141,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
version, err := build.ParseVersion(reports[0].Version)
if err != nil {
http.Error(w, err.Error(), 400)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
for _, r := range reports {

View File

@@ -90,7 +90,7 @@ func sendReport(dsn string, pkt *raven.Packet, userID string) error {
}
// The client sets release and such on the packet before sending, in the
// misguided idea that it knows this better than than the packet we give
// misguided idea that it knows this better than the packet we give
// it. So we copy the values from the packet to the client first...
cli.SetRelease(pkt.Release)
cli.SetEnvironment(pkt.Environment)
@@ -136,7 +136,7 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
r := bytes.NewReader(report)
ctx, _, err := stack.ScanSnapshot(r, io.Discard, stack.DefaultOpts())
if err != nil && err != io.EOF {
if err != nil && !errors.Is(err, io.EOF) {
return nil, err
}
if ctx == nil || len(ctx.Goroutines) == 0 {

View File

@@ -10,7 +10,7 @@ import (
"bytes"
"compress/gzip"
"crypto/sha256"
"fmt"
"encoding/hex"
"net"
"net/http"
"os"
@@ -23,7 +23,7 @@ import (
// remote IP, and the current month.
func userIDFor(req *http.Request) string {
addr := req.RemoteAddr
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
if fwd := req.Header.Get("X-Forwarded-For"); fwd != "" {
addr = fwd
}
if host, _, err := net.SplitHostPort(addr); err == nil {
@@ -32,7 +32,7 @@ func userIDFor(req *http.Request) string {
now := time.Now().Format("200601")
salt := "stcrashreporter"
hash := sha256.Sum256([]byte(salt + addr + now))
return fmt.Sprintf("%x", hash[:8])
return hex.EncodeToString(hash[:8])
}
// 01234567890abcdef... => 01/23

View File

@@ -162,7 +162,7 @@ func main() {
testCert = createTestCertificate()
for i := 0; i < requestProcessors; i++ {
for range requestProcessors {
go requestProcessor(geoip)
}
@@ -180,7 +180,7 @@ func main() {
relayTestsTotal.WithLabelValues("success").Inc()
}
}
// Run the the stats refresher once the relays are loaded.
// Run the stats refresher once the relays are loaded.
statsRefresher(statsRefresh)
}()
@@ -653,6 +653,7 @@ func getLocation(host string, geoip *geoip.Provider) location {
type loggingResponseWriter struct {
http.ResponseWriter
statusCode int
}

View File

@@ -47,7 +47,7 @@ func newMetricsSet(srv *server) *metricsSet {
var initForType func(reflect.Type)
initForType = func(t reflect.Type) {
for i := 0; i < t.NumField(); i++ {
for i := range t.NumField() {
field := t.Field(i)
if field.Type.Kind() == reflect.Struct {
initForType(field.Type)
@@ -175,7 +175,7 @@ func (s *metricsSet) addReport(r *contract.Report) {
func (s *metricsSet) addReportStruct(v reflect.Value, gaugeVecs map[string][]string) {
t := v.Type()
for i := 0; i < v.NumField(); i++ {
for i := range v.NumField() {
field := v.Field(i)
if field.Kind() == reflect.Struct {
s.addReportStruct(field, gaugeVecs)

View File

@@ -23,6 +23,7 @@ import (
type amqpReplicator struct {
suture.Service
broker string
sender *amqpSender
receiver *amqpReceiver

View File

@@ -350,7 +350,7 @@ func certificateBytes(req *http.Request) ([]byte, error) {
var bs []byte
if hdr := req.Header.Get("X-SSL-Cert"); hdr != "" {
if hdr := req.Header.Get("X-Ssl-Cert"); hdr != "" {
if strings.Contains(hdr, "%") {
// Nginx using $ssl_client_escaped_cert
// The certificate is in PEM format with url encoding.
@@ -513,6 +513,7 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
type loggingResponseWriter struct {
http.ResponseWriter
statusCode int
}

View File

@@ -14,6 +14,7 @@ import (
"os"
"os/signal"
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"syscall"
@@ -247,10 +248,10 @@ func main() {
query.Set("pingInterval", pingInterval.String())
query.Set("networkTimeout", networkTimeout.String())
if sessionLimitBps > 0 {
query.Set("sessionLimitBps", fmt.Sprint(sessionLimitBps))
query.Set("sessionLimitBps", strconv.Itoa(sessionLimitBps))
}
if globalLimitBps > 0 {
query.Set("globalLimitBps", fmt.Sprint(globalLimitBps))
query.Set("globalLimitBps", strconv.Itoa(globalLimitBps))
}
if statusAddr != "" {
query.Set("statusAddr", statusAddr)

View File

@@ -122,7 +122,7 @@ func (r *rateCalculator) updateRates(interval time.Duration) {
func (r *rateCalculator) rate(periods int) int64 {
var tot int64
for i := 0; i < periods; i++ {
for i := range periods {
tot += r.rates[i]
}
return tot / int64(periods)

View File

@@ -6,6 +6,7 @@ import (
"bufio"
"context"
"crypto/tls"
"errors"
"flag"
"log"
"net"
@@ -133,7 +134,8 @@ func connectToStdio(stdin <-chan string, conn net.Conn) {
conn.SetReadDeadline(time.Now().Add(time.Millisecond))
n, err := conn.Read(buf[0:])
if err != nil {
nerr, ok := err.(net.Error)
var nerr net.Error
ok := errors.As(err, &nerr)
if !ok || !nerr.Timeout() {
log.Println(err)
return

View File

@@ -10,7 +10,7 @@ import (
func setTCPOptions(conn net.Conn) error {
tcpConn, ok := conn.(*net.TCPConn)
if !ok {
return errors.New("Not a TCP connection")
return errors.New("not a TCP connection")
}
if err := tcpConn.SetLinger(0); err != nil {
return err

View File

@@ -32,6 +32,7 @@ type APIClient interface {
type apiClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
@@ -91,11 +92,11 @@ func loadGUIConfig() (config.GUIConfiguration, error) {
guiCfg := cfg.GUI()
if guiCfg.Address() == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI Address")
return config.GUIConfiguration{}, errors.New("could not find GUI Address")
}
if guiCfg.APIKey == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI API key")
return config.GUIConfiguration{}, errors.New("could not find GUI API key")
}
return guiCfg, nil
@@ -113,7 +114,7 @@ func (c *apiClient) Endpoint() string {
}
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
req.Header.Set("X-Api-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
return nil, err

View File

@@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"reflect"
"github.com/AudriusButkevicius/recli"
@@ -86,7 +87,7 @@ func (h *configHandler) configAfter(_ *cli.Context) error {
if err != nil {
return err
}
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
body, err := responseToBArray(resp)
if err != nil {
return err

View File

@@ -9,6 +9,7 @@ package cli
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/alecthomas/kong"
@@ -34,7 +35,7 @@ func (e *errorsPushCommand) Run(ctx Context) error {
if err != nil {
return err
}
if response.StatusCode != 200 {
if response.StatusCode != http.StatusOK {
errStr = fmt.Sprint("Failed to push error\nStatus code: ", response.StatusCode)
bytes, err := responseToBArray(response)
if err != nil {

View File

@@ -10,6 +10,7 @@ import (
"bufio"
"errors"
"fmt"
"net/http"
"path/filepath"
"github.com/alecthomas/kong"
@@ -63,7 +64,7 @@ func (f *folderOverrideCommand) Run(ctx Context) error {
if err != nil {
return err
}
if response.StatusCode != 200 {
if response.StatusCode != http.StatusOK {
errStr := fmt.Sprint("Failed to override changes\nStatus code: ", response.StatusCode)
bytes, err := responseToBArray(response)
if err != nil {

View File

@@ -31,7 +31,7 @@ const (
// directory to the crash reporting server as urlBase. Uploads are attempted
// with the newest log first.
//
// This can can block for a long time. The context can set a final deadline
// This can block for a long time. The context can set a final deadline
// for this.
func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
files, err := filepath.Glob(filepath.Join(dir, "panic-*.log"))

View File

@@ -388,8 +388,8 @@ func upgradeViaRest() error {
}
u.Path = path.Join(u.Path, "rest/system/upgrade")
target := u.String()
r, _ := http.NewRequest("POST", target, nil)
r.Header.Set("X-API-Key", cfg.GUI().APIKey)
r, _ := http.NewRequest(http.MethodPost, target, nil)
r.Header.Set("X-Api-Key", cfg.GUI().APIKey)
tr := &http.Transport{
DialContext: dialer.DialContext,
@@ -407,7 +407,7 @@ func upgradeViaRest() error {
defer resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
bs, err := io.ReadAll(resp.Body)
if err != nil {
return err
@@ -529,7 +529,8 @@ func (c *serveCmd) syncthingMain() {
err = upgrade.To(release)
}
if err != nil {
if _, ok := err.(*errNoUpgrade); ok || err == errTooEarlyUpgradeCheck || err == errTooEarlyUpgrade {
var noUpgradeErr *errNoUpgrade
if errors.As(err, &noUpgradeErr) || errors.Is(err, errTooEarlyUpgradeCheck) || errors.Is(err, errTooEarlyUpgrade) {
slog.Debug("Initial automatic upgrade", slogutil.Error(err))
} else {
slog.Info("Initial automatic upgrade", slogutil.Error(err))
@@ -659,13 +660,14 @@ func auditWriter(auditFile string) io.Writer {
var auditDest string
var auditFlags int
if auditFile == "-" {
switch auditFile {
case "-":
fd = os.Stdout
auditDest = "stdout"
} else if auditFile == "--" {
case "--":
fd = os.Stderr
auditDest = "stderr"
} else {
default:
if auditFile == "" {
auditFile = locations.GetTimestamped(locations.AuditLog)
auditFlags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
@@ -720,7 +722,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
checkInterval := time.Duration(opts.AutoUpgradeIntervalH) * time.Hour
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
if err == upgrade.ErrUpgradeUnsupported {
if errors.Is(err, upgrade.ErrUpgradeUnsupported) {
sub.Unsubscribe()
return
}
@@ -836,7 +838,8 @@ func setPauseState(cfgWrapper config.Wrapper, paused bool) {
}
func exitCodeForUpgrade(err error) int {
if _, ok := err.(*errNoUpgrade); ok {
var noUpgradeErr *errNoUpgrade
if errors.As(err, &noUpgradeErr) {
return svcutil.ExitNoUpgradeAvailable.AsInt()
}
return svcutil.ExitError.AsInt()

View File

@@ -9,6 +9,7 @@ package main
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"log/slog"
@@ -176,7 +177,8 @@ func (c *serveCmd) monitorMain() {
os.Exit(svcutil.ExitSuccess.AsInt())
}
if exiterr, ok := err.(*exec.ExitError); ok {
exiterr := &exec.ExitError{}
if errors.As(err, &exiterr) {
exitCode := exiterr.ExitCode()
if stopped || c.NoRestart {
os.Exit(exitCode)

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -82,6 +82,7 @@
"Custom Range": "Custom Range",
"Danger!": "Danger!",
"Database Location": "Database Location",
"Debug": "Debug",
"Debugging Facilities": "Debugging Facilities",
"Default": "Default",
"Default Configuration": "Default Configuration",
@@ -210,6 +211,7 @@
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Incorrect configuration may damage your folder contents and render Syncthing inoperable.",
"Incorrect user name or password.": "Incorrect username or password.",
"Info": "Info",
"Internally used paths:": "Internally used paths:",
"Introduced By": "Introduced By",
"Introducer": "Introducer",

View File

@@ -82,6 +82,7 @@
"Custom Range": "Intervallo personalizzato",
"Danger!": "Pericolo!",
"Database Location": "Posizione del database",
"Debug": "Debug",
"Debugging Facilities": "Servizi di Debug",
"Default": "Default",
"Default Configuration": "Configurazione predefinita",
@@ -210,6 +211,7 @@
"Incoming Rate Limit (KiB/s)": "Limite Velocità in Ingresso (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configurazione non corretta potrebbe danneggiare il contenuto delle cartelle e rendere Syncthing inoperativo.",
"Incorrect user name or password.": "Nome utente o password errati.",
"Info": "Info",
"Internally used paths:": "Percorsi interni utilizzati:",
"Introduced By": "Introdotto da",
"Introducer": "Introduttore",
@@ -227,6 +229,7 @@
"Learn more": "Per saperne di più",
"Learn more at {%url%}": "Scopri di più su {{url}}",
"Limit": "Limite",
"Limit Bandwidth in LAN": "Limitare la larghezza di banda nella LAN",
"Listener Failures": "Fallimenti dell'Ascoltatore",
"Listener Status": "Stato dell'Ascoltatore",
"Listeners": "In Ascolto",

View File

@@ -30,7 +30,7 @@
<h4 class="text-center" translate>The Syncthing Authors</h4>
<div class="row">
<div class="col-md-12" id="contributor-list">
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Tommy van der Vorst, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Daniil Gentili, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Marcus B Spencer, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Tommy van der Vorst, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Daniil Gentili, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
</div>
</div>
</div>

View File

@@ -10,6 +10,7 @@ import "github.com/jmoiron/sqlx"
type txPreparedStmts struct {
*sqlx.Tx
stmts map[string]*sqlx.Stmt
}

View File

@@ -14,9 +14,10 @@ import (
)
type folderDB struct {
folderID string
*baseDB
folderID string
localDeviceIdx int64
deleteRetention time.Duration
}

View File

@@ -455,7 +455,7 @@ func (s *service) Serve(ctx context.Context) error {
// due to a config change through the API, let that finish successfully.
timeout, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
defer cancel()
if err := srv.Shutdown(timeout); err == timeout.Err() {
if err := srv.Shutdown(timeout); errors.Is(err, timeout.Err()) {
srv.Close()
}
@@ -546,7 +546,7 @@ func corsMiddleware(next http.Handler, allowFrameLoading bool) http.Handler {
// See https://www.w3.org/TR/cors/ for details.
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Process OPTIONS requests
if r.Method == "OPTIONS" {
if r.Method == http.MethodOptions {
// Add a generous access-control-allow-origin header for CORS requests
w.Header().Add("Access-Control-Allow-Origin", "*")
// Only GET/POST/OPTIONS Methods are supported
@@ -557,7 +557,7 @@ func corsMiddleware(next http.Handler, allowFrameLoading bool) http.Handler {
w.Header().Set("Access-Control-Max-Age", "600")
// Indicate that no content will be returned
w.WriteHeader(204)
w.WriteHeader(http.StatusNoContent)
return
}

View File

@@ -337,7 +337,7 @@ func formatOptionalPercentS(template string, username string) string {
if nReps < 0 {
nReps = 0
}
for i := 0; i < nReps; i++ {
for range nReps {
replacements = append(replacements, username)
}
return fmt.Sprintf(template, replacements...)

View File

@@ -22,6 +22,7 @@ import (
type configMuxBuilder struct {
*httprouter.Router
id protocol.DeviceID
cfg config.Wrapper
}

View File

@@ -168,8 +168,8 @@ func (m *tokenCookieManager) createSession(username string, persistent bool, w h
// either directly to us, or as used by the client towards a reverse
// proxy who sends us headers.
connectionIsHTTPS := r.TLS != nil ||
strings.ToLower(r.Header.Get("x-forwarded-proto")) == "https" ||
strings.Contains(strings.ToLower(r.Header.Get("forwarded")), "proto=https")
strings.ToLower(r.Header.Get("X-Forwarded-Proto")) == "https" ||
strings.Contains(strings.ToLower(r.Header.Get("Forwarded")), "proto=https")
// If the connection is HTTPS, or *should* be HTTPS, set the Secure
// bit in cookies.
useSecureCookie := connectionIsHTTPS || m.guiCfg.UseTLS()

View File

@@ -32,6 +32,7 @@ type Interface interface {
type cast struct {
*suture.Supervisor
name string
reader svcutil.ServiceWithError
writer svcutil.ServiceWithError

View File

@@ -8,6 +8,7 @@ package beacon
import (
"context"
"errors"
"log/slog"
"net"
"time"
@@ -93,7 +94,8 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error {
_, err = conn.WriteTo(bs, dst)
conn.SetWriteDeadline(time.Time{})
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
var nerr net.Error
if errors.As(err, &nerr) && nerr.Timeout() {
// Write timeouts should not happen. We treat it as a fatal
// error on the socket.
l.Debugln(err)

View File

@@ -165,6 +165,7 @@ func (cfg *Configuration) ProbeFreePorts() error {
type xmlConfiguration struct {
Configuration
XMLName xml.Name `xml:"configuration"`
}
@@ -684,7 +685,7 @@ func copyMatchingTag(from interface{}, to interface{}, tag string, shouldCopy fu
panic(fmt.Sprintf("non equal types: %s != %s", fromType, toType))
}
for i := 0; i < toStruct.NumField(); i++ {
for i := range toStruct.NumField() {
fromField := fromStruct.Field(i)
toField := toStruct.Field(i)

View File

@@ -153,7 +153,7 @@ func (f FolderConfiguration) ModTimeWindow() time.Duration {
}
func (f *FolderConfiguration) CreateMarker() error {
if err := f.CheckPath(); err != ErrMarkerMissing {
if err := f.CheckPath(); !errors.Is(err, ErrMarkerMissing) {
return err
}
if f.MarkerName != DefaultMarkerName {

View File

@@ -428,11 +428,12 @@ func migrateToConfigV12(cfg *Configuration) {
var newDiscoServers []string
var useDefault bool
for _, addr := range cfg.Options.RawGlobalAnnServers {
if addr == "udp4://announce.syncthing.net:22026" {
switch addr {
case "udp4://announce.syncthing.net:22026":
useDefault = true
} else if addr == "udp6://announce-v6.syncthing.net:22026" {
case "udp6://announce-v6.syncthing.net:22026":
useDefault = true
} else {
default:
newDiscoServers = append(newDiscoServers, addr)
}
}

View File

@@ -11,6 +11,7 @@ import "github.com/syncthing/syncthing/lib/config"
// invalidListener is never valid
type invalidListener struct {
listenerFactory
err error
}
@@ -25,6 +26,7 @@ func (i invalidListener) Valid(_ config.Configuration) error {
// invalidDialer is never valid
type invalidDialer struct {
dialerFactory
err error
}

View File

@@ -225,8 +225,9 @@ func getRateLimiter(m map[protocol.DeviceID]*rate.Limiter, deviceID protocol.Dev
// limitedReader is a rate limited io.Reader
type limitedReader struct {
reader io.Reader
waiterHolder
reader io.Reader
}
func (r *limitedReader) Read(buf []byte) (int, error) {
@@ -239,8 +240,9 @@ func (r *limitedReader) Read(buf []byte) (int, error) {
// limitedWriter is a rate limited io.Writer
type limitedWriter struct {
writer io.Writer
waiterHolder
writer io.Writer
}
func (w *limitedWriter) Write(buf []byte) (int, error) {

View File

@@ -39,6 +39,7 @@ func init() {
type quicDialer struct {
commonDialer
registry *registry.Registry
}

View File

@@ -39,10 +39,10 @@ func init() {
type quicListener struct {
svcutil.ServiceWithError
nat atomic.Uint64 // Holds a stun.NATType.
onAddressesChangedNotifier
nat atomic.Uint64 // Holds a stun.NATType.
uri *url.URL
cfg config.Wrapper
tlsCfg *tls.Config

View File

@@ -42,6 +42,7 @@ func quicNetwork(uri *url.URL) string {
type quicTlsConn struct {
quic.Connection
quic.Stream
// If we created this connection, we should be the ones closing it.
createdConn net.PacketConn
}

View File

@@ -1340,7 +1340,7 @@ func (c *deviceConnectionTracker) accountAddedConnection(conn protocol.Connectio
// how many total connections they want
d := conn.DeviceID()
c.connections[d] = append(c.connections[d], conn)
c.wantConnections[d] = int(h.NumConnections)
c.wantConnections[d] = h.NumConnections
l.Debugf("Added connection for %s (now %d), they want %d connections", d.Short(), len(c.connections[d]), h.NumConnections)
// Update active connections metric

View File

@@ -39,6 +39,7 @@ type tlsConn interface {
// came from (type, priority).
type internalConn struct {
tlsConn
connType connType
isLocal bool
priority int

View File

@@ -27,6 +27,7 @@ func init() {
type tcpDialer struct {
commonDialer
registry *registry.Registry
}

View File

@@ -81,11 +81,12 @@ func (t *tcpListener) serve(ctx context.Context) error {
defer slog.InfoContext(ctx, "TCP listener shutting down", slogutil.Address(tcaddr))
var ipVersion nat.IPVersion
if t.uri.Scheme == "tcp4" {
switch t.uri.Scheme {
case "tcp4":
ipVersion = nat.IPv4Only
} else if t.uri.Scheme == "tcp6" {
case "tcp6":
ipVersion = nat.IPv6Only
} else {
default:
ipVersion = nat.IPvAny
}
mapping := t.natService.NewMapping(nat.TCP, ipVersion, tcaddr.IP, tcaddr.Port)

View File

@@ -7,6 +7,7 @@
package connections
import (
"errors"
"net"
"net/url"
"strconv"
@@ -20,7 +21,8 @@ func fixupPort(uri *url.URL, defaultPort int) *url.URL {
copyURI := *uri
host, port, err := net.SplitHostPort(uri.Host)
if e, ok := err.(*net.AddrError); ok && strings.Contains(e.Err, "missing port") {
e := &net.AddrError{}
if errors.As(err, &e) && strings.Contains(e.Err, "missing port") {
// addr is of the form "1.2.3.4" or "[fe80::1]"
host = uri.Host
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {

View File

@@ -64,6 +64,7 @@ func socksDialerFunction(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error)
// existing connection" shenanigans.
type dialerConn struct {
net.Conn
addr net.Addr
}

View File

@@ -17,6 +17,7 @@ import (
// A cachedFinder is a Finder with associated cache timeouts.
type cachedFinder struct {
Finder
cacheTime time.Duration
negCacheTime time.Duration
cache *cache

View File

@@ -32,6 +32,8 @@ import (
)
type globalClient struct {
errorHolder
server string
addrList AddressLister
announceClient httpClient
@@ -39,7 +41,6 @@ type globalClient struct {
noAnnounce bool
noLookup bool
evLogger events.Logger
errorHolder
}
type httpClient interface {
@@ -373,6 +374,7 @@ func queryBool(q url.Values, key string) bool {
type idCheckingHTTPClient struct {
httpClient
id protocol.DeviceID
}
@@ -472,7 +474,7 @@ func ipv4Identity(port int) string {
}
func ipv6Identity(addr string) string {
return fmt.Sprintf("IPv6 local multicast discovery on address %s", addr)
return "IPv6 local multicast discovery on address " + addr
}
func http2EnabledTransport(t *http.Transport) *http.Transport {

View File

@@ -34,6 +34,8 @@ import (
type localClient struct {
*suture.Supervisor
*cache
myID protocol.DeviceID
addrList AddressLister
name string
@@ -43,8 +45,6 @@ type localClient struct {
localBcastStart time.Time
localBcastTick <-chan time.Time
forcedBcastTick chan time.Time
*cache
}
const (

View File

@@ -41,6 +41,7 @@ type Manager interface {
type manager struct {
*suture.Supervisor
myID protocol.DeviceID
cfg config.Wrapper
cert tls.Certificate

View File

@@ -524,7 +524,7 @@ func (s *bufferedSubscription) Since(id int, into []Event, timeout time.Duration
into = append(into, s.buf[i])
}
}
for i := 0; i < s.next; i++ {
for i := range s.next {
if s.buf[i].SubscriptionID > id {
into = append(into, s.buf[i])
}

View File

@@ -340,6 +340,7 @@ func (*BasicFilesystem) underlying() (Filesystem, bool) {
// basicFile implements the fs.File interface on top of an os.File
type basicFile struct {
*os.File
name string
}

View File

@@ -397,10 +397,13 @@ func (f *caseFilesystem) checkCaseExisting(name string) error {
type defaultRealCaser struct {
cache *caseCache
fs Filesystem
mut sync.Mutex
}
type caseCache = lru.TwoQueueCache[string, *caseNode]
type caseCache struct {
*lru.TwoQueueCache[string, *caseNode]
mut sync.Mutex
}
func newCaseCache() *caseCache {
cache, err := lru.New2Q[string, *caseNode](caseCacheItemLimit)
@@ -408,7 +411,9 @@ func newCaseCache() *caseCache {
if err != nil {
panic(err)
}
return cache
return &caseCache{
TwoQueueCache: cache,
}
}
func (r *defaultRealCaser) realCase(name string) (string, error) {
@@ -418,7 +423,7 @@ func (r *defaultRealCaser) realCase(name string) (string, error) {
}
for _, comp := range PathComponents(name) {
node := r.getExpireAdd(realName)
node := r.cache.getExpireAdd(realName, r.fs)
if node.err != nil {
return "", node.err
@@ -444,18 +449,18 @@ func (r *defaultRealCaser) dropCache() {
// getExpireAdd gets an entry for the given key. If no entry exists, or it is
// expired a new one is created and added to the cache.
func (r *defaultRealCaser) getExpireAdd(key string) *caseNode {
r.mut.Lock()
defer r.mut.Unlock()
node, ok := r.cache.Get(key)
func (c *caseCache) getExpireAdd(key string, fs Filesystem) *caseNode {
c.mut.Lock()
defer c.mut.Unlock()
node, ok := c.Get(key)
if !ok {
node := newCaseNode(key, r.fs)
r.cache.Add(key, node)
node := newCaseNode(key, fs)
c.Add(key, node)
return node
}
if node.expires.Before(time.Now()) {
node = newCaseNode(key, r.fs)
r.cache.Add(key, node)
node = newCaseNode(key, fs)
c.Add(key, node)
}
return node
}

View File

@@ -156,7 +156,7 @@ func testCaseFSStat(t *testing.T, fsys Filesystem) {
func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
const entries = 100_000
fsys, paths, err := fakefsForBenchmark(entries, 0)
fsys, paths, err := fakefsForTest(entries, 0)
if err != nil {
b.Fatal(err)
}
@@ -260,7 +260,7 @@ func TestStressCaseFS(t *testing.T) {
t.Skip("long test")
}
fsys, paths, err := fakefsForBenchmark(10_000, 0)
fsys, paths, err := fakefsForTest(10_000, 0, &OptionDetectCaseConflicts{})
if err != nil {
t.Fatal(err)
}
@@ -326,8 +326,8 @@ func doubleWalkFSWithOtherOps(fsys Filesystem, paths []string, otherOpEvery int,
return nil
}
func fakefsForBenchmark(nfiles int, latency time.Duration) (Filesystem, []string, error) {
fsys := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("fakefsForBenchmark?files=%d&insens=true&latency=%s", nfiles, latency))
func fakefsForTest(nfiles int, latency time.Duration, opts ...Option) (Filesystem, []string, error) {
fsys := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("fakefsForBenchmark?files=%d&insens=true&latency=%s", nfiles, latency), opts...)
var paths []string
if err := fsys.Walk("/", func(path string, info FileInfo, err error) error {

View File

@@ -749,6 +749,7 @@ func (fs *fakeFS) reportMetricsPer(b *testing.B, divisor float64, unit string) {
// opened for reading or writing, it's all good.
type fakeFile struct {
*fakeEntry
mut *sync.Mutex
rng io.Reader
seed int64

View File

@@ -140,12 +140,12 @@ func (evType EventType) Merge(other EventType) EventType {
}
func (evType EventType) String() string {
switch {
case evType == NonRemove:
switch evType {
case NonRemove:
return "non-remove"
case evType == Remove:
case Remove:
return "remove"
case evType == Mixed:
case Mixed:
return "mixed"
default:
panic("bug: Unknown event type")

View File

@@ -16,6 +16,7 @@ import (
type logFilesystem struct {
Filesystem
// Number of filesystem layers on top of logFilesystem to skip when looking
// for the true caller of the filesystem
layers int

View File

@@ -19,6 +19,7 @@ type database interface {
type mtimeFS struct {
Filesystem
chtimes func(string, time.Time, time.Time) error
db database
folderID string
@@ -170,6 +171,7 @@ func (f *mtimeFS) load(name string) (ondisk, virtual time.Time) {
type mtimeFileInfo struct {
FileInfo
mtime time.Time
}
@@ -179,6 +181,7 @@ func (m mtimeFileInfo) ModTime() time.Time {
type mtimeFile struct {
File
fs *mtimeFS
}

View File

@@ -63,6 +63,7 @@ type WalkFunc func(path string, info FileInfo, err error) error
type walkFilesystem struct {
Filesystem
checkInfiniteRecursion bool
}

View File

@@ -12,6 +12,7 @@ import (
"context"
"fmt"
"net/http"
"strconv"
"strings"
"sync"
"time"
@@ -50,13 +51,13 @@ func (resp *recordedResponse) ServeHTTP(w http.ResponseWriter, r *http.Request)
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Content-Length", fmt.Sprint(len(resp.gzip)))
w.Header().Set("Content-Length", strconv.Itoa(len(resp.gzip)))
w.WriteHeader(resp.status)
_, _ = w.Write(resp.gzip)
return
}
w.Header().Set("Content-Length", fmt.Sprint(len(resp.data)))
w.Header().Set("Content-Length", strconv.Itoa(len(resp.data)))
w.WriteHeader(resp.status)
_, _ = w.Write(resp.data)
}

View File

@@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
@@ -353,7 +354,7 @@ func hashPatterns(patterns []Pattern) string {
h.Write([]byte(pat.String()))
h.Write([]byte("\n"))
}
return fmt.Sprintf("%x", h.Sum(nil))
return hex.EncodeToString(h.Sum(nil))
}
func loadIgnoreFile(fs fs.Filesystem, file string) (fs.File, fs.FileInfo, error) {

View File

@@ -44,6 +44,7 @@ type folder struct {
stateTracker
config.FolderConfiguration
*stats.FolderStatisticsReference
ioLimiter *semaphore.Semaphore
localFlags protocol.FlagLocal

View File

@@ -48,6 +48,7 @@ func init() {
// to be fetched.
type pullBlockState struct {
*sharedPullerState
block protocol.BlockInfo
}
@@ -55,6 +56,7 @@ type pullBlockState struct {
// copied.
type copyBlocksState struct {
*sharedPullerState
blocks []protocol.BlockInfo
have int
}

View File

@@ -690,6 +690,7 @@ type ConnectionStats struct {
type ConnectionInfo struct {
protocol.Statistics
Address string `json:"address"`
Type string `json:"type"`
IsLocal bool `json:"isLocal"`
@@ -3484,6 +3485,7 @@ func redactPathError(err error) (error, bool) {
type redactedError struct {
error
redacted error
}

View File

@@ -356,7 +356,7 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
l.Debugf("Error extending lease on %v (external port %d -> internal port %d): %v", natd.ID(), extPort, intAddr.Port, err)
}
for i := 0; i < 10; i++ {
for range 10 {
select {
case <-ctx.Done():
return []Address{}, ctx.Err()

View File

@@ -44,7 +44,7 @@ func CreateAtomic(path string) (*AtomicWriter, error) {
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 os.CreateTemp
// does. We have a test that verifies that that is the case, should this
// does. We have a test that verifies that this is the case, should this
// ever change in the standard library in the future.
fd, err := TempFile(filesystem, filepath.Dir(path), TempPrefix)
if err != nil {

View File

@@ -48,7 +48,7 @@ func nextSuffix() string {
// to remove the file when no longer needed.
func TempFile(filesystem fs.Filesystem, dir, prefix string) (f fs.File, err error) {
nconflict := 0
for i := 0; i < 10000; i++ {
for range 10000 {
name := filepath.Join(dir, prefix+nextSuffix())
f, err = filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate|fs.OptExclusive, 0o600)
if fs.IsExist(err) {

View File

@@ -7,7 +7,6 @@
package osutil
import (
"fmt"
"path/filepath"
"github.com/syncthing/syncthing/lib/fs"
@@ -19,7 +18,7 @@ type TraversesSymlinkError struct {
}
func (e *TraversesSymlinkError) Error() string {
return fmt.Sprintf("traverses symlink: %s", e.path)
return "traverses symlink: " + e.path
}
// NotADirectoryError is an error indicating an expected path is not a directory
@@ -28,7 +27,7 @@ type NotADirectoryError struct {
}
func (e *NotADirectoryError) Error() string {
return fmt.Sprintf("not a directory: %s", e.path)
return "not a directory: " + e.path
}
// TraversesSymlink returns an error if any path component of name (including name

View File

@@ -9,7 +9,6 @@ package pmp
import (
"context"
"errors"
"fmt"
"log/slog"
"net"
"strings"
@@ -90,7 +89,7 @@ type wrapper struct {
}
func (w *wrapper) ID() string {
return fmt.Sprintf("NAT-PMP@%s", w.gatewayIP.String())
return "NAT-PMP@" + w.gatewayIP.String()
}
func (w *wrapper) GetLocalIPv4Address() net.IP {

View File

@@ -14,6 +14,7 @@ import (
type countingReader struct {
io.Reader
idString string
tot atomic.Int64 // bytes
last atomic.Int64 // unix nanos
@@ -41,6 +42,7 @@ func (c *countingReader) Last() time.Time {
type countingWriter struct {
io.Writer
idString string
tot atomic.Int64 // bytes
last atomic.Int64 // unix nanos

View File

@@ -181,7 +181,7 @@ func luhnify(s string) (string, error) {
}
res := make([]byte, 4*(13+1))
for i := 0; i < 4; i++ {
for i := range 4 {
p := s[i*13 : (i+1)*13]
copy(res[i*(13+1):], p)
l, err := luhn32(p)
@@ -199,7 +199,7 @@ func unluhnify(s string) (string, error) {
}
res := make([]byte, 52)
for i := 0; i < 4; i++ {
for i := range 4 {
p := s[i*(13+1) : (i+1)*(13+1)-1]
copy(res[i*13:], p)
l, err := luhn32(p)
@@ -216,7 +216,7 @@ func unluhnify(s string) (string, error) {
func chunkify(s string) string {
chunks := len(s) / 7
res := make([]byte, chunks*(7+1)-1)
for i := 0; i < chunks; i++ {
for i := range chunks {
if i > 0 {
res[i*(7+1)-1] = '-'
}

View File

@@ -171,6 +171,7 @@ func (e encryptedModel) Closed(err error) {
// encrypts outgoing metadata and decrypts incoming responses.
type encryptedConnection struct {
ConnectionInfo
conn *rawConnection
folderKeys *folderKeyRegistry
keyGen *KeyGenerator

View File

@@ -406,7 +406,7 @@ func (c *rawConnection) readerLoop() {
for {
msg, err := c.readMessage(fourByteBuf)
if err != nil {
if err == errUnknownMessage {
if errors.Is(err, errUnknownMessage) {
// Unknown message types are skipped, for future extensibility.
continue
}

View File

@@ -41,7 +41,7 @@ func String(l int) string {
var sb strings.Builder
sb.Grow(l)
for i := 0; i < l; i++ {
for range l {
sb.WriteByte(randomCharset[defaultSecureRand.Intn(len(randomCharset))])
}
return sb.String()

View File

@@ -144,7 +144,7 @@ func (p *Process) Stop() (*os.ProcessState, error) {
default:
}
if _, err := p.Post("/rest/system/shutdown", nil); err != nil && err != io.ErrUnexpectedEOF {
if _, err := p.Post("/rest/system/shutdown", nil); err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
// Unexpected EOF is somewhat expected here, as we may exit before
// returning something sensible.
return nil, err
@@ -173,12 +173,12 @@ func (p *Process) Get(path string) ([]byte, error) {
}
url := fmt.Sprintf("http://%s%s", p.addr, path)
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", APIKey)
req.Header.Add("X-Api-Key", APIKey)
resp, err := client.Do(req)
if err != nil {
@@ -198,12 +198,12 @@ func (p *Process) Post(path string, data io.Reader) ([]byte, error) {
},
}
url := fmt.Sprintf("http://%s%s", p.addr, path)
req, err := http.NewRequest("POST", url, data)
req, err := http.NewRequest(http.MethodPost, url, data)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", APIKey)
req.Header.Add("X-Api-Key", APIKey)
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
@@ -397,7 +397,7 @@ func (*Process) readResponse(resp *http.Response) ([]byte, error) {
if err != nil {
return bs, err
}
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
return bs, errors.New(resp.Status)
}
return bs, nil

View File

@@ -38,6 +38,7 @@ func NewClient(uri *url.URL, certs []tls.Certificate, timeout time.Duration) (Re
type commonClient struct {
svcutil.ServiceWithError
invitations chan protocol.SessionInvitation
}

View File

@@ -48,7 +48,7 @@ func (c *dynamicClient) serve(ctx context.Context) error {
l.Debugln(c, "looking up dynamic relays")
req, err := http.NewRequestWithContext(ctx, "GET", uri.String(), nil)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
if err != nil {
l.Debugln(c, "failed to lookup dynamic relays", err)
return err

View File

@@ -5,6 +5,7 @@ package client
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/url"
@@ -132,12 +133,13 @@ func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep
}()
defer cancel()
for i := 0; i < times; i++ {
for range times {
_, err = GetInvitationFromRelay(ctx, uri, id, certs, timeout)
if err == nil {
return nil
}
if _, ok := err.(*incorrectResponseCodeErr); !ok {
incorrectResponseCodeErr := &incorrectResponseCodeErr{}
if errors.As(err, &incorrectResponseCodeErr) {
return fmt.Errorf("getting invitation: %w", err)
}
time.Sleep(sleep)

View File

@@ -84,7 +84,7 @@ func newParallelHasher(ctx context.Context, folderID string, fs fs.Filesystem, w
}
ph.wg.Add(workers)
for i := 0; i < workers; i++ {
for range workers {
go ph.hashFiles(ctx)
}

View File

@@ -681,9 +681,10 @@ func (w *walker) String() string {
// A byteCounter gets bytes added to it via Update() and then provides the
// Total() and one minute moving average Rate() in bytes per second.
type byteCounter struct {
total atomic.Int64
metrics.EWMA
stop chan struct{}
total atomic.Int64
stop chan struct{}
}
func newByteCounter() *byteCounter {

View File

@@ -14,9 +14,9 @@ import (
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
@@ -135,7 +135,7 @@ func hashReader(r io.Reader) ([]byte, error) {
if _, err := io.Copy(h, r); err != nil {
return nil, err
}
hash := []byte(fmt.Sprintf("%x", h.Sum(nil)))
hash := []byte(hex.EncodeToString(h.Sum(nil)))
return hash, nil
}

View File

@@ -93,7 +93,7 @@ func FillNil(data any) {
func fillNil(data any, skipDeprecated bool) {
s := reflect.ValueOf(data).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
for i := range s.NumField() {
if skipDeprecated && strings.HasPrefix(t.Field(i).Name, "Deprecated") {
continue
}
@@ -123,7 +123,7 @@ func fillNil(data any, skipDeprecated bool) {
if f.Type().Elem().Kind() != reflect.Struct {
continue
}
for i := 0; i < f.Len(); i++ {
for i := range f.Len() {
fillNil(f.Index(i).Addr().Interface(), skipDeprecated)
}
case reflect.Struct:
@@ -142,7 +142,7 @@ func FillNilSlices(data any) error {
s := reflect.ValueOf(data).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
for i := range s.NumField() {
f := s.Field(i)
tag := t.Field(i).Tag

View File

@@ -1,64 +0,0 @@
// Copyright (C) 2019 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 stun
import (
"bytes"
"net"
"sync"
"time"
)
const (
stunFilterPriority = 10
otherDataPriority = 100
)
type stunFilter struct {
ids map[string]time.Time
mut sync.Mutex
}
func (f *stunFilter) Outgoing(out []byte, _ net.Addr) {
if !f.isStunPayload(out) {
panic("not a stun payload")
}
f.mut.Lock()
f.ids[string(out[8:20])] = time.Now().Add(time.Minute)
f.reap()
f.mut.Unlock()
}
func (f *stunFilter) ClaimIncoming(in []byte, _ net.Addr) bool {
if f.isStunPayload(in) {
f.mut.Lock()
_, ok := f.ids[string(in[8:20])]
f.reap()
f.mut.Unlock()
return ok
}
return false
}
func (*stunFilter) isStunPayload(data []byte) bool {
// Need at least 20 bytes
if len(data) < 20 {
return false
}
// First two bits always unset, and should always send magic cookie.
return data[0]&0xc0 == 0 && bytes.Equal(data[4:8], []byte{0x21, 0x12, 0xA4, 0x42})
}
func (f *stunFilter) reap() {
now := time.Now()
for id, timeout := range f.ids {
if timeout.Before(now) {
delete(f.ids, id)
}
}
}

View File

@@ -45,7 +45,7 @@ func (m *Internals) SetIgnores(folderID string, content []string) error {
}
func (m *Internals) DownloadBlock(ctx context.Context, deviceID protocol.DeviceID, folderID string, path string, blockNumber int, blockInfo protocol.BlockInfo, allowFromTemporary bool) ([]byte, error) {
return m.model.RequestGlobal(ctx, deviceID, folderID, path, int(blockNumber), blockInfo.Offset, blockInfo.Size, blockInfo.Hash, allowFromTemporary)
return m.model.RequestGlobal(ctx, deviceID, folderID, path, blockNumber, blockInfo.Offset, blockInfo.Size, blockInfo.Hash, allowFromTemporary)
}
func (m *Internals) BlockAvailability(folderID string, file protocol.FileInfo, block protocol.BlockInfo) ([]model.Availability, error) {

View File

@@ -200,6 +200,7 @@ func NewCertificateInMemory(commonName string, lifetimeDays int) (tls.Certificat
type DowngradingListener struct {
net.Listener
TLSConfig *tls.Config
}
@@ -208,7 +209,7 @@ func (l *DowngradingListener) Accept() (net.Conn, error) {
// We failed to identify the socket type, pretend that everything is fine,
// and pass it to the underlying handler, and let them deal with it.
if err == ErrIdentificationFailed {
if errors.Is(err, ErrIdentificationFailed) {
return conn, nil
}
@@ -244,9 +245,10 @@ func (l *DowngradingListener) AcceptNoWrapTLS() (net.Conn, bool, error) {
}
type UnionedConnection struct {
net.Conn
first [1]byte
firstDone bool
net.Conn
}
func (c *UnionedConnection) Read(b []byte) (n int, err error) {

View File

@@ -119,7 +119,7 @@ func CompareVersions(a, b string) Relation {
}
// First compare major-minor-patch versions
for i := 0; i < minlen; i++ {
for i := range minlen {
if arel[i] < brel[i] {
if i == 0 {
// major version difference
@@ -168,7 +168,7 @@ func CompareVersions(a, b string) Relation {
}
// Compare prerelease strings
for i := 0; i < minlen; i++ {
for i := range minlen {
switch av := apre[i].(type) {
case int:
switch bv := bpre[i].(type) {

View File

@@ -222,7 +222,7 @@ func upgradeToURL(archiveName, binary string, url string) error {
func readRelease(archiveName, dir, url string) (string, error) {
l.Debugf("loading %q", url)
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return "", err
}
@@ -254,15 +254,9 @@ func readTarGz(archiveName, dir string, r io.Reader) (string, error) {
var sig []byte
// Iterate through the files in the archive.
i := 0
for {
if i >= maxArchiveMembers {
break
}
i++
for range maxArchiveMembers {
hdr, err := tr.Next()
if err == io.EOF {
if errors.Is(err, io.EOF) {
// end of tar archive
break
}

View File

@@ -56,8 +56,6 @@ type IGDService struct {
URN string
LocalIPv4 net.IP
Interface *net.Interface
nat.Service
}
// AddPinhole adds an IPv6 pinhole in accordance to http://upnp.org/specs/gw/UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf
@@ -134,11 +132,12 @@ func (s *IGDService) AddPinhole(ctx context.Context, protocol nat.Protocol, intA
func (s *IGDService) tryAddPinholeForIP6(ctx context.Context, protocol nat.Protocol, port int, duration time.Duration, ip net.IP) error {
var protoNumber int
if protocol == nat.TCP {
switch protocol {
case nat.TCP:
protoNumber = 6
} else if protocol == nat.UDP {
case nat.UDP:
protoNumber = 17
} else {
default:
return errors.New("protocol not supported")
}
@@ -260,11 +259,12 @@ func (s *IGDService) GetLocalIPv4Address() net.IP {
// SupportsIPVersion checks whether this is a WANIPv6FirewallControl device,
// in which case pinholing instead of port mapping should be done
func (s *IGDService) SupportsIPVersion(version nat.IPVersion) bool {
if version == nat.IPvAny {
switch version {
case nat.IPvAny:
return true
} else if version == nat.IPv6Only {
case nat.IPv6Only:
return s.URN == urnWANIPv6FirewallControlV1
} else if version == nat.IPv4Only {
case nat.IPv4Only:
return s.URN != urnWANIPv6FirewallControlV1
}

View File

@@ -86,7 +86,7 @@ type UnsupportedDeviceTypeError struct {
}
func (e *UnsupportedDeviceTypeError) Error() string {
return fmt.Sprintf("Unsupported UPnP device of type %s", e.deviceType)
return "unsupported UPnP device of type " + e.deviceType
}
const (
@@ -229,7 +229,8 @@ USER-AGENT: syncthing/%s
_, err = socket.WriteTo(search, &ssdp)
if err != nil {
if e, ok := err.(net.Error); !ok || !e.Timeout() {
var e net.Error
if !errors.As(err, &e) || !e.Timeout() {
l.Debugln("UPnP discovery: sending search request:", err)
}
return
@@ -578,7 +579,7 @@ func soapRequestWithIP(ctx context.Context, url, service, function, message stri
body := fmt.Sprintf(template, message)
req, err := http.NewRequestWithContext(ctx, "POST", url, strings.NewReader(body))
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(body))
if err != nil {
return resp, err
}

View File

@@ -249,7 +249,7 @@ func clear(v interface{}, since int) error {
s := reflect.ValueOf(v).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
for i := range s.NumField() {
f := s.Field(i)
tag := t.Field(i).Tag

View File

@@ -41,6 +41,7 @@ var (
type FailureReport struct {
FailureData
Count int
Version string
}

View File

@@ -89,10 +89,10 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
if err != nil {
return nil, err
}
totFiles += int(global.Files)
totFiles += global.Files
totBytes += global.Bytes
if int(global.Files) > maxFiles {
maxFiles = int(global.Files)
if global.Files > maxFiles {
maxFiles = global.Files
}
if global.Bytes > maxBytes {
maxBytes = global.Bytes
@@ -366,7 +366,7 @@ func (s *Service) sendUsageReport(ctx context.Context) error {
},
},
}
req, err := http.NewRequestWithContext(ctx, "POST", s.cfg.Options().URURL, &b)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, s.cfg.Options().URURL, &b)
if err != nil {
return err
}
@@ -436,7 +436,7 @@ func CpuBench(ctx context.Context, iterations int, duration time.Duration) float
r.Read(bs)
var perf float64
for i := 0; i < iterations; i++ {
for range iterations {
if v := cpuBenchOnce(ctx, duration, bs); v > perf {
perf = v
}

View File

@@ -101,8 +101,9 @@ func (v external) Archive(filePath string) error {
combinedOutput, err := cmd.CombinedOutput()
l.Debugln("external command output:", string(combinedOutput))
if err != nil {
if eerr, ok := err.(*exec.ExitError); ok && len(eerr.Stderr) > 0 {
return fmt.Errorf("%v: %v", err, string(eerr.Stderr))
eerr := &exec.ExitError{}
if errors.As(err, &eerr) && len(eerr.Stderr) > 0 {
return fmt.Errorf("%w: %v", err, string(eerr.Stderr))
}
return err
}

View File

@@ -55,6 +55,7 @@ func New(cfg config.FolderConfiguration) (Versioner, error) {
type versionerWithErrorContext struct {
Versioner
vtype string
}

View File

@@ -449,10 +449,11 @@ func (a *aggregator) updateConfig(folderCfg config.FolderConfiguration) {
}
func updateInProgressSet(event events.Event, inProgress map[string]struct{}) {
if event.Type == events.ItemStarted {
switch event.Type {
case events.ItemStarted:
path := event.Data.(map[string]string)["item"]
inProgress[path] = struct{}{}
} else if event.Type == events.ItemFinished {
case events.ItemFinished:
path := event.Data.(map[string]interface{})["item"].(string)
delete(inProgress, path)
}

View File

@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "STDISCOSRV" "1" "Sep 14, 2025" "v2.0.0" "Syncthing"
.TH "STDISCOSRV" "1" "Oct 23, 2025" "v2.0.0" "Syncthing"
.SH NAME
stdiscosrv \- Syncthing Discovery Server
.SH SYNOPSIS

Some files were not shown because too many files have changed in this diff Show More