Compare commits

...

56 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
Jakob Borg
6f0acacbd2 fix(sqlite): actually always insert blocks for local files (fixes #10388) (#10411)
Due to a thinko, this optimisation was wildly incorrect and would read
to lack of block reuse when syncing files.

(We do not insert a blocklist per device, but only a single one. We
can't use the fact of whether the insert happened as a criteria for
inserting blocks.)

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-23 12:46:31 +00:00
Jakob Borg
932b4ce9bd fix(model): don't announce untrusted devices to other devices (fixes #10393) (#10408)
fix(model): don't announce untrusted devices to other devices

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-23 13:16:58 +02:00
mrclmr
b3e3ca7294 build: update GitHub actions (#10399) 2025-09-22 08:50:09 +03:00
Syncthing Release Automation
41b4c5cd5e chore(gui, man, authors): update docs, translations, and contributors 2025-09-22 03:52:07 +00:00
Tommy van der Vorst
eb4eb7524d fix(syncthing): only perform CPU benchmark on startup when logging enabled, and on goroutine (#10398)
Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
Co-authored-by: bt90 <btom1990@googlemail.com>
2025-09-19 07:17:10 +02:00
Tommy van der Vorst
a64c5396e9 fix(db): only perform foreign key checking when a migration was applied (#10397) 2025-09-18 12:22:35 +00:00
Jakob Borg
5595113074 fix(gui): don't fetch usage report preview unnecessarily on GUI load (#10395)
IMHO the logic here was inverted. The only use for the report data is to
show a preview when we ask the user whether they want to participate in
usage reporting. However, the GUI would first load the report data and
then consider whether we wanted to show that dialog or not. Instead,
only load if it we're going to show the dialog.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-16 18:01:17 +02:00
Jakob Borg
ea19ec64bf fix(ur): properly skip zero/empty fields in report (#10394)
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-15 20:35:59 +00:00
Syncthing Release Automation
9de6c5ed69 chore(gui, man, authors): update docs, translations, and contributors 2025-09-15 03:52:28 +00:00
Jakob Borg
d037681fd1 fix: improve conflict detection by tracking previous file hash (fixes #10349) (#10351)
This adds a new field to the file information we keep, the "previous
blocks hash". This is the hash of the file contents as it was in its
previous incarnation. That is, every scan that updates the blocks hash
will move the current hash to the "previous" field.

This enables an addition to the conflict detection algorithm: if the
file to be synced is in conflict with the current file on disk
(version-counter wise), but it indicates that it was based on the
precise contents we have (new.prevBlocksHash == current.blocksHash),
then it's not really a conflict.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-13 16:16:28 +02:00
Jakob Borg
1b0eaa093a chore(policy): increase power & responsibility for maintainers
This adds a rule where a maintainer can merge a PR on their own even in
non-trivial cases, which we (I) already do as-is today, but by breaking
the rules instead of following them. This just codifies that behavior.
If we get to a point where it's no longer necessary, that'd be cool.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-13 15:42:54 +02:00
Jakob Borg
3382ccc3f1 chore(model): slightly deflake TestRecvOnlyRevertOwnID (#10390)
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-12 09:41:47 +00:00
Jakob Borg
9ee208b441 chore(sqlite): use normalised tables for file names and versions (#10383)
This changes the files table to use normalisation for the names and
versions. The idea is that these are often common between all remote
devices, and repeating an integer is more efficient than repeating a
long string. A new benchmark bears this out; for a database with 100k
files shared between 31 devices, with some worst case assumption on
version vector size, the database is reduced in size by 50% and the test
finishes quicker:

    Current:
        db_bench_test.go:322: Total size: 6263.70 MiB
    --- PASS: TestBenchmarkSizeManyFilesRemotes (1084.89s)

    New:
        db_bench_test.go:326: Total size: 3049.95 MiB
    --- PASS: TestBenchmarkSizeManyFilesRemotes (776.97s)

The other benchmarks end up about the same within the margin of
variability, with one possible exception being that RemoteNeed seems to
be a little slower on average:

                                          old files/s   new files/s
    Update/n=RemoteNeed/size=1000-8            5.051k        4.654k
    Update/n=RemoteNeed/size=2000-8            5.201k        4.384k
    Update/n=RemoteNeed/size=4000-8            4.943k        4.242k
    Update/n=RemoteNeed/size=8000-8            5.099k        3.527k
    Update/n=RemoteNeed/size=16000-8           3.686k        3.847k
    Update/n=RemoteNeed/size=30000-8           4.456k        3.482k

I'm not sure why, possibly that query can be optimised anyhow.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-12 09:27:41 +00:00
Jakob Borg
dd90e8ec7a fix(api): limit size of allowed authentication request (#10386)
We have a slightly naive io.ReadAll on the authentication handler, which
can result in unlimited memory consumption from an unauthenticated API
endpoint. Add a reasonable limit there.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-11 10:11:29 +00:00
Jakob Borg
aa6ae0f3b0 fix(sqlite): add _txlock=immediate to modernc implementation (#10384)
For symmetry with the CGO variant.

https://pkg.go.dev/modernc.org/sqlite#Driver.Open

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-11 06:16:31 +00:00
Jakob Borg
e8b256793a chore: clean up migrated database (#10381)
Remove the migrated v0.14.0 database format after two weeks. Remove a
few old patterns that are no longer relevant. Ensure the cleanup runs in
both the config and database directories.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-10 12:23:35 +02:00
Catfriend1
8233279a65 chore(ursrv): update regex patterns for Syncthing-Fork entries (#10380)
Update regex patterns for Syncthing-Fork entries

Signed-off-by: Catfriend1 <16361913+Catfriend1@users.noreply.github.com>
2025-09-09 14:34:12 +02:00
Jakob Borg
8e5d5802cc chore(ursrv): calculate more fine-grained percentiles
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-09 07:37:39 +02:00
Jakob Borg
25ae01b0d7 chore(sqlite): skip database GC entirely when it's provably unnecessary (#10379)
Store the sequence number of the last GC sweep in a KV. Next time, if it
matches we can just skip GC because nothing has been added or removed.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-08 08:55:04 +02:00
Syncthing Release Automation
66583927f8 chore(gui, man, authors): update docs, translations, and contributors 2025-09-08 03:52:21 +00:00
Simon Frei
f0328abeaa chore(scanner): always return values to the pools when hashing blocks (#10377)
There are some return statements in between, but putting back the values
isn't my motivation (hardly ever happens), I just find this more
readable. Same with moving `hashLength`: Placed next to the pool the
connection with `sha256.New()` is closer.

Followup to:
chore(scanner): reduce memory pressure by using pools inside hasher #10222
6e26fab3a0

Signed-off-by: Simon Frei <freisim93@gmail.com>
2025-09-07 17:00:19 +02:00
Jakob Borg
4b8d07d91c fix(sqlite): explicitly set temporary directory location (fixes #10368) (#10376)
On Unixes, avoid the /tmp which is likely to become the chosen default.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-07 14:04:47 +02:00
Jakob Borg
c33daca3b4 fix(sqlite): less impactful periodic garbage collection (#10374)
Periodic garbage collection can take a long time on large folders. The worst
step is the one for blocks, which are typically orders of magnitude more
numerous than files or block lists.

This improves the situation in by running blocks GC in a number of smaller
range chunks, in random order, and stopping after a time limit. At most ten
minutes per run will be spent garbage collecting blocklists and blocks.

With this, we're not guaranteed to complete a full GC on every run, but
we'll make some progress and get there eventually.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-07 14:04:29 +02:00
Amin Vakil
a533f453f8 build: trigger nightly build only on syncthing repo (#10375)
Signed-off-by: Amin Vakil <info@aminvakil.com>
2025-09-07 14:03:33 +02:00
Jakob Borg
3c9e87d994 build: exclude illumos from cross building
Now that we have a native build for it.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-05 11:51:15 +02:00
Jakob Borg
f0180cb014 fix(sqlite): avoid rowid on kv table (#10367)
No migration on this as it has no practical impact, just a slight
cleanup for new installations.

Also a refactor of how we declare single column primary keys, for
consistency.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-05 09:31:07 +00:00
Jakob Borg
a99a730c0c fix(tlsutil): support HTTP/2 on GUI/API connections (#10366)
By not setting ALPN we were implicitly rejecting HTTP/2, completely
unnecessarily.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-05 10:57:39 +02:00
Jakob Borg
36254473a3 chore(slogutil): add configurable logging format (fixes #10352) (#10354)
This adds several options for configuring the log format of timestamps
and severity levels, making it more suitable for integration with log
systems like systemd.

      --log-format-timestamp="2006-01-02 15:04:05"
         Format for timestamp, set to empty to disable timestamps ($STLOGFORMATTIMESTAMP)

      --[no-]log-format-level-string
         Whether to include level string in log line ($STLOGFORMATLEVELSTRING)

      --[no-]log-format-level-syslog
         Whether to include level as syslog prefix in log line ($STLOGFORMATLEVELSYSLOG)

So, to get a timestamp suitable for systemd (syslog prefix, no level
string, no timestamp) we can pass `--log-format-timestamp=""
--no-log-format-level-string --log-format-level-syslog` or,
equivalently, set `STLOGFORMATTIMESTAMP="" STLOGFORMATLEVELSTRING=false
STLOGFORMATLEVELSYSLOG=true`.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-05 10:52:49 +02:00
Jakob Borg
800596139e chore(sqlite): stamp files with application_id
No practical effect, just a tiny bit of fun to stamp the database files
with an application ID that identifies them.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 23:15:38 +02:00
Jakob Borg
f48782e4df fix(sqlite): revert to default page cache size (#10362)
While we're figuring out optimal defaults, reduce the page cache size to
the compiled-in default. In my computer this makes no difference in
benchmarks. In forum threads, it solved the problem of massive memory
usage during initial scan.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 23:07:51 +02:00
Jakob Borg
922cc7544e docs: we now do binaries for illumos again
Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 21:38:30 +02:00
Tommy van der Vorst
9e262d84de fix(api): redact device encryption passwords in support bundle config (#10359)
* fix(api): redact device encryption passwords in support bundle config

Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>

* Update lib/api/support_bundle.go

Signed-off-by: Jakob Borg <jakob@kastelo.net>

---------

Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
Signed-off-by: Jakob Borg <jakob@kastelo.net>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 18:22:59 +00:00
Jakob Borg
42db6280e6 fix(model): earlier free-space check (fixes #10347) (#10348)
Since #10332 we'd create the temp file when closing out the puller state
for a file, but this is inappropriate if the reason we're bailing out is
that there isn't space for it to begin with. Instead, do the
free space check before we even start copying/pulling.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 16:53:30 +00:00
Albert Lee
8d8adae310 build: package for illumos using vmactions/omnios-vm (#10328)
Use GitHub Actions to build illumos/amd64 package.

Signed-off-by: Albert Lee <trisk@forkgnu.org>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 08:51:44 +00:00
Jakob Borg
12ba4b6aea chore(model): adjust folder state logging (fixes #10350) (#10353)
Removes the chitter-chatter of folder state changes from the info level,
while adding the error state at warning level and a corresponding
clearing of the error state at info level.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-04 07:38:06 +00:00
Jakob Borg
372e3c26b0 fix(db): remove temp_store = MEMORY pragmas (#10343)
This reduces database migration memory usage in my test scenario from
3.8 GB to 440 MB. In principle I don't think we're causing many temp
tables to be generated anyway in normal usage, but if we do and someone
can benchmark a performance difference, we can add a tunable. I ran the
database benchmark before and after and didn't see a difference above
the noise level.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-03 09:27:53 +02:00
Jakob Borg
01e2426a56 fix(syncthing): properly report kibibytes RSS in Linux perfstats
The value from getrusage is already in KiB, while on macOS it's in
bytes.

Signed-off-by: Jakob Borg <jakob@kastelo.net>
2025-09-03 07:52:19 +02:00
169 changed files with 2004 additions and 1173 deletions

View File

@@ -30,11 +30,11 @@ jobs:
- stupgrades
- ursrv
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
check-latest: true

View File

@@ -51,12 +51,12 @@ jobs:
release-generation: ${{ steps.get-version.outputs.release-generation }}
go-version: ${{ steps.get-go.outputs.go-version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
cache: false
@@ -116,9 +116,9 @@ jobs:
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
cache: true
@@ -159,6 +159,7 @@ jobs:
needs:
- build-test
- package-linux
- package-illumos
- package-cross
- package-source
- package-debian
@@ -167,7 +168,7 @@ jobs:
- golangci
- meta
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
#
# Windows
@@ -182,9 +183,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -291,9 +292,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -337,6 +338,39 @@ jobs:
*.tar.gz
compat.json
package-illumos:
runs-on: ubuntu-latest
name: Package for illumos
needs:
- facts
env:
VERSION: ${{ needs.facts.outputs.version }}
GO_VERSION: ${{ needs.facts.outputs.go-version }}
steps:
- uses: actions/checkout@v5
- name: Build syncthing in OmniOS VM
uses: vmactions/omnios-vm@v1
with:
envs: "VERSION GO_VERSION CGO_ENABLED"
usesh: true
prepare: |
pkg install developer/gcc14 web/curl archiver/gnu-tar
run: |
curl -L "https://go.dev/dl/go$GO_VERSION.illumos-amd64.tar.gz" | gtar xzf -
export PATH="$GITHUB_WORKSPACE/go/bin:$PATH"
go version
for tgt in syncthing stdiscosrv strelaysrv ; do
go run build.go -tags "${{env.TAGS}}" tar "$tgt"
done
env:
CGO_ENABLED: "1"
- name: Archive artifacts
uses: actions/upload-artifact@v4
with:
name: packages-illumos
path: "*.tar.gz"
#
# macOS. The entire build runs in the release environment because code
# signing is part of the build process, so it is limited to release
@@ -355,9 +389,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -483,9 +517,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -503,6 +537,7 @@ jobs:
| grep -v aix/ppc64 \
| grep -v android/ \
| grep -v darwin/ \
| grep -v illumos/ \
| grep -v ios/ \
| grep -v js/ \
| grep -v linux/ \
@@ -549,9 +584,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -588,6 +623,7 @@ jobs:
needs:
- codesign-windows
- package-linux
- package-illumos
- package-macos
- package-cross
- package-source
@@ -597,9 +633,9 @@ jobs:
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
repository: syncthing/release-tools
path: tools
@@ -607,7 +643,7 @@ jobs:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -678,9 +714,9 @@ jobs:
VERSION: ${{ needs.facts.outputs.version }}
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -734,7 +770,7 @@ jobs:
- facts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
repository: syncthing/release-tools
path: tools
@@ -745,7 +781,7 @@ jobs:
name: packages-signed
path: packages
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -789,7 +825,7 @@ jobs:
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
@@ -806,7 +842,7 @@ jobs:
name: debian-packages
path: packages
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -968,9 +1004,9 @@ jobs:
dockerfile: Dockerfile.stdiscosrv
image: discosrv
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -1063,7 +1099,7 @@ jobs:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Sync images
uses: docker://docker.io/regclient/regsync:latest
with:
@@ -1081,9 +1117,9 @@ jobs:
needs:
- facts
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: ${{ needs.facts.outputs.go-version }}
cache: false
@@ -1103,8 +1139,8 @@ jobs:
name: Run golangci-lint
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: 'stable'
@@ -1124,8 +1160,8 @@ jobs:
name: Run meta checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: 'stable'

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

@@ -15,13 +15,13 @@ jobs:
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: stable

View File

@@ -8,11 +8,12 @@ on:
jobs:
trigger-nightly:
if: github.repository_owner == 'syncthing'
runs-on: ubuntu-latest
name: Push to release-nightly to trigger build
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
fetch-depth: 0

View File

@@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-latest
name: Update translations and documentation
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: stable
- run: |

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

@@ -8,17 +8,20 @@
policy:
approval:
- subject is conventional commit
- project metadata requires maintainer approval
- or:
- project metadata requires maintainer approval
- a maintainer claims responsibility
- or:
- is approved by a syncthing contributor
- is a translation or dependency update by a contributor
- is a trivial change by a contributor
- a maintainer claims responsibility
# Additionally, contributors can disapprove of a PR
# Additionally, maintainers can disapprove of a PR
disapproval:
requires:
teams:
- syncthing/contributors
- syncthing/maintainers
# The rules for the policy are described below.
@@ -49,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
@@ -59,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
@@ -96,3 +99,13 @@ approval_rules:
has_author_in:
teams:
- syncthing/contributors
# A member of the maintainers group can take responsibility by adding the
# appropriate label.
- name: a maintainer claims responsibility
if:
has_labels:
- maintainer-responsibility
has_author_in:
teams:
- syncthing/maintainers

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

@@ -8,6 +8,7 @@ package serve
import (
"context"
"fmt"
"log/slog"
"reflect"
"slices"
@@ -46,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)
@@ -174,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)
@@ -335,12 +336,12 @@ func (q *metricSummary) Collect(c chan<- prometheus.Metric) {
}
slices.Sort(vs)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[0], append(labelVals, "0")...)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[len(vs)*5/100], append(labelVals, "0.05")...)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[len(vs)/2], append(labelVals, "0.5")...)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[len(vs)*9/10], append(labelVals, "0.9")...)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[len(vs)*95/100], append(labelVals, "0.95")...)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[len(vs)-1], append(labelVals, "1")...)
pctiles := []float64{0, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.975, 0.99, 1}
for _, pct := range pctiles {
idx := int(float64(len(vs)-1) * pct)
c <- prometheus.MustNewConstMetric(q.qDesc, prometheus.GaugeValue, vs[idx], append(labelVals, fmt.Sprint(pct))...)
}
}
}

View File

@@ -79,7 +79,8 @@ var (
{regexp.MustCompile(`\svagrant@bullseye`), "F-Droid"},
{regexp.MustCompile(`\svagrant@bookworm`), "F-Droid"},
{regexp.MustCompile(`Anwender@NET2017`), "Syncthing-Fork (3rd party)"},
{regexp.MustCompile(`\sreproducible-build@Catfriend1-syncthing-android`), "Syncthing-Fork Catfriend1 (3rd party)"},
{regexp.MustCompile(`\sreproducible-build@nel0x-syncthing-android-gplay`), "Syncthing-Fork nel0x (3rd party)"},
{regexp.MustCompile(`\sbuilduser@(archlinux|svetlemodry)`), "Arch (3rd party)"},
{regexp.MustCompile(`\ssyncthing@archlinux`), "Arch (3rd party)"},

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

@@ -164,6 +164,9 @@ type serveCmd struct {
LogLevel slog.Level `help:"Log level for all packages (DEBUG,INFO,WARN,ERROR)" env:"STLOGLEVEL" default:"INFO"`
LogMaxFiles int `name:"log-max-old-files" help:"Number of old files to keep (zero to keep only current)" default:"${logMaxFiles}" placeholder:"N" env:"STLOGMAXOLDFILES"`
LogMaxSize int `help:"Maximum size of any file (zero to disable log rotation)" default:"${logMaxSize}" placeholder:"BYTES" env:"STLOGMAXSIZE"`
LogFormatTimestamp string `name:"log-format-timestamp" help:"Format for timestamp, set to empty to disable timestamps" env:"STLOGFORMATTIMESTAMP" default:"${timestampFormat}"`
LogFormatLevelString bool `name:"log-format-level-string" help:"Whether to include level string in log line" env:"STLOGFORMATLEVELSTRING" default:"${levelString}" negatable:""`
LogFormatLevelSyslog bool `name:"log-format-level-syslog" help:"Whether to include level as syslog prefix in log line" env:"STLOGFORMATLEVELSYSLOG" default:"${levelSyslog}" negatable:""`
NoBrowser bool `help:"Do not start browser" env:"STNOBROWSER"`
NoPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup" env:"STNOPORTPROBING"`
NoRestart bool `help:"Do not restart Syncthing when exiting due to API/GUI command, upgrade, or crash" env:"STNORESTART"`
@@ -186,10 +189,13 @@ type serveCmd struct {
}
func defaultVars() kong.Vars {
vars := kong.Vars{}
vars["logMaxSize"] = strconv.Itoa(10 << 20) // 10 MiB
vars["logMaxFiles"] = "3" // plus the current one
vars := kong.Vars{
"logMaxSize": strconv.Itoa(10 << 20), // 10 MiB
"logMaxFiles": "3", // plus the current one
"levelString": strconv.FormatBool(slogutil.DefaultLineFormat.LevelString),
"levelSyslog": strconv.FormatBool(slogutil.DefaultLineFormat.LevelSyslog),
"timestampFormat": slogutil.DefaultLineFormat.TimestampFormat,
}
// On non-Windows, we explicitly default to "-" which means stdout. On
// Windows, the "default" options.logFile will later be replaced with the
@@ -262,8 +268,14 @@ func (c *serveCmd) Run() error {
osutil.HideConsole()
}
// The default log level for all packages
// Customize the logging early
slogutil.SetLineFormat(slogutil.LineFormat{
TimestampFormat: c.LogFormatTimestamp,
LevelString: c.LogFormatLevelString,
LevelSyslog: c.LogFormatLevelSyslog,
})
slogutil.SetDefaultLevel(c.LogLevel)
slogutil.SetLevelOverrides(os.Getenv("STTRACE"))
// Treat an explicitly empty log file name as no log file
if c.LogFile == "" {
@@ -376,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,
@@ -395,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
@@ -517,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))
@@ -647,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
@@ -708,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
}
@@ -769,40 +783,39 @@ func initialAutoUpgradeCheck(misc *db.Typed) (upgrade.Release, error) {
// suitable time after they have gone out of fashion.
func cleanConfigDirectory() {
patterns := map[string]time.Duration{
"panic-*.log": 7 * 24 * time.Hour, // keep panic logs for a week
"audit-*.log": 7 * 24 * time.Hour, // keep audit logs for a week
"index": 14 * 24 * time.Hour, // keep old index format for two weeks
"index-v0.11.0.db": 14 * 24 * time.Hour, // keep old index format for two weeks
"index-v0.13.0.db": 14 * 24 * time.Hour, // keep old index format for two weeks
"index*.converted": 14 * 24 * time.Hour, // keep old converted indexes for two weeks
"config.xml.v*": 30 * 24 * time.Hour, // old config versions for a month
"*.idx.gz": 30 * 24 * time.Hour, // these should for sure no longer exist
"backup-of-v0.8": 30 * 24 * time.Hour, // these neither
"tmp-index-sorter.*": time.Minute, // these should never exist on startup
"support-bundle-*": 30 * 24 * time.Hour, // keep old support bundle zip or folder for a month
"csrftokens.txt": 0, // deprecated, remove immediately
"panic-*.log": 7 * 24 * time.Hour, // keep panic logs for a week
"audit-*.log": 7 * 24 * time.Hour, // keep audit logs for a week
"index-v0.14.0.db-migrated": 14 * 24 * time.Hour, // keep old index format for two weeks
"config.xml.v*": 30 * 24 * time.Hour, // old config versions for a month
"support-bundle-*": 30 * 24 * time.Hour, // keep old support bundle zip or folder for a month
}
for pat, dur := range patterns {
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, locations.GetBaseDir(locations.ConfigBaseDir))
files, err := fs.Glob(pat)
if err != nil {
slog.Warn("Failed to clean config directory", slogutil.Error(err))
continue
}
for _, file := range files {
info, err := fs.Lstat(file)
locations := slices.Compact([]string{
locations.GetBaseDir(locations.ConfigBaseDir),
locations.GetBaseDir(locations.DataBaseDir),
})
for _, loc := range locations {
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, loc)
for pat, dur := range patterns {
entries, err := fs.Glob(pat)
if err != nil {
slog.Warn("Failed to clean config directory", slogutil.Error(err))
continue
}
if time.Since(info.ModTime()) > dur {
if err = fs.RemoveAll(file); err != nil {
for _, entry := range entries {
info, err := fs.Lstat(entry)
if err != nil {
slog.Warn("Failed to clean config directory", slogutil.Error(err))
} else {
slog.Warn("Cleaned away old file", slogutil.FilePath(filepath.Base(file)))
continue
}
if time.Since(info.ModTime()) > dur {
if err = fs.RemoveAll(entry); err != nil {
slog.Warn("Failed to clean config directory", slogutil.Error(err))
} else {
slog.Warn("Cleaned away old file", slogutil.FilePath(filepath.Base(entry)))
}
}
}
}
@@ -825,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()
@@ -1039,7 +1053,7 @@ func (m migratingAPI) Serve(ctx context.Context) error {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("*** Database migration in progress ***\n\n"))
for _, line := range slogutil.GlobalRecorder.Since(time.Time{}) {
line.WriteTo(w)
_, _ = line.WriteTo(w, slogutil.DefaultLineFormat)
}
}),
}

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

@@ -16,7 +16,9 @@ import (
"syscall"
"time"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"golang.org/x/exp/constraints"
)
@@ -48,14 +50,19 @@ func savePerfStats(file string) {
in, out := protocol.TotalInOut()
timeDiff := t.Sub(prevTime)
rss := curRus.Maxrss
if build.IsDarwin {
rss /= 1024
}
fmt.Fprintf(fd, "%.03f\t%f\t%d\t%d\t%.0f\t%.0f\t%d\n",
t.Sub(t0).Seconds(),
rate(cpusec(&prevRus), cpusec(&curRus), timeDiff, 1),
(curMem.Sys-curMem.HeapReleased)/1024,
curRus.Maxrss/1024,
rss,
rate(prevIn, in, timeDiff, 1e3),
rate(prevOut, out, timeDiff, 1e3),
dirsize(locations.Get(locations.Database))/1024,
osutil.DirSize(locations.Get(locations.Database))/1024,
)
prevTime = t
@@ -78,21 +85,3 @@ func rate[T number](prev, cur T, d time.Duration, div float64) float64 {
rate := float64(diff) / d.Seconds() / div
return rate
}
func dirsize(location string) int64 {
entries, err := os.ReadDir(location)
if err != nil {
return 0
}
var size int64
for _, entry := range entries {
fi, err := entry.Info()
if err != nil {
continue
}
size += fi.Size()
}
return size
}

View File

@@ -7,6 +7,9 @@ StartLimitBurst=4
[Service]
User=%i
Environment="STLOGFORMATTIMESTAMP="
Environment="STLOGFORMATLEVELSTRING=false"
Environment="STLOGFORMATLEVELSYSLOG=true"
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart
Restart=on-failure
RestartSec=1

View File

@@ -5,7 +5,10 @@ StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
Environment="STLOGFORMATTIMESTAMP="
Environment="STLOGFORMATLEVELSTRING=false"
Environment="STLOGFORMATLEVELSYSLOG=true"
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4

View File

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

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Дазволеныя Сеткі",
"Alphabetic": "Па Алфавіту",
"Altered by ignoring deletes.": "Зменена з-за ігнаравання выдаленняў.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Заўсёды ўключана для папак з тыпам \"{{foldertype}}\".",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Знешняя каманда утрымлівае версіянаванне. Яно патрабуе выдалення файла з агульнай дырэкторыі. Калі шлях да прыкладання ўтрымлівае прабелы, трэба іх выдаліць.",
"Anonymous Usage Reporting": "Ананімная Спрадвыздача Аб Выкарыстанні",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Фармат ананімнай спрадвыздачы аб выкарыстанні быў зменены. Ці жадаеце вы выкарыстоўваць новы фармат?",

View File

@@ -177,7 +177,7 @@
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Вида „{{receiveEncrypted}}“ може да бъде избран само при добавяне на папка.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Видът папката „{{receiveEncrypted}}“ не може да бъде променян след нейното създаване. Трябва да я премахнете, изтриете или разшифровате съдържанието и да добавите папката отново.",
"Folders": "Папки",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Грешка при започване на наблюдението за промени на следните папки. Всяка минута ще бъде извършван нов опит, така че грешката скоро може да изчезне. Ако все пак не изчезне, отстранете нейната първопричина или потърсете помощ ако не съумявате.",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Грешка при започване на наблюдението за промени на следните папки. Всяка минута ще бъде извършван нов опит, така че грешката скоро може да изчезне. Ако все пак не изчезне, отстранете първопричината или ако не съумявате потърсете помощ.",
"Forever": "Завинаги",
"Full Rescan Interval (s)": "Интервал на пълно обхождане (секунди)",
"GUI": "Интерфейс",

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

@@ -27,6 +27,7 @@
"Allowed Networks": "Redes permitidas",
"Alphabetic": "Alfabético",
"Altered by ignoring deletes.": "Alterado ignorando eliminaciones.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Siempre activado cuando el tipo de carpeta es \"{{foldertype}}\".",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Un comando externo maneja las versiones. Tienes que eliminar el archivo de la carpeta compartida. Si la ruta a la aplicación contiene espacios, ésta debe estar entre comillas.",
"Anonymous Usage Reporting": "Informe anónimo de uso",
"Anonymous usage report format has changed. Would you like to move to the new format?": "El formato del informe de uso anónimo a cambiado. ¿Le gustaría pasar al nuevo formato?",
@@ -52,6 +53,7 @@
"Body:": "Contenido:",
"Bugs": "Errores",
"Cancel": "Cancelar",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "No se puede habilitar cuando el tipo de carpeta es \"{{foldertype}}\".",
"Changelog": "Registro de cambios",
"Clean out after": "Limpiar tras",
"Cleaning Versions": "Limpiando Versiones",
@@ -80,6 +82,7 @@
"Custom Range": "Rango personalizado",
"Danger!": "¡Peligro!",
"Database Location": "Ubicación de la base de datos",
"Debug": "Depurar",
"Debugging Facilities": "Servicios de depuración",
"Default": "Predeterminado",
"Default Configuration": "Configuración Predeterminada",
@@ -208,6 +211,7 @@
"Incoming Rate Limit (KiB/s)": "Límite de descarga (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configuración incorrecta puede corromper el contenido de la carpeta y poner a Syncthing en un estado inoperante.",
"Incorrect user name or password.": "Nombre de usuario o contraseña incorrectos.",
"Info": "Información",
"Internally used paths:": "Rutas de uso interno:",
"Introduced By": "Introducido por",
"Introducer": "Presentador",
@@ -225,6 +229,7 @@
"Learn more": "Saber más",
"Learn more at {%url%}": "Más información en {{url}}",
"Limit": "Límite",
"Limit Bandwidth in LAN": "Limitar el ancho de banda en LAN",
"Listener Failures": "Fallos de Oyente",
"Listener Status": "Estado de Oyente",
"Listeners": "Oyentes",

View File

@@ -1,6 +1,7 @@
{
"A device with that ID is already added.": "Sellise tunnusega seade on juba lisatud.",
"A negative number of days doesn't make sense.": "Negatiivne päevade arv ei ole loogiline.",
"A new major version may not be compatible with previous versions.": "Uus põhiversioon ei pruugi ühilduv varasemate versioonidega.",
"API Key": "API võti",
"About": "Rakenduse teave",
"Action": "Tegevus",
@@ -19,20 +20,34 @@
"Apply": "Rakenda",
"Automatic upgrades": "Automaatsed uuendused",
"Be careful!": "Ettevaatust!",
"Cancel": "Loobu",
"Changelog": "Muudatuste nimekiri",
"Bugs": "Vead",
"Cancel": "Katkesta",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kui kausta tüüp on „{{foldertype}}“, siis seda ei saa kasutada.",
"Changelog": "Muudatuste ajalugu",
"Close": "Sulge",
"Compression": "Pakkimine",
"Configuration Directory": "Seadistuste kaust",
"Configuration File": "Seadistuste fail",
"Configured": "Seadistatud",
"Connected (Unused)": "Ühendatud (pole kasutusel)",
"Connection Error": "Ühenduse viga",
"Connection Management": "Ühenduste haldus",
"Connection Type": "Ühenduse tüüp",
"Connections": "Ühendused",
"Copied from elsewhere": "Kopeeritud mujalt",
"Copied from original": "Kopeeritud algallikast",
"Copied!": "Kopeeritud!",
"Delete": "Kustuta",
"Device": "Seade",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Seade \"{{name}}\" ({{device}} aadressil {{address}}) soovib luua ühendust. Kas lisada uus seade?",
"Device ID": "Seadme ID",
"Device Certificate": "Seadme sertifikaat",
"Device ID": "Seadme tunnus",
"Device Identification": "Seadme tuvastamine",
"Device Name": "Seadme nimi",
"Devices": "Seadmed",
"Disconnected": "Ühendus puudub",
"Do not restore": "Ära taasta",
"Do not restore all": "Ära taasta kõiki",
"Documentation": "Dokumentatsioon",
"Download Rate": "Allalaadimise Kiirus",
"Downloaded": "Alla laetud",
@@ -55,33 +70,48 @@
"GUI Authentication User": "GUI Autentimise Kasutajatunnus",
"GUI Theme": "GUI Teema",
"Generate": "Genereeri",
"Global State": "Globaalne Olek",
"Help": "Abi",
"Global State": "Üldine olek",
"Help": "Abiteave",
"Ignore": "Ignoreeri",
"Ignore Patterns": "Ignoreeri Mustreid",
"Ignore Permissions": "Ignoreeri Õigusi",
"Incoming Rate Limit (KiB/s)": "Siseneva Kiiruse Piirang (KiB/s)",
"Ignored Devices": "Eiratud seadmed",
"Ignored Folders": "Eiratud kaustad",
"Incoming Rate Limit (KiB/s)": "Siseneva liikluse kiiruspiirang (KiB/s)",
"Keep Versions": "Säilita Versioone",
"LDAP": "LDAP",
"Largest First": "Suurim Enne",
"Last 30 Days": "Viimased 30 päeva",
"Last 7 Days": "Viimased 7 päeva",
"Last Month": "Viimane kuu",
"Last Scan": "Viimane skaneerimine",
"Last seen": "Viimati nähtud",
"Latest Change": "Viimane Muudatus",
"Learn more": "Veel infot",
"Learn more at {%url%}": "Lisateavet leiad siit: {{url}}",
"Local State": "Kohalik Olek",
"Local State (Total)": "Kohalik Olek (Summaarne)",
"Maximum Age": "Maksimaalne Vanus",
"Metadata Only": "Ainult Meta-andmed",
"Maximum Age": "Maksimaalne vanus",
"Maximum single entry size": "Maksimaalne ühe objekti maht",
"Maximum total size": "Maksimaalne kogumaht",
"Metadata Only": "Ainult metaandmed",
"Minimum Free Disk Space": "Minimaalne Vaba Kettaruum",
"More than a month ago": "Enam, kui kuu tagasi",
"More than a week ago": "Enam, kui nädal tagasi",
"More than a year ago": "Enam, kui aasta tagasi",
"Move to top of queue": "Liiguta järjekorra algusesse",
"Never": "Eikunagi",
"New Device": "Uus Seade",
"New Folder": "Uus Kaust",
"Newest First": "Uusimad Ennem",
"No": "Ei",
"Number of Connections": "Ühenduste arv",
"OK": "Sobib",
"Oldest First": "Vanimad Ennem",
"Options": "Valikud",
"Outgoing Rate Limit (KiB/s)": "Väljuva Kiiruse Piirang (KiB/s)",
"Out of Sync": "Pole sünkroonis",
"Out of Sync Items": "Sünkroonimata objektid",
"Outgoing Rate Limit (KiB/s)": "Väljuva kiiruse piirang (KiB/s)",
"Override Changes": "Kirjuta Muudatused Üle",
"Pause": "Peata",
"Pause All": "Peata Kõik",

View File

@@ -1,11 +1,11 @@
{
"A device with that ID is already added.": "May naidagdag na device na may ganitong ding ID.",
"A negative number of days doesn't make sense.": "Walang saysay ang negatibong numero ng araw.",
"A new major version may not be compatible with previous versions.": "Maaring hindi compatible ang isang bagong major na beryson sa mga nakaraang bersyon.",
"A device with that ID is already added.": "May naidagdag na device na may ganito ring ID.",
"A negative number of days doesn't make sense.": "Walang saysay ang negatibong bilang ng araw.",
"A new major version may not be compatible with previous versions.": "Maaring hindi compatible ang isang bagong major na bersiyon sa mga nakaraang bersiyon.",
"API Key": "API Key",
"About": "Tungkol sa",
"Action": "Aksyon",
"Actions": "Mga Aksyon",
"Action": "Aksiyon",
"Actions": "Mga Aksiyon",
"Active filter rules": "Mga aktibong tuntunin sa pag-filter",
"Add": "Magdagdag",
"Add Device": "Magdagdag ng Device",
@@ -56,7 +56,7 @@
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Hindi maaaring paganahin kapag ang uri ng folder ay \"{{foldertype}}\".",
"Changelog": "Mga Pagbabago",
"Clean out after": "Linisin pagkatapos",
"Cleaning Versions": "Mga Bersyon ng Paglinis",
"Cleaning Versions": "Mga Bersiyon ng Paglinis",
"Cleanup Interval": "Pagitan ng Paglinis",
"Click to see full identification string and QR code.": "I-click upang makita ang buong string ng pagkakakilanlan at QR code.",
"Close": "Isara",
@@ -155,14 +155,14 @@
"External": "Panlabas",
"External File Versioning": "Panlabas na File Versioning",
"Failed Items": "Mga Nabigong Item",
"Failed to load file versions.": "Nabigong i-load ang mga bersyon ng file.",
"Failed to load file versions.": "Nabigong i-load ang mga bersiyon ng file.",
"Failed to load ignore patterns.": "Nabigong i-load ang mga ignore pattern.",
"Failed to set up, retrying": "Nabigong i-set up, sinusubukan muli",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Inaasahan ang pagbigo sa pagkonekta sa mga IPv6 na server kapag walang konektibidad sa IPv6.",
"File Pull Order": "Order ng Pagkuha ng File",
"File Versioning": "File Versioning",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Nilipat ang mga file sa .stversions na direktoryo kapag pinalitan o binura ng Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Nililipat ang mga file sa mga naka-date stamp na bersyon sa .stversions na direktoryo kapag pinalitan o binura ng Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Nililipat ang mga file sa mga naka-date stamp na bersiyon sa .stversions na direktoryo kapag pinalitan o binura ng Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Pinoprotektahan ang mga file mula sa mga pagbabago sa ibang device, pero ipapadala sa ibang cluster ang mga pagbabago na ginawa sa device na ito.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Sini-synchronize mula sa cluster ang mga file, pero hindi ipapadala sa mga ibang device ang mgaanumang pagbabago.",
"Filesystem Watcher Errors": "Mga Error sa Taganood ng Filesystem",
@@ -217,7 +217,7 @@
"Introducer": "Tagapagpakilala",
"Introduction": "Panimula",
"Inversion of the given condition (i.e. do not exclude)": "Pabaliktad ng ibinigay na kundisyon (hal. huwag ibukod)",
"Keep Versions": "Panatilihin ang mga Bersyon",
"Keep Versions": "Panatilihin ang mga Bersiyon",
"LDAP": "LDAP",
"Largest First": "Pinakamalaki Muna",
"Last 30 Days": "Huling 30 Araw",
@@ -245,12 +245,12 @@
"Log In": "Mag-Log In",
"Log Out": "Mag-Log Out",
"Log in to see paths information.": "Mag-log in upang makita ang impormasyon ng mga path.",
"Log in to see version information.": "Mag-log in upang makita ang impormasyon ng bersyon.",
"Log in to see version information.": "Mag-log in upang makita ang impormasyon ng bersiyon.",
"Log tailing paused. Scroll to the bottom to continue.": "Na-pause ang tailing ng tala. Mag-scroll pababa para magpatuloy.",
"Login failed, see Syncthing logs for details.": "Nabigo ang pag-login, tignan ang mga tala ng Syncthing para sa mga detalye.",
"Logs": "Mga Tala",
"Major Upgrade": "Major na Upgrade",
"Mass actions": "Mga maramihang aksyon",
"Mass actions": "Mga maramihang aksiyon",
"Maximum Age": "Pinakamataas na Edad",
"Maximum single entry size": "Pinakamataas na laki ng isang entry",
"Maximum total size": "Pinakamataas na kabuuang laki",
@@ -289,7 +289,7 @@
"Password": "Password",
"Path": "Path",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Path papunta sa folder sa computer na ito. Gagawin kapag hindi umiiral. Maaring gamitin ang tilde na character (~) bilang shortcut sa",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Path kung saan ilalagay ang mga bersyon (iwanang walang laman para sa default .stversions na direktoryo sa binabahaging folder).",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Path kung saan ilalagay ang mga bersiyon (iwanang walang laman para sa default .stversions na direktoryo sa binabahaging folder).",
"Paths": "Mga Path",
"Pause": "I-pause",
"Pause All": "I-pause Lahat",
@@ -335,7 +335,7 @@
"Restart Needed": "Kinakailangan ng Restart",
"Restarting": "Nagre-restart",
"Restore": "I-restore",
"Restore Versions": "I-restore ang Mga Bersyon",
"Restore Versions": "I-restore ang Mga Bersiyon",
"Resume": "I-resume",
"Resume All": "I-resume Lahat",
"Reused": "Ginamit muli",
@@ -345,13 +345,13 @@
"Saving changes": "Sine-save ang mga pagbabago",
"Scan Time Remaining": "Natitirang Oras sa Pag-scan",
"Scanning": "Sina-scan",
"See external versioning help for supported templated command line parameters.": "Tingnan ang tulong sa external na pag-bersyon para sa mga sinusuportahang naka-template na parameter ng command line.",
"See external versioning help for supported templated command line parameters.": "Tingnan ang tulong sa external na pag-bersiyon para sa mga sinusuportahang naka-template na parameter ng command line.",
"Select All": "Piliin Lahat",
"Select a version": "Pumili ng bersyon",
"Select a version": "Pumili ng bersiyon",
"Select additional devices to share this folder with.": "Pumili ng mga karagdagang device para ibagagi ang folder na ito.",
"Select additional folders to share with this device.": "Pumili ng mga karagdagang folder para ibagagi sa device na ito.",
"Select latest version": "Piliin ang pinakabagong bersyon",
"Select oldest version": "Piliin ang pinakalumang bersyon",
"Select latest version": "Piliin ang pinakabagong bersiyon",
"Select oldest version": "Piliin ang pinakalumang bersiyon",
"Send & Receive": "Magpadala at Makatanggap",
"Send Extended Attributes": "Magpadala ng mga Pinalawak na Attribute",
"Send Only": "Magpadala Lamang",
@@ -370,7 +370,7 @@
"Show QR": "Ipakita ang QR",
"Show detailed discovery status": "Magpakita ng detalyadong status sa pagtuklas",
"Show detailed listener status": "Ipakita ang detalyadong status sa listener",
"Show diff with previous version": "Ipakita ang diff sa nakaraang bersyon",
"Show diff with previous version": "Ipakita ang diff sa nakaraang bersiyon",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Ipinapakita sa halip na Device ID sa status ng cluster. Ia-advertise sa iba pang mga device bilang opsyonal na default na pangalan.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Ipinapakita sa halip na Device ID sa status ng cluster. Ia-update sa pangalan na ina-advertise ng device kung iiwanang walang laman.",
"Shut Down": "I-shutdown",
@@ -425,15 +425,15 @@
"The cleanup interval cannot be blank.": "Hindi maaaring walang laman ang pagitan ng paglinis.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Na-save na ang configuration ngunit hindi naka-activate. Kailangang mag-restart ang Syncthing para i-activate ang bagong configuration.",
"The device ID cannot be blank.": "Hindi maaaring walang laman ang Device ID.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Mahahanap ang device ID na ilalagay dito sa \"Mga Aksyon > Ipakita ang ID\" na dialog sa isa pang device. Opsyonal ang mga puwang at gitling (hindi pinapansin).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes, and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Araw-araw na pinapadala ang naka-encrypt na ulat sa paggamit. Ginagamit ito sa pag-track ng mga karaniwang platform, laki ng folder, at bersyon ng app. Kapag nabago ang tinakdang data ng ulat ipo-prompt kang muli ng dialog na ito.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Mahahanap ang device ID na ilalagay dito sa \"Mga Aksiyon > Ipakita ang ID\" na dialog sa isa pang device. Opsyonal ang mga puwang at gitling (hindi pinapansin).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes, and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Araw-araw na pinapadala ang naka-encrypt na ulat sa paggamit. Ginagamit ito sa pag-track ng mga karaniwang platform, laki ng folder, at bersiyon ng app. Kapag nabago ang tinakdang data ng ulat ipo-prompt kang muli ng dialog na ito.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Mukhang hindi angkop ang inilagay na device ID. Dapat itong 52 o 56 na character na string na binubuo ng mga titik at numero, na may mga puwang at gitling bilang opsyonal.",
"The folder ID cannot be blank.": "Hindi maaaring walang laman ang folder ID.",
"The folder ID must be unique.": "Kailangang kakaiba ang folder ID.",
"The folder content on other devices will be overwritten to become identical with this device. Files not present here will be deleted on other devices.": "Io-overwrite ang nilalaman ng folder sa mga ibang device para maging magkapareho sa device na ito. Ang mga file na hindi nandito ay buburahin sa mga ibang device.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "Io-overwrite ang nilalaman ng folder sa mga ibang device para maging magkapareho sa device na ito. Ang mga file na kamakilang dinagdag dito ay buburahin sa mga ibang device.",
"The folder path cannot be blank.": "Hindi maaaring walang laman ang path ng folder.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Ang mga sumusunod na pagitan ay ginagamit: sa unang oras ang isang bersyon ay pinapanatili bawat 30 segundo, sa unang araw ang isang bersyon ay pinapanatili bawat oras, sa unang 30 araw ang isang bersyon ay pinapanatili bawat araw, hanggang sa pinakamataas na edad ang isang bersyon ay pinapanatili bawat linggo.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Ang mga sumusunod na pagitan ay ginagamit: sa unang oras ang isang bersiyon ay pinapanatili bawat 30 segundo, sa unang araw ang isang bersiyon ay pinapanatili bawat oras, sa unang 30 araw ang isang bersiyon ay pinapanatili bawat araw, hanggang sa pinakamataas na edad ang isang bersiyon ay pinapanatili bawat linggo.",
"The following items could not be synchronized.": "Hindi ma-synchronize ang mga sumusunod na item.",
"The following items were changed locally.": "Binago ng lokal ang mga sumusunod na item.",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "Ang mga sumusunod na paraan ay ginagamit upang tumuklas ng mga ibang device sa network at ipahayag ang device na ito na mahanap ng iba:",
@@ -442,12 +442,12 @@
"The interval must be a positive number of seconds.": "Dapat positibong numero ng segundo ang pagitan.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Ang pagitan, bilang segundo, para sa pagtakbo ng paglinis sa versions na direktoryo. Sero para i-disable ang periodical na paglinis.",
"The maximum age must be a number and cannot be blank.": "Dapat numero ang pinakamataas na edad at hindi maaaring walang laman.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Ang pinakamataas na oras para panatilihin ang bersyon (bilang araw, itakda sa 0 para panatilihin ang mga bersyon magpakailanman).",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Ang pinakamataas na oras para panatilihin ang bersiyon (bilang araw, itakda sa 0 para panatilihin ang mga bersiyon magpakailanman).",
"The number of connections must be a non-negative number.": "Dapat hindi negatibong numero ang bilang ng mga koneksyon.",
"The number of days must be a number and cannot be blank.": "Dapat numero ang bilang ng araw at hindi maaaring walang laman.",
"The number of days to keep files in the trash can. Zero means forever.": "Ang bilang ng araw para panatilihin ang mga file sa basurahan. Ang sero ay ibig sabihin ay magpakailanman.",
"The number of old versions to keep, per file.": "Ang bilang ng mga lumang bersyon na dapat panatilihin, bawat file.",
"The number of versions must be a number and cannot be blank.": "Dapat numero ang bilang ng mga bersyon at hindi maaaring walang laman.",
"The number of old versions to keep, per file.": "Ang bilang ng mga lumang bersiyon na dapat panatilihin, bawat file.",
"The number of versions must be a number and cannot be blank.": "Dapat numero ang bilang ng mga bersiyon at hindi maaaring walang laman.",
"The path cannot be blank.": "Hindi maaaring walang laman ang path.",
"The rate limit is applied to the accumulated traffic of all connections to this device.": "Ina-apply ang rate limit sa naipon na traffic ng lahat ng mga koneksyon sa device na ito.",
"The rate limit must be a non-negative number (0: no limit)": "Dapat hindi negatibong numero ang rate limit (0: walang limitasyon)",
@@ -462,7 +462,7 @@
"This Month": "Itong Buwan",
"This can easily give hackers access to read and change any files on your computer.": "Madali nitong mabibigyan ang mga hacker ng access na basahin at baguhin ang anumang mga file sa iyong computer.",
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "Hindi awtomatikong tutuklasin ng device na ito ng mga ibang device o i-annouce ang sarili nitong address para mahanap ng iba. Makakakonekta lamang ang mga device na may static na naka-configure na address.",
"This is a major version upgrade.": "Ito ay isang upgrade sa major na bersyon.",
"This is a major version upgrade.": "Ito ay isang upgrade sa major na bersiyon.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Kinokontrol ng setting na ito ang kinakailangan na bakanteng espasyo sa home (hal., index database) disk.",
"Time": "Oras",
"Time the item was last modified": "Oras na huling binago ang file",
@@ -501,10 +501,10 @@
"Using a QUIC connection over WAN": "Gumagamit ng QUIC na koneksyon mula sa WAN",
"Using a direct TCP connection over LAN": "Gumagamit ng direktang TCP na koneksyon mula sa LAN",
"Using a direct TCP connection over WAN": "Gumagamit ng direktang TCP na koneksyon mula sa WAN",
"Version": "Bersyon",
"Versions": "Mga Bersyon",
"Versions Path": "Path ng Mga Bersyon",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Awtomatikong buburahin ang mgs bersyon kapag mas matanda sila kaysa sa pinakamataas na edad o lumalagpas sa numero ng mga file na pinapayagan sa pagitan.",
"Version": "Bersiyon",
"Versions": "Mga Bersiyon",
"Versions Path": "Path ng Mga Bersiyon",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Awtomatikong buburahin ang mgs bersiyon kapag mas matanda sila kaysa sa pinakamataas na edad o lumalagpas sa numero ng mga file na pinapayagan sa pagitan.",
"Waiting to Clean": "Naghihintay para Linisin",
"Waiting to Scan": "Naghihintay para Mag-scan",
"Waiting to Sync": "Naghihintay para Mag-sync",
@@ -529,7 +529,7 @@
"You have no ignored devices.": "Wala kang mga hindi pinapansin na device.",
"You have no ignored folders.": "Wala kang mga hindi pinapansin na folder.",
"You have unsaved changes. Do you really want to discard them?": "Mayroon kang mga hindi na-save na pagbabago. Gusto mo ba talagang i-discard ang mga ito?",
"You must keep at least one version.": "Kailangan mong magpanatili ng kahit isang bersyon.",
"You must keep at least one version.": "Kailangan mong magpanatili ng kahit isang bersiyon.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "Hindi ka dapat magdagdag o magpalit ng anumang lokal sa folder na \"{{receiveEncrypted}}\".",
"Your SMS app should open to let you choose the recipient and send it from your own number.": "Magbubukas ang iyong SMS app para hayaan kang pumili ng tatanggap at ipadala ito mula sa sarili mong numero.",
"Your email app should open to let you choose the recipient and send it from your own address.": "Magbubukas ang iyong email app para hayaan kang pumili ng tatanggap at ipadala mula sa sarili mong address.",

View File

@@ -256,8 +256,8 @@
"Maximum total size": "Taille maximum totale",
"Metadata Only": "Métadonnées uniquement",
"Minimum Free Disk Space": "Espace disque libre minimum",
"Mod. Device": "Appareil modificateur",
"Mod. Time": "Date de modification",
"Mod. Device": "Modificateur",
"Mod. Time": "Dernière modif.",
"More than a month ago": "Plus d'un mois",
"More than a week ago": "Plus d'une semaine",
"More than a year ago": "Plus d'un an",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Redes permitidas",
"Alphabetic": "Alfabética",
"Altered by ignoring deletes.": "Cambiado por ignorar o borrado.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre acendido cando o cartafol é de tipo \"{{foldertype}}\".",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Un comando externo xestiona as versións. Ten que eliminar o ficheiro do cartafol compartido. Si a ruta ao aplicativo contén espazos, deberían ir acotados.",
"Anonymous Usage Reporting": "Informe anónimo de uso",
"Anonymous usage report format has changed. Would you like to move to the new format?": "O formato do informe de uso anónimo cambiou. Quere usar o novo formato?",
@@ -52,6 +53,7 @@
"Body:": "Corpo:",
"Bugs": "Erros",
"Cancel": "Cancelar",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Non se pode activar cando o cartafol é de tipo \"{{foldertype}}\".",
"Changelog": "Rexistro de cambios",
"Clean out after": "Limpar despois",
"Cleaning Versions": "Limpando Versións",
@@ -80,6 +82,7 @@
"Custom Range": "Rango personalizado",
"Danger!": "Perigo!",
"Database Location": "Localización da Base de Datos",
"Debug": "Depurar",
"Debugging Facilities": "Ferramentas de depuración",
"Default": "Predeterminado",
"Default Configuration": "Configuración Predeterminada",
@@ -140,6 +143,7 @@
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Activa o envío de atributos extendidos a outros dispositivos, e aplicar os atributos extendidos recibidos. Podería requerir a execución con privilexios elevados.",
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Activa o envío de atributos extendidos a outros dispositivos, pero non aplica atributos extendidos que se reciben. Isto podería afectar significativamente ao rendemento. Sempre está activado cando «Sincr Atributos Extendidos\" está activado.",
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Activa o envío de información sobre a propiedade a outros dispositivos, e aplica a información sobre a propiedade cando se recibe. Normalmente require a execución con privilexios elevados.",
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Activa o envío a outros dispositivos de información sobre a propiedade, pero non aplica información entrante sobre a propiedade. Isto pode afectar en gran medida ao rendemento. Está sempre activado cando \"Sincronización da propiedade\" está activada.",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Introduza un número non negativo (por exemplo, \"2.35\") e seleccione unha unidade. As porcentaxes son como partes totais do tamaño do disco.",
"Enter a non-privileged port number (1024 - 65535).": "Introduza un número de porto non privilexiado (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza direccións separadas por comas (\"tcp://ip:porto\", \"tcp://host:porto\") ou \"dynamic\" para realizar o descubrimento automático da dirección.",

View File

@@ -82,6 +82,7 @@
"Custom Range": "טווח מותאם אישית",
"Danger!": "סכנה!",
"Database Location": "מיקום מסד נתונים",
"Debug": "איתור באגים",
"Debugging Facilities": "מתקני דיבוג",
"Default": "ברירת מחדל",
"Default Configuration": "תצורת ברירת מחדל",
@@ -210,6 +211,7 @@
"Incoming Rate Limit (KiB/s)": "מגבלת קצב נכנס (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "תצורה שגויה עלולה לגרום נזק לתכולת התיקייה שלך ולהפוך את Syncthing לבלתי ניתן להפעלה.",
"Incorrect user name or password.": "שם משתמש או סיסמה שגויים.",
"Info": "מידע",
"Internally used paths:": "נתיבים בשימוש פנימי:",
"Introduced By": "הוצג על ידי",
"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

@@ -187,13 +187,14 @@ angular.module('syncthing.core')
$scope.version = data;
}).error($scope.emitHTTPError);
$http.get(urlbase + '/svc/report').success(function (data) {
$scope.reportData = data;
if ($scope.system && $scope.config.options.urAccepted > -1 && $scope.config.options.urSeen < $scope.system.urVersionMax && $scope.config.options.urAccepted < $scope.system.urVersionMax) {
// Usage reporting format has changed, prompt the user to re-accept.
if ($scope.system && $scope.config.options.urAccepted > -1 && $scope.config.options.urSeen < $scope.system.urVersionMax && $scope.config.options.urAccepted < $scope.system.urVersionMax) {
// Usage reporting decision has not been taken or format
// has changed, prompt the user to (re-)accept.
$http.get(urlbase + '/svc/report').success(function (data) {
$scope.reportData = data;
showModal('#ur');
}
}).error($scope.emitHTTPError);
}).error($scope.emitHTTPError);
}
$http.get(urlbase + '/system/upgrade').success(function (data) {
$scope.upgradeInfo = data;

View File

@@ -7,6 +7,7 @@
package sqlite
import (
"context"
"database/sql"
"embed"
"io/fs"
@@ -25,7 +26,11 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
)
const currentSchemaVersion = 4
const (
currentSchemaVersion = 5
applicationIDMain = 0x53546d6e // "STmn", Syncthing main database
applicationIDFolder = 0x53546664 // "STfd", Syncthing folder database
)
//go:embed sql/**
var embedded embed.FS
@@ -83,7 +88,31 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
},
}
tx, err := db.sql.Beginx()
// Create a specific connection for the schema setup and migration to
// run in. We do this because we need to disable foreign keys for the
// duration, which is a thing that needs to happen outside of a
// transaction and affects the connection it's run on. So we need to a)
// make sure all our commands run on this specific connection (which the
// transaction accomplishes naturally) and b) make sure these pragmas
// don't leak to anyone else afterwards.
ctx := context.TODO()
conn, err := db.sql.Connx(ctx)
if err != nil {
return nil, wrap(err)
}
defer func() {
_, _ = conn.ExecContext(ctx, "PRAGMA foreign_keys = ON")
_, _ = conn.ExecContext(ctx, "PRAGMA legacy_alter_table = OFF")
conn.Close()
}()
if _, err := conn.ExecContext(ctx, "PRAGMA foreign_keys = OFF"); err != nil {
return nil, wrap(err)
}
if _, err := conn.ExecContext(ctx, "PRAGMA legacy_alter_table = ON"); err != nil {
return nil, wrap(err)
}
tx, err := conn.BeginTxx(ctx, nil)
if err != nil {
return nil, wrap(err)
}
@@ -96,7 +125,7 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
}
ver, _ := db.getAppliedSchemaVersion(tx)
shouldVacuum := false
appliedMigrations := false
if ver.SchemaVersion > 0 {
filter := func(scr string) bool {
scr = filepath.Base(scr)
@@ -110,7 +139,7 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
}
if int(n) > ver.SchemaVersion {
slog.Info("Applying database migration", slogutil.FilePath(db.baseName), slog.String("script", scr))
shouldVacuum = true
appliedMigrations = true
return true
}
return false
@@ -120,6 +149,24 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
return nil, wrap(err)
}
}
// Run the initial schema scripts once more. This is generally a
// no-op. However, dropping a table removes associated triggers etc,
// and that's a thing we sometimes do in migrations. To avoid having
// to repeat the setup of associated triggers and indexes in the
// migration, we re-run the initial schema scripts.
for _, script := range schemaScripts {
if err := db.runScripts(tx, script); err != nil {
return nil, wrap(err)
}
}
// Finally, ensure nothing we've done along the way has violated key integrity.
if appliedMigrations {
if _, err := conn.ExecContext(ctx, "PRAGMA foreign_key_check"); err != nil {
return nil, wrap(err)
}
}
}
// Set the current schema version, if not already set
@@ -131,7 +178,7 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
return nil, wrap(err)
}
if shouldVacuum {
if appliedMigrations {
// We applied migrations and should take the opportunity to vaccuum
// the database.
if err := db.vacuumAndOptimize(); err != nil {
@@ -267,7 +314,12 @@ nextScript:
// also statement-internal semicolons in the triggers.
for _, stmt := range strings.Split(string(bs), "\n;") {
if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
return wrap(err, stmt)
if strings.Contains(stmt, "syncthing:ignore-failure") {
// We're ok with this failing. Just note it.
slog.Debug("Script failed, but with ignore-failure annotation", slog.String("script", scr), slogutil.Error(wrap(err, stmt)))
} else {
return wrap(err, stmt)
}
}
}
}

View File

@@ -8,11 +8,13 @@ package sqlite
import (
"fmt"
"os"
"testing"
"time"
"github.com/syncthing/syncthing/internal/timeutil"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
)
@@ -223,7 +225,7 @@ func BenchmarkUpdate(b *testing.B) {
}
func TestBenchmarkDropAllRemote(t *testing.T) {
if testing.Short() {
if testing.Short() || os.Getenv("LONG_TEST") == "" {
t.Skip("slow test")
}
@@ -266,3 +268,61 @@ func TestBenchmarkDropAllRemote(t *testing.T) {
d := time.Since(t0)
t.Log("drop all took", d)
}
func TestBenchmarkSizeManyFilesRemotes(t *testing.T) {
// Reports the database size for a setup with many files and many remote
// devices each announcing every files, with fairly long file names and
// "worst case" version vectors.
if testing.Short() || os.Getenv("LONG_TEST") == "" {
t.Skip("slow test")
}
dir := t.TempDir()
db, err := Open(dir)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
if err := db.Close(); err != nil {
t.Fatal(err)
}
})
// This is equivalent to about 800 GiB in 100k files (i.e., 8 MiB per
// file), shared between 31 devices where each have touched every file.
const numFiles = 1e5
const numRemotes = 30
const numBlocks = 64
const filenameLen = 64
fs := make([]protocol.FileInfo, 1000)
n := 0
seq := 0
for n < numFiles {
for i := range fs {
seq++
fs[i] = genFile(rand.String(filenameLen), numBlocks, seq)
for r := range numRemotes {
fs[i].Version = fs[i].Version.Update(42 + protocol.ShortID(r))
}
}
if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
t.Fatal(err)
}
for r := range numRemotes {
if err := db.Update(folderID, protocol.DeviceID{byte(42 + r)}, fs); err != nil {
t.Fatal(err)
}
}
n += len(fs)
t.Log(n, (numRemotes+1)*n)
}
if err := db.Close(); err != nil {
t.Fatal(err)
}
size := osutil.DirSize(dir)
t.Logf("Total size: %.02f MiB", float64(size)/1024/1024)
}

View File

@@ -7,6 +7,7 @@
package sqlite
import (
"fmt"
"log/slog"
"os"
"path/filepath"
@@ -15,6 +16,7 @@ import (
"github.com/syncthing/syncthing/internal/db"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
)
const (
@@ -52,8 +54,7 @@ func Open(path string, opts ...Option) (*DB, error) {
"journal_mode = WAL",
"optimize = 0x10002",
"auto_vacuum = INCREMENTAL",
"default_temp_store = MEMORY",
"temp_store = MEMORY",
fmt.Sprintf("application_id = %d", applicationIDMain),
}
schemas := []string{
"sql/schema/common/*",
@@ -65,6 +66,8 @@ func Open(path string, opts ...Option) (*DB, error) {
}
_ = os.MkdirAll(path, 0o700)
initTmpDir(path)
mainPath := filepath.Join(path, "main.db")
mainBase, err := openBase(mainPath, maxDBConns, pragmas, schemas, migrations)
if err != nil {
@@ -99,11 +102,10 @@ func Open(path string, opts ...Option) (*DB, error) {
func OpenForMigration(path string) (*DB, error) {
pragmas := []string{
"journal_mode = OFF",
"default_temp_store = MEMORY",
"temp_store = MEMORY",
"foreign_keys = 0",
"synchronous = 0",
"locking_mode = EXCLUSIVE",
fmt.Sprintf("application_id = %d", applicationIDMain),
}
schemas := []string{
"sql/schema/common/*",
@@ -115,6 +117,8 @@ func OpenForMigration(path string) (*DB, error) {
}
_ = os.MkdirAll(path, 0o700)
initTmpDir(path)
mainPath := filepath.Join(path, "main.db")
mainBase, err := openBase(mainPath, 1, pragmas, schemas, migrations)
if err != nil {
@@ -144,3 +148,24 @@ func (s *DB) Close() error {
}
return wrap(s.baseDB.Close())
}
func initTmpDir(path string) {
if build.IsWindows || build.IsDarwin || os.Getenv("SQLITE_TMPDIR") != "" {
// Doesn't use SQLITE_TMPDIR, isn't likely to have a tiny
// ram-backed temp directory, or already set to something.
return
}
// Attempt to override the SQLite temporary directory by setting the
// env var prior to the (first) database being opened and hence
// SQLite becoming initialized. We set the temp dir to the same
// place we store the database, in the hope that there will be
// enough space there for the operations it needs to perform, as
// opposed to /tmp and similar, on some systems.
dbTmpDir := filepath.Join(path, ".tmp")
if err := os.MkdirAll(dbTmpDir, 0o700); err == nil {
os.Setenv("SQLITE_TMPDIR", dbTmpDir)
} else {
slog.Warn("Failed to create temp directory for SQLite", slogutil.FilePath(dbTmpDir), slogutil.Error(err))
}
}

View File

@@ -14,5 +14,5 @@ import (
const (
dbDriver = "sqlite3"
commonOptions = "_fk=true&_rt=true&_cache_size=-65536&_sync=1&_txlock=immediate"
commonOptions = "_fk=true&_rt=true&_sync=1&_txlock=immediate"
)

View File

@@ -15,7 +15,7 @@ import (
const (
dbDriver = "sqlite"
commonOptions = "_pragma=foreign_keys(1)&_pragma=recursive_triggers(1)&_pragma=cache_size(-65536)&_pragma=synchronous(1)"
commonOptions = "_pragma=foreign_keys(1)&_pragma=recursive_triggers(1)&_pragma=synchronous(1)&_txlock=immediate"
)
func init() {

View File

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

View File

@@ -8,19 +8,28 @@ package sqlite
import (
"context"
"encoding/binary"
"fmt"
"log/slog"
"math/rand"
"strings"
"time"
"github.com/jmoiron/sqlx"
"github.com/syncthing/syncthing/internal/db"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/thejerf/suture/v4"
)
const (
internalMetaPrefix = "dbsvc"
lastMaintKey = "lastMaint"
internalMetaPrefix = "dbsvc"
lastMaintKey = "lastMaint"
lastSuccessfulGCSeqKey = "lastSuccessfulGCSeq"
gcMinChunks = 5
gcChunkSize = 100_000 // approximate number of rows to process in a single gc query
gcMaxRuntime = 5 * time.Minute // max time to spend on gc, per table, per run
)
func (s *DB) Service(maintenanceInterval time.Duration) suture.Service {
@@ -91,16 +100,44 @@ func (s *Service) periodic(ctx context.Context) error {
}
return wrap(s.sdb.forEachFolder(func(fdb *folderDB) error {
fdb.updateLock.Lock()
defer fdb.updateLock.Unlock()
// Get the current device sequence, for comparison in the next step.
seq, err := fdb.GetDeviceSequence(protocol.LocalDeviceID)
if err != nil {
return wrap(err)
}
// Get the last successful GC sequence. If it's the same as the
// current sequence, nothing has changed and we can skip the GC
// entirely.
meta := db.NewTyped(fdb, internalMetaPrefix)
if prev, _, err := meta.Int64(lastSuccessfulGCSeqKey); err != nil {
return wrap(err)
} else if seq == prev {
slog.DebugContext(ctx, "Skipping unnecessary GC", "folder", fdb.folderID, "fdb", fdb.baseName)
return nil
}
if err := garbageCollectOldDeletedLocked(ctx, fdb); err != nil {
// Run the GC steps, in a function to be able to use a deferred
// unlock.
if err := func() error {
fdb.updateLock.Lock()
defer fdb.updateLock.Unlock()
if err := garbageCollectOldDeletedLocked(ctx, fdb); err != nil {
return wrap(err)
}
if err := garbageCollectNamesAndVersions(ctx, fdb); err != nil {
return wrap(err)
}
if err := garbageCollectBlocklistsAndBlocksLocked(ctx, fdb); err != nil {
return wrap(err)
}
return tidy(ctx, fdb.sql)
}(); err != nil {
return wrap(err)
}
if err := garbageCollectBlocklistsAndBlocksLocked(ctx, fdb); err != nil {
return wrap(err)
}
return tidy(ctx, fdb.sql)
// Update the successful GC sequence.
return wrap(meta.PutInt64(lastSuccessfulGCSeqKey, seq))
}))
}
@@ -118,8 +155,36 @@ func tidy(ctx context.Context, db *sqlx.DB) error {
return nil
}
func garbageCollectNamesAndVersions(ctx context.Context, fdb *folderDB) error {
l := slog.With("folder", fdb.folderID, "fdb", fdb.baseName)
res, err := fdb.stmt(`
DELETE FROM file_names
WHERE NOT EXISTS (SELECT 1 FROM files f WHERE f.name_idx = idx)
`).Exec()
if err != nil {
return wrap(err, "delete names")
}
if aff, err := res.RowsAffected(); err == nil {
l.DebugContext(ctx, "Removed old file names", "affected", aff)
}
res, err = fdb.stmt(`
DELETE FROM file_versions
WHERE NOT EXISTS (SELECT 1 FROM files f WHERE f.version_idx = idx)
`).Exec()
if err != nil {
return wrap(err, "delete versions")
}
if aff, err := res.RowsAffected(); err == nil {
l.DebugContext(ctx, "Removed old file versions", "affected", aff)
}
return nil
}
func garbageCollectOldDeletedLocked(ctx context.Context, fdb *folderDB) error {
l := slog.With("fdb", fdb.baseDB)
l := slog.With("folder", fdb.folderID, "fdb", fdb.baseName)
if fdb.deleteRetention <= 0 {
slog.DebugContext(ctx, "Delete retention is infinite, skipping cleanup")
return nil
@@ -171,37 +236,108 @@ func garbageCollectBlocklistsAndBlocksLocked(ctx context.Context, fdb *folderDB)
}
defer tx.Rollback() //nolint:errcheck
if res, err := tx.ExecContext(ctx, `
DELETE FROM blocklists
WHERE NOT EXISTS (
SELECT 1 FROM files WHERE files.blocklist_hash = blocklists.blocklist_hash
)`); err != nil {
return wrap(err, "delete blocklists")
} else {
slog.DebugContext(ctx, "Blocklist GC", "fdb", fdb.baseName, "result", slogutil.Expensive(func() any {
rows, err := res.RowsAffected()
if err != nil {
return slogutil.Error(err)
}
return slog.Int64("rows", rows)
}))
}
// Both blocklists and blocks refer to blocklists_hash from the files table.
for _, table := range []string{"blocklists", "blocks"} {
// Count the number of rows
var rows int64
if err := tx.GetContext(ctx, &rows, `SELECT count(*) FROM `+table); err != nil {
return wrap(err)
}
if res, err := tx.ExecContext(ctx, `
DELETE FROM blocks
WHERE NOT EXISTS (
SELECT 1 FROM blocklists WHERE blocklists.blocklist_hash = blocks.blocklist_hash
)`); err != nil {
return wrap(err, "delete blocks")
} else {
slog.DebugContext(ctx, "Blocks GC", "fdb", fdb.baseName, "result", slogutil.Expensive(func() any {
rows, err := res.RowsAffected()
if err != nil {
return slogutil.Error(err)
chunks := max(gcMinChunks, rows/gcChunkSize)
l := slog.With("folder", fdb.folderID, "fdb", fdb.baseName, "table", table, "rows", rows, "chunks", chunks)
// Process rows in chunks up to a given time limit. We always use at
// least gcMinChunks chunks, then increase the number as the number of rows
// exceeds gcMinChunks*gcChunkSize.
t0 := time.Now()
for i, br := range randomBlobRanges(int(chunks)) {
if d := time.Since(t0); d > gcMaxRuntime {
l.InfoContext(ctx, "GC was interrupted due to exceeding time limit", "processed", i, "runtime", time.Since(t0))
break
}
return slog.Int64("rows", rows)
}))
// The limit column must be an indexed column with a mostly random distribution of blobs.
// That's the blocklist_hash column for blocklists, and the hash column for blocks.
limitColumn := table + ".blocklist_hash"
if table == "blocks" {
limitColumn = "blocks.hash"
}
q := fmt.Sprintf(`
DELETE FROM %s
WHERE %s AND NOT EXISTS (
SELECT 1 FROM files WHERE files.blocklist_hash = %s.blocklist_hash
)`, table, br.SQL(limitColumn), table)
if res, err := tx.ExecContext(ctx, q); err != nil {
return wrap(err, "delete from "+table)
} else {
l.DebugContext(ctx, "GC query result", "processed", i, "runtime", time.Since(t0), "result", slogutil.Expensive(func() any {
rows, err := res.RowsAffected()
if err != nil {
return slogutil.Error(err)
}
return slog.Int64("rows", rows)
}))
}
}
}
return wrap(tx.Commit())
}
// blobRange defines a range for blob searching. A range is open ended if
// start or end is nil.
type blobRange struct {
start, end []byte
}
// SQL returns the SQL where clause for the given range, e.g.
// `column >= x'49249248' AND column < x'6db6db6c'`
func (r blobRange) SQL(name string) string {
var sb strings.Builder
if r.start != nil {
fmt.Fprintf(&sb, "%s >= x'%x'", name, r.start)
}
if r.start != nil && r.end != nil {
sb.WriteString(" AND ")
}
if r.end != nil {
fmt.Fprintf(&sb, "%s < x'%x'", name, r.end)
}
return sb.String()
}
// randomBlobRanges returns n blobRanges in random order
func randomBlobRanges(n int) []blobRange {
ranges := blobRanges(n)
rand.Shuffle(len(ranges), func(i, j int) { ranges[i], ranges[j] = ranges[j], ranges[i] })
return ranges
}
// blobRanges returns n blobRanges
func blobRanges(n int) []blobRange {
// We use three byte (24 bit) prefixes to get fairly granular ranges and easy bit
// conversions.
rangeSize := (1 << 24) / n
ranges := make([]blobRange, 0, n)
var prev []byte
for i := range n {
var pref []byte
if i < n-1 {
end := (i + 1) * rangeSize
pref = intToBlob(end)
}
ranges = append(ranges, blobRange{prev, pref})
prev = pref
}
return ranges
}
func intToBlob(n int) []byte {
var pref [4]byte
binary.BigEndian.PutUint32(pref[:], uint32(n)) //nolint:gosec
// first byte is always zero and not part of the range
return pref[1:]
}

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2025 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 sqlite
import (
"bytes"
"fmt"
"strings"
"testing"
)
func TestBlobRange(t *testing.T) {
exp := `
hash < x'249249'
hash >= x'249249' AND hash < x'492492'
hash >= x'492492' AND hash < x'6db6db'
hash >= x'6db6db' AND hash < x'924924'
hash >= x'924924' AND hash < x'b6db6d'
hash >= x'b6db6d' AND hash < x'db6db6'
hash >= x'db6db6'
`
ranges := blobRanges(7)
buf := new(bytes.Buffer)
for _, r := range ranges {
fmt.Fprintln(buf, r.SQL("hash"))
}
if strings.TrimSpace(buf.String()) != strings.TrimSpace(exp) {
t.Log(buf.String())
t.Error("unexpected output")
}
}

View File

@@ -1206,6 +1206,47 @@ func TestOpenSpecialName(t *testing.T) {
db.Close()
}
func TestBlocksInserted(t *testing.T) {
// Verifies that blocks are inserted after syncing a file
t.Parallel()
sdb, err := Open(t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
if err := sdb.Close(); err != nil {
t.Fatal(err)
}
})
// Add remote file
files := []protocol.FileInfo{genFile("test1", 100, 1)}
if err := sdb.Update(folderID, protocol.DeviceID{42}, files); err != nil {
t.Fatal(err)
}
// Add the same file locally
if err := sdb.Update(folderID, protocol.LocalDeviceID, files); err != nil {
t.Fatal(err)
}
// Verify all the blocks are here
for i, block := range files[0].Blocks {
bs, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, block.Hash))
if err != nil {
t.Fatal(err)
}
if len(bs) == 0 {
t.Error("missing blocks for", i)
}
}
}
func mustCollect[T any](t *testing.T) func(it iter.Seq[T], errFn func() error) []T {
t.Helper()
return func(it iter.Seq[T], errFn func() error) []T {

View File

@@ -84,7 +84,7 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND NOT EXISTS (
SELECT 1 FROM FILES f
INNER JOIN devices d ON d.idx = f.device_idx
WHERE f.name = g.name AND f.version = g.version AND d.device_id = ?
WHERE f.name_idx = g.name_idx AND f.version_idx = g.version_idx AND d.device_id = ?
)
GROUP BY g.type, g.local_flags, g.deleted
@@ -94,7 +94,7 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND EXISTS (
SELECT 1 FROM FILES f
INNER JOIN devices d ON d.idx = f.device_idx
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
WHERE f.name_idx = g.name_idx AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
)
GROUP BY g.type, g.local_flags, g.deleted
`).Select(&res, device.String(),

View File

@@ -27,7 +27,8 @@ func (s *folderDB) GetGlobalFile(file string) (protocol.FileInfo, bool, error) {
SELECT fi.fiprotobuf, bl.blprotobuf FROM fileinfos fi
INNER JOIN files f on fi.sequence = f.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = f.blocklist_hash
WHERE f.name = ? AND f.local_flags & {{.FlagLocalGlobal}} != 0
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE n.name = ? AND f.local_flags & {{.FlagLocalGlobal}} != 0
`).Get(&ind, file)
if errors.Is(err, sql.ErrNoRows) {
return protocol.FileInfo{}, false, nil
@@ -49,8 +50,9 @@ func (s *folderDB) GetGlobalAvailability(file string) ([]protocol.DeviceID, erro
err := s.stmt(`
SELECT d.device_id FROM files f
INNER JOIN devices d ON d.idx = f.device_idx
INNER JOIN files g ON g.version = f.version AND g.name = f.name
WHERE g.name = ? AND g.local_flags & {{.FlagLocalGlobal}} != 0 AND f.device_idx != {{.LocalDeviceIdx}}
INNER JOIN files g ON g.version_idx = f.version_idx AND g.name_idx = f.name_idx
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE n.name = ? AND g.local_flags & {{.FlagLocalGlobal}} != 0 AND f.device_idx != {{.LocalDeviceIdx}}
ORDER BY d.device_id
`).Select(&devStrs, file)
if errors.Is(err, sql.ErrNoRows) {
@@ -74,9 +76,10 @@ func (s *folderDB) GetGlobalAvailability(file string) ([]protocol.DeviceID, erro
func (s *folderDB) AllGlobalFiles() (iter.Seq[db.FileMetadata], func() error) {
it, errFn := iterStructs[db.FileMetadata](s.stmt(`
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
SELECT f.sequence, n.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE f.local_flags & {{.FlagLocalGlobal}} != 0
ORDER BY f.name
ORDER BY n.name
`).Queryx())
return itererr.Map(it, errFn, func(m db.FileMetadata) (db.FileMetadata, error) {
m.Name = osutil.NativeFilename(m.Name)
@@ -93,9 +96,10 @@ func (s *folderDB) AllGlobalFilesPrefix(prefix string) (iter.Seq[db.FileMetadata
end := prefixEnd(prefix)
it, errFn := iterStructs[db.FileMetadata](s.stmt(`
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
WHERE f.name >= ? AND f.name < ? AND f.local_flags & {{.FlagLocalGlobal}} != 0
ORDER BY f.name
SELECT f.sequence, n.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE n.name >= ? AND n.name < ? AND f.local_flags & {{.FlagLocalGlobal}} != 0
ORDER BY n.name
`).Queryx(prefix, end))
return itererr.Map(it, errFn, func(m db.FileMetadata) (db.FileMetadata, error) {
m.Name = osutil.NativeFilename(m.Name)
@@ -109,7 +113,7 @@ func (s *folderDB) AllNeededGlobalFiles(device protocol.DeviceID, order config.P
case config.PullOrderRandom:
selectOpts = "ORDER BY RANDOM()"
case config.PullOrderAlphabetic:
selectOpts = "ORDER BY g.name ASC"
selectOpts = "ORDER BY n.name ASC"
case config.PullOrderSmallestFirst:
selectOpts = "ORDER BY g.size ASC"
case config.PullOrderLargestFirst:
@@ -137,9 +141,10 @@ func (s *folderDB) AllNeededGlobalFiles(device protocol.DeviceID, order config.P
func (s *folderDB) neededGlobalFilesLocal(selectOpts string) (iter.Seq[protocol.FileInfo], func() error) {
// Select all the non-ignored files with the need bit set.
it, errFn := iterStructs[indirectFI](s.stmt(`
SELECT fi.fiprotobuf, bl.blprotobuf, g.name, g.size, g.modified FROM fileinfos fi
SELECT fi.fiprotobuf, bl.blprotobuf, n.name, g.size, g.modified FROM fileinfos fi
INNER JOIN files g on fi.sequence = g.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = g.blocklist_hash
INNER JOIN file_names n ON g.name_idx = n.idx
WHERE g.local_flags & {{.FlagLocalIgnored}} = 0 AND g.local_flags & {{.FlagLocalNeeded}} != 0
` + selectOpts).Queryx())
return itererr.Map(it, errFn, indirectFI.FileInfo)
@@ -155,24 +160,26 @@ func (s *folderDB) neededGlobalFilesRemote(device protocol.DeviceID, selectOpts
// non-deleted and valid remote file (of any version)
it, errFn := iterStructs[indirectFI](s.stmt(`
SELECT fi.fiprotobuf, bl.blprotobuf, g.name, g.size, g.modified FROM fileinfos fi
SELECT fi.fiprotobuf, bl.blprotobuf, n.name, g.size, g.modified FROM fileinfos fi
INNER JOIN files g on fi.sequence = g.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = g.blocklist_hash
INNER JOIN file_names n ON g.name_idx = n.idx
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND NOT EXISTS (
SELECT 1 FROM FILES f
INNER JOIN devices d ON d.idx = f.device_idx
WHERE f.name = g.name AND f.version = g.version AND d.device_id = ?
WHERE f.name_idx = g.name_idx AND f.version_idx = g.version_idx AND d.device_id = ?
)
UNION ALL
SELECT fi.fiprotobuf, bl.blprotobuf, g.name, g.size, g.modified FROM fileinfos fi
SELECT fi.fiprotobuf, bl.blprotobuf, n.name, g.size, g.modified FROM fileinfos fi
INNER JOIN files g on fi.sequence = g.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = g.blocklist_hash
INNER JOIN file_names n ON g.name_idx = n.idx
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND EXISTS (
SELECT 1 FROM FILES f
INNER JOIN devices d ON d.idx = f.device_idx
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
WHERE f.name_idx = g.name_idx AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
)
`+selectOpts).Queryx(
device.String(),

View File

@@ -32,7 +32,8 @@ func (s *folderDB) GetDeviceFile(device protocol.DeviceID, file string) (protoco
INNER JOIN files f on fi.sequence = f.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = f.blocklist_hash
INNER JOIN devices d ON f.device_idx = d.idx
WHERE d.device_id = ? AND f.name = ?
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE d.device_id = ? AND n.name = ?
`).Get(&ind, device.String(), file)
if errors.Is(err, sql.ErrNoRows) {
return protocol.FileInfo{}, false, nil
@@ -87,14 +88,16 @@ func (s *folderDB) AllLocalFilesWithPrefix(device protocol.DeviceID, prefix stri
INNER JOIN files f on fi.sequence = f.sequence
LEFT JOIN blocklists bl ON bl.blocklist_hash = f.blocklist_hash
INNER JOIN devices d ON d.idx = f.device_idx
WHERE d.device_id = ? AND f.name >= ? AND f.name < ?
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE d.device_id = ? AND n.name >= ? AND n.name < ?
`, device.String(), prefix, end))
return itererr.Map(it, errFn, indirectFI.FileInfo)
}
func (s *folderDB) AllLocalFilesWithBlocksHash(h []byte) (iter.Seq[db.FileMetadata], func() error) {
return iterStructs[db.FileMetadata](s.stmt(`
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
SELECT f.sequence, n.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
INNER JOIN file_names n ON f.name_idx = n.idx
WHERE f.device_idx = {{.LocalDeviceIdx}} AND f.blocklist_hash = ?
`).Queryx(h))
}
@@ -104,7 +107,8 @@ func (s *folderDB) AllLocalBlocksWithHash(hash []byte) (iter.Seq[db.BlockMapEntr
// & blocklists is deferred (garbage collected) while the files list is
// not. This filters out blocks that are in fact deleted.
return iterStructs[db.BlockMapEntry](s.stmt(`
SELECT f.blocklist_hash as blocklisthash, b.idx as blockindex, b.offset, b.size, f.name as filename FROM files f
SELECT f.blocklist_hash as blocklisthash, b.idx as blockindex, b.offset, b.size, n.name as filename FROM files f
INNER JOIN file_names n ON f.name_idx = n.idx
LEFT JOIN blocks b ON f.blocklist_hash = b.blocklist_hash
WHERE f.device_idx = {{.LocalDeviceIdx}} AND b.hash = ?
`).Queryx(hash))
@@ -170,10 +174,12 @@ func (s *folderDB) DebugFilePattern(out io.Writer, name string) error {
}
name = "%" + name + "%"
res := itererr.Zip(iterStructs[hashFileMetadata](s.stmt(`
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags, f.version, f.blocklist_hash as blocklisthash, d.device_id as deviceid FROM files f
SELECT f.sequence, n.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags, v.version, f.blocklist_hash as blocklisthash, d.device_id as deviceid FROM files f
INNER JOIN devices d ON d.idx = f.device_idx
WHERE f.name LIKE ?
ORDER BY f.name, f.device_idx
INNER JOIN file_names n ON n.idx = f.name_idx
INNER JOIN file_versions v ON v.idx = f.version_idx
WHERE n.name LIKE ?
ORDER BY n.name, f.device_idx
`).Queryx(name)))
delMap := map[bool]string{

View File

@@ -7,15 +7,17 @@
package sqlite
import (
"fmt"
"time"
"github.com/syncthing/syncthing/lib/protocol"
)
type folderDB struct {
folderID string
*baseDB
folderID string
localDeviceIdx int64
deleteRetention time.Duration
}
@@ -25,8 +27,7 @@ func openFolderDB(folder, path string, deleteRetention time.Duration) (*folderDB
"journal_mode = WAL",
"optimize = 0x10002",
"auto_vacuum = INCREMENTAL",
"default_temp_store = MEMORY",
"temp_store = MEMORY",
fmt.Sprintf("application_id = %d", applicationIDFolder),
}
schemas := []string{
"sql/schema/common/*",
@@ -64,11 +65,10 @@ func openFolderDB(folder, path string, deleteRetention time.Duration) (*folderDB
func openFolderDBForMigration(folder, path string, deleteRetention time.Duration) (*folderDB, error) {
pragmas := []string{
"journal_mode = OFF",
"default_temp_store = MEMORY",
"temp_store = MEMORY",
"foreign_keys = 0",
"synchronous = 0",
"locking_mode = EXCLUSIVE",
fmt.Sprintf("application_id = %d", applicationIDFolder),
}
schemas := []string{
"sql/schema/common/*",
@@ -96,16 +96,13 @@ func openFolderDBForMigration(folder, path string, deleteRetention time.Duration
func (s *folderDB) deviceIdxLocked(deviceID protocol.DeviceID) (int64, error) {
devStr := deviceID.String()
if _, err := s.stmt(`
INSERT OR IGNORE INTO devices(device_id)
VALUES (?)
`).Exec(devStr); err != nil {
return 0, wrap(err)
}
var idx int64
if err := s.stmt(`
SELECT idx FROM devices
WHERE device_id = ?
INSERT INTO devices(device_id)
VALUES (?)
ON CONFLICT(device_id) DO UPDATE
SET device_id = excluded.device_id
RETURNING idx
`).Get(&idx, devStr); err != nil {
return 0, wrap(err)
}

View File

@@ -46,9 +46,33 @@ func (s *folderDB) Update(device protocol.DeviceID, fs []protocol.FileInfo) erro
defer tx.Rollback() //nolint:errcheck
txp := &txPreparedStmts{Tx: tx}
//nolint:sqlclosecheck
insertNameStmt, err := txp.Preparex(`
INSERT INTO file_names(name)
VALUES (?)
ON CONFLICT(name) DO UPDATE
SET name = excluded.name
RETURNING idx
`)
if err != nil {
return wrap(err, "prepare insert name")
}
//nolint:sqlclosecheck
insertVersionStmt, err := txp.Preparex(`
INSERT INTO file_versions (version)
VALUES (?)
ON CONFLICT(version) DO UPDATE
SET version = excluded.version
RETURNING idx
`)
if err != nil {
return wrap(err, "prepare insert version")
}
//nolint:sqlclosecheck
insertFileStmt, err := txp.Preparex(`
INSERT OR REPLACE INTO files (device_idx, remote_sequence, name, type, modified, size, version, deleted, local_flags, blocklist_hash)
INSERT OR REPLACE INTO files (device_idx, remote_sequence, type, modified, size, deleted, local_flags, blocklist_hash, name_idx, version_idx)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
RETURNING sequence
`)
@@ -102,8 +126,19 @@ func (s *folderDB) Update(device protocol.DeviceID, fs []protocol.FileInfo) erro
prevRemoteSeq = f.Sequence
remoteSeq = &f.Sequence
}
var nameIdx int64
if err := insertNameStmt.Get(&nameIdx, f.Name); err != nil {
return wrap(err, "insert name")
}
var versionIdx int64
if err := insertVersionStmt.Get(&versionIdx, f.Version.String()); err != nil {
return wrap(err, "insert version")
}
var localSeq int64
if err := insertFileStmt.Get(&localSeq, deviceIdx, remoteSeq, f.Name, f.Type, f.ModTime().UnixNano(), f.Size, f.Version.String(), f.IsDeleted(), f.LocalFlags, blockshash); err != nil {
if err := insertFileStmt.Get(&localSeq, deviceIdx, remoteSeq, f.Type, f.ModTime().UnixNano(), f.Size, f.IsDeleted(), f.LocalFlags, blockshash, nameIdx, versionIdx); err != nil {
return wrap(err, "insert file")
}
@@ -114,9 +149,9 @@ func (s *folderDB) Update(device protocol.DeviceID, fs []protocol.FileInfo) erro
if err != nil {
return wrap(err, "marshal blocklist")
}
if res, err := insertBlockListStmt.Exec(f.BlocksHash, bs); err != nil {
if _, err := insertBlockListStmt.Exec(f.BlocksHash, bs); err != nil {
return wrap(err, "insert blocklist")
} else if aff, _ := res.RowsAffected(); aff != 0 && device == protocol.LocalDeviceID {
} else if device == protocol.LocalDeviceID {
// Insert all blocks
if err := s.insertBlocksLocked(txp, f.BlocksHash, f.Blocks); err != nil {
return wrap(err, "insert blocks")
@@ -246,7 +281,9 @@ func (s *folderDB) DropFilesNamed(device protocol.DeviceID, names []string) erro
query, args, err := sqlx.In(`
DELETE FROM files
WHERE device_idx = ? AND name IN (?)
WHERE device_idx = ? AND name_idx IN (
SELECT idx FROM file_names WHERE name IN (?)
)
`, deviceIdx, names)
if err != nil {
return wrap(err)
@@ -299,12 +336,13 @@ func (s *folderDB) recalcGlobalForFolder(txp *txPreparedStmts) error {
// recalculate.
//nolint:sqlclosecheck
namesStmt, err := txp.Preparex(`
SELECT f.name FROM files f
SELECT n.name FROM files f
INNER JOIN file_names n ON n.idx = f.name_idx
WHERE NOT EXISTS (
SELECT 1 FROM files g
WHERE g.name = f.name AND g.local_flags & ? != 0
WHERE g.name_idx = f.name_idx AND g.local_flags & ? != 0
)
GROUP BY name
GROUP BY n.name
`)
if err != nil {
return wrap(err)
@@ -329,11 +367,13 @@ func (s *folderDB) recalcGlobalForFolder(txp *txPreparedStmts) error {
func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error {
//nolint:sqlclosecheck
selStmt, err := txp.Preparex(`
SELECT name, device_idx, sequence, modified, version, deleted, local_flags FROM files
WHERE name = ?
SELECT n.name, f.device_idx, f.sequence, f.modified, v.version, f.deleted, f.local_flags FROM files f
INNER JOIN file_versions v ON v.idx = f.version_idx
INNER JOIN file_names n ON n.idx = f.name_idx
WHERE n.name = ?
`)
if err != nil {
return wrap(err)
return wrap(err, "prepare select")
}
es, err := itererr.Collect(iterStructs[fileRow](selStmt.Queryx(file)))
if err != nil {
@@ -389,10 +429,10 @@ func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error
//nolint:sqlclosecheck
upStmt, err = txp.Preparex(`
UPDATE files SET local_flags = local_flags & ?
WHERE name = ? AND sequence != ? AND local_flags & ? != 0
WHERE name_idx = (SELECT idx FROM file_names WHERE name = ?) AND sequence != ? AND local_flags & ? != 0
`)
if err != nil {
return wrap(err)
return wrap(err, "prepare update")
}
if _, err := upStmt.Exec(^(protocol.FlagLocalNeeded | protocol.FlagLocalGlobal), global.Name, global.Sequence, protocol.FlagLocalNeeded|protocol.FlagLocalGlobal); err != nil {
return wrap(err)

View File

@@ -0,0 +1,53 @@
-- Copyright (C) 2025 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/.
-- Grab all unique names into the names table
INSERT INTO file_names (idx, name) SELECT DISTINCT null, name FROM files
;
-- Grab all unique versions into the versions table
INSERT INTO file_versions (idx, version) SELECT DISTINCT null, version FROM files
;
-- Create the new files table
DROP TABLE IF EXISTS files_v5
;
CREATE TABLE files_v5 (
device_idx INTEGER NOT NULL,
sequence INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
remote_sequence INTEGER,
name_idx INTEGER NOT NULL, -- changed
type INTEGER NOT NULL,
modified INTEGER NOT NULL,
size INTEGER NOT NULL,
version_idx INTEGER NOT NULL, -- changed
deleted INTEGER NOT NULL,
local_flags INTEGER NOT NULL,
blocklist_hash BLOB,
FOREIGN KEY(device_idx) REFERENCES devices(idx) ON DELETE CASCADE,
FOREIGN KEY(name_idx) REFERENCES file_names(idx), -- added
FOREIGN KEY(version_idx) REFERENCES file_versions(idx) -- added
) STRICT
;
-- Populate the new files table and move it in place
INSERT INTO files_v5
SELECT f.device_idx, f.sequence, f.remote_sequence, n.idx as name_idx, f.type, f.modified, f.size, v.idx as version_idx, f.deleted, f.local_flags, f.blocklist_hash
FROM files f
INNER JOIN file_names n ON n.name = f.name
INNER JOIN file_versions v ON v.version = f.version
;
DROP TABLE files
;
ALTER TABLE files_v5 RENAME TO files
;

View File

@@ -6,9 +6,8 @@
-- Schema migrations hold the list of historical migrations applied
CREATE TABLE IF NOT EXISTS schemamigrations (
schema_version INTEGER NOT NULL,
schema_version INTEGER NOT NULL PRIMARY KEY,
applied_at INTEGER NOT NULL, -- unix nanos
syncthing_version TEXT NOT NULL COLLATE BINARY,
PRIMARY KEY(schema_version)
syncthing_version TEXT NOT NULL COLLATE BINARY
) STRICT
;

View File

@@ -9,5 +9,5 @@
CREATE TABLE IF NOT EXISTS kv (
key TEXT NOT NULL PRIMARY KEY COLLATE BINARY,
value BLOB NOT NULL
) STRICT
) STRICT, WITHOUT ROWID
;

View File

@@ -25,15 +25,27 @@ CREATE TABLE IF NOT EXISTS files (
device_idx INTEGER NOT NULL, -- actual device ID or LocalDeviceID
sequence INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- our local database sequence, for each and every entry
remote_sequence INTEGER, -- remote device's sequence number, null for local or synthetic entries
name TEXT NOT NULL COLLATE BINARY,
name_idx INTEGER NOT NULL,
type INTEGER NOT NULL, -- protocol.FileInfoType
modified INTEGER NOT NULL, -- Unix nanos
size INTEGER NOT NULL,
version TEXT NOT NULL COLLATE BINARY,
version_idx INTEGER NOT NULL,
deleted INTEGER NOT NULL, -- boolean
local_flags INTEGER NOT NULL,
blocklist_hash BLOB, -- null when there are no blocks
FOREIGN KEY(device_idx) REFERENCES devices(idx) ON DELETE CASCADE
FOREIGN KEY(device_idx) REFERENCES devices(idx) ON DELETE CASCADE,
FOREIGN KEY(name_idx) REFERENCES file_names(idx),
FOREIGN KEY(version_idx) REFERENCES file_versions(idx)
) STRICT
;
CREATE TABLE IF NOT EXISTS file_names (
idx INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL UNIQUE COLLATE BINARY
) STRICT
;
CREATE TABLE IF NOT EXISTS file_versions (
idx INTEGER NOT NULL PRIMARY KEY,
version TEXT NOT NULL UNIQUE COLLATE BINARY
) STRICT
;
-- FileInfos store the actual protobuf object. We do this separately to keep
@@ -49,11 +61,17 @@ CREATE UNIQUE INDEX IF NOT EXISTS files_remote_sequence ON files (device_idx, re
WHERE remote_sequence IS NOT NULL
;
-- There can be only one file per folder, device, and name
CREATE UNIQUE INDEX IF NOT EXISTS files_device_name ON files (device_idx, name)
;
-- We want to be able to look up & iterate files based on just folder and name
CREATE INDEX IF NOT EXISTS files_name_only ON files (name)
CREATE UNIQUE INDEX IF NOT EXISTS files_device_name ON files (device_idx, name_idx)
;
-- We want to be able to look up & iterate files based on blocks hash
CREATE INDEX IF NOT EXISTS files_blocklist_hash_only ON files (blocklist_hash, device_idx) WHERE blocklist_hash IS NOT NULL
;
-- We need to look by name_idx or version_idx for garbage collection.
-- This will fail pre-migration for v4 schemas, which is fine.
-- syncthing:ignore-failure
CREATE INDEX IF NOT EXISTS files_name_idx_only ON files (name_idx)
;
-- This will fail pre-migration for v4 schemas, which is fine.
-- syncthing:ignore-failure
CREATE INDEX IF NOT EXISTS files_version_idx_only ON files (version_idx)
;

View File

@@ -6,10 +6,9 @@
-- indexids holds the index ID and maximum sequence for a given device and folder
CREATE TABLE IF NOT EXISTS indexids (
device_idx INTEGER NOT NULL,
device_idx INTEGER NOT NULL PRIMARY KEY,
index_id TEXT NOT NULL COLLATE BINARY,
sequence INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY(device_idx),
FOREIGN KEY(device_idx) REFERENCES devices(idx) ON DELETE CASCADE
) STRICT, WITHOUT ROWID
;

View File

@@ -6,9 +6,8 @@
--- Backing for the MtimeFS
CREATE TABLE IF NOT EXISTS mtimes (
name TEXT NOT NULL,
name TEXT NOT NULL PRIMARY KEY,
ondisk INTEGER NOT NULL, -- unix nanos
virtual INTEGER NOT NULL, -- unix nanos
PRIMARY KEY(name)
virtual INTEGER NOT NULL -- unix nanos
) STRICT, WITHOUT ROWID
;

View File

@@ -944,28 +944,29 @@ type FileInfo struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedBy uint64 `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"`
Version *Vector `protobuf:"bytes,9,opt,name=version,proto3" json:"version,omitempty"`
Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
Blocks []*BlockInfo `protobuf:"bytes,16,rep,name=blocks,proto3" json:"blocks,omitempty"`
SymlinkTarget []byte `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlink_target,omitempty"`
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocks_hash,omitempty"`
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
Type FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=bep.FileInfoType" json:"type,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
BlockSize int32 `protobuf:"varint,13,opt,name=block_size,json=blockSize,proto3" json:"block_size,omitempty"`
Platform *PlatformData `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedBy uint64 `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"`
Version *Vector `protobuf:"bytes,9,opt,name=version,proto3" json:"version,omitempty"`
Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
Blocks []*BlockInfo `protobuf:"bytes,16,rep,name=blocks,proto3" json:"blocks,omitempty"`
SymlinkTarget []byte `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlink_target,omitempty"`
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocks_hash,omitempty"`
PreviousBlocksHash []byte `protobuf:"bytes,20,opt,name=previous_blocks_hash,json=previousBlocksHash,proto3" json:"previous_blocks_hash,omitempty"`
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
Type FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=bep.FileInfoType" json:"type,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
BlockSize int32 `protobuf:"varint,13,opt,name=block_size,json=blockSize,proto3" json:"block_size,omitempty"`
Platform *PlatformData `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
// The local_flags fields stores flags that are relevant to the local
// host only. It is not part of the protocol, doesn't get sent or
// received (we make sure to zero it), nonetheless we need it on our
// struct and to be able to serialize it to/from the database.
LocalFlags uint32 `protobuf:"varint,1000,opt,name=local_flags,json=localFlags,proto3" json:"local_flags,omitempty"`
// The version_hash is an implementation detail and not part of the wire
// format.
// format. It is used in the old database format.
VersionHash []byte `protobuf:"bytes,1001,opt,name=version_hash,json=versionHash,proto3" json:"version_hash,omitempty"`
// The time when the inode was last changed (i.e., permissions, xattrs
// etc changed). This is host-local, not sent over the wire.
@@ -1071,6 +1072,13 @@ func (x *FileInfo) GetBlocksHash() []byte {
return nil
}
func (x *FileInfo) GetPreviousBlocksHash() []byte {
if x != nil {
return x.PreviousBlocksHash
}
return nil
}
func (x *FileInfo) GetEncrypted() []byte {
if x != nil {
return x.Encrypted
@@ -2084,7 +2092,7 @@ var file_bep_bep_proto_rawDesc = []byte{
0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a,
0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x76, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e,
0x63, 0x65, 0x22, 0xfe, 0x05, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x63, 0x65, 0x22, 0xb0, 0x06, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66,
@@ -2102,198 +2110,201 @@ var file_bep_bep_proto_rawDesc = []byte{
0x72, 0x67, 0x65, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x79, 0x6d, 0x6c,
0x69, 0x6e, 0x6b, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e,
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65,
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x6e, 0x73,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64,
0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a,
0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f,
0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18,
0xe8, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61,
0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61,
0x73, 0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x5f,
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x73, 0x12,
0x37, 0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72,
0x61, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28,
0x05, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x61,
0x69, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x07, 0x20,
0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e,
0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f,
0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x32, 0x0a, 0x06, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72,
0x12, 0x28, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x07, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xfd, 0x01, 0x0a, 0x0c,
0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04,
0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70,
0x2e, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x12,
0x2a, 0x0a, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x10, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x61,
0x74, 0x61, 0x52, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x6c,
0x69, 0x6e, 0x75, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x75,
0x78, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74,
0x61, 0x52, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x12, 0x28, 0x0a, 0x07, 0x66, 0x72, 0x65,
0x65, 0x62, 0x73, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x66, 0x72, 0x65, 0x65,
0x62, 0x73, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x18, 0x06, 0x20,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x30, 0x0a, 0x14, 0x70, 0x72,
0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61,
0x73, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f,
0x75, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09,
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79,
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46,
0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f,
0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x64, 0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69,
0x7a, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
0x69, 0x7a, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18,
0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74,
0x66, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f,
0x72, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67,
0x73, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46,
0x6c, 0x61, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64,
0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0xea, 0x07, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e,
0x73, 0x12, 0x37, 0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20,
0x01, 0x28, 0x05, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54,
0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18,
0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x25,
0x0a, 0x0e, 0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x69,
0x7a, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x32, 0x0a, 0x06, 0x56, 0x65, 0x63, 0x74,
0x6f, 0x72, 0x12, 0x28, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x65, 0x72, 0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x07,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xfd, 0x01,
0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21,
0x0a, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62,
0x65, 0x70, 0x2e, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x75, 0x6e, 0x69,
0x78, 0x12, 0x2a, 0x0a, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x10, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73,
0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x12, 0x24, 0x0a,
0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62,
0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x6c, 0x69,
0x6e, 0x75, 0x78, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44,
0x61, 0x74, 0x61, 0x52, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x22, 0x6c, 0x0a, 0x08, 0x55,
0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77, 0x6e,
0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x67, 0x69, 0x64, 0x22, 0x52, 0x0a, 0x0b, 0x57, 0x69, 0x6e,
0x64, 0x6f, 0x77, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72,
0x5f, 0x69, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0c, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2f, 0x0a,
0x09, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x06, 0x78, 0x61,
0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x62, 0x65, 0x70,
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x52, 0x06, 0x78, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x31,
0x0a, 0x05, 0x58, 0x61, 0x74, 0x74, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a,
0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66,
0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x72, 0x6f,
0x6d, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79,
0x12, 0x19, 0x0a, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x6f, 0x18, 0x09, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x6f, 0x4a, 0x04, 0x08, 0x08, 0x10,
0x09, 0x22, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a,
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
0x61, 0x12, 0x22, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x65, 0x0a, 0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61,
0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65,
0x72, 0x12, 0x39, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77,
0x61, 0x74, 0x61, 0x52, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x12, 0x28, 0x0a, 0x07, 0x66,
0x72, 0x65, 0x65, 0x62, 0x73, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62,
0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x66, 0x72,
0x65, 0x65, 0x62, 0x73, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x18,
0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74,
0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x22, 0x6c, 0x0a,
0x08, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e,
0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f,
0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03,
0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64,
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x67, 0x69, 0x64, 0x22, 0x52, 0x0a, 0x0b, 0x57,
0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x6f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6f, 0x77, 0x6e,
0x65, 0x72, 0x5f, 0x69, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0c, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22,
0x2f, 0x0a, 0x09, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x06,
0x78, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x62,
0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x52, 0x06, 0x78, 0x61, 0x74, 0x74, 0x72, 0x73,
0x22, 0x31, 0x0a, 0x05, 0x58, 0x61, 0x74, 0x74, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f,
0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18,
0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x66,
0x72, 0x6f, 0x6d, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61,
0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x6f, 0x18, 0x09,
0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x6f, 0x4a, 0x04, 0x08,
0x08, 0x10, 0x09, 0x22, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12,
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64,
0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x65, 0x0a, 0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66,
0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44,
0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xe5,
0x01, 0x0a, 0x1a, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a,
0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x23, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77,
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
0x1a, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x23, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56, 0x65, 0x63,
0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0d,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x04, 0x20,
0x03, 0x28, 0x05, 0x42, 0x02, 0x10, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x53, 0x69, 0x7a, 0x65, 0x22, 0x06, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x22, 0x1f, 0x0a, 0x05,
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xed, 0x01,
0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a,
0x1b, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c,
0x55, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x16,
0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49,
0x4e, 0x44, 0x45, 0x58, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47,
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x5f, 0x55, 0x50, 0x44,
0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12,
0x19, 0x0a, 0x15, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x4d, 0x45,
0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c,
0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x05, 0x12, 0x15,
0x0a, 0x11, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50,
0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x07, 0x2a, 0x4f, 0x0a,
0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43,
0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10,
0x00, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d,
0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4c, 0x5a, 0x34, 0x10, 0x01, 0x2a, 0x56,
0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
0x14, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54,
0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4d, 0x50, 0x52,
0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x45, 0x56, 0x45, 0x52, 0x10, 0x01, 0x12, 0x16,
0x0a, 0x12, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4c,
0x57, 0x41, 0x59, 0x53, 0x10, 0x02, 0x2a, 0x86, 0x01, 0x0a, 0x0a, 0x46, 0x6f, 0x6c, 0x64, 0x65,
0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56,
0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59,
0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x12, 0x1c,
0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45,
0x43, 0x45, 0x49, 0x56, 0x45, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d,
0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x45,
0x49, 0x56, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a,
0x51, 0x0a, 0x10, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x61,
0x73, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54,
0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e,
0x47, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54,
0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x55, 0x53, 0x45, 0x44,
0x10, 0x01, 0x2a, 0xb0, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54,
0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f,
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18,
0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44,
0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1b, 0x46, 0x49,
0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d,
0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12,
0x28, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54,
0x4f, 0x52, 0x59, 0x10, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x4c,
0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c,
0x49, 0x4e, 0x4b, 0x10, 0x04, 0x2a, 0x76, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f,
0x64, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45,
0x5f, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x45,
0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x49,
0x43, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44,
0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x53, 0x55, 0x43, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02,
0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49,
0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x7e, 0x0a,
0x1e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12,
0x2d, 0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44,
0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x2d,
0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f,
0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x01, 0x42, 0x70, 0x0a,
0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x65, 0x70, 0x42, 0x08, 0x42, 0x65, 0x70, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74,
0x68, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65,
0x6e, 0x2f, 0x62, 0x65, 0x70, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x42, 0x65,
0x70, 0xca, 0x02, 0x03, 0x42, 0x65, 0x70, 0xe2, 0x02, 0x0f, 0x42, 0x65, 0x70, 0x5c, 0x47, 0x50,
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x42, 0x65, 0x70, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54,
0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56,
0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27,
0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, 0x10, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x06, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x22, 0x1f,
0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a,
0xed, 0x01, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12,
0x1f, 0x0a, 0x1b, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
0x43, 0x4c, 0x55, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00,
0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x53, 0x53,
0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x5f, 0x55,
0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x45, 0x53, 0x53, 0x41,
0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10,
0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e,
0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x57,
0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x05,
0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41,
0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x07, 0x2a,
0x4f, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e,
0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43,
0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4c, 0x5a, 0x34, 0x10, 0x01,
0x2a, 0x56, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d,
0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4d,
0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x45, 0x56, 0x45, 0x52, 0x10, 0x01,
0x12, 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f,
0x41, 0x4c, 0x57, 0x41, 0x59, 0x53, 0x10, 0x02, 0x2a, 0x86, 0x01, 0x0a, 0x0a, 0x46, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45,
0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x45, 0x43, 0x45,
0x49, 0x56, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01,
0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x21,
0x0a, 0x1d, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45,
0x43, 0x45, 0x49, 0x56, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x10,
0x03, 0x2a, 0x51, 0x0a, 0x10, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52,
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f,
0x53, 0x54, 0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x52, 0x55, 0x4e, 0x4e,
0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f,
0x53, 0x54, 0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x55, 0x53,
0x45, 0x44, 0x10, 0x01, 0x2a, 0xb0, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66,
0x6f, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e,
0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1c,
0x0a, 0x18, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1b,
0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53,
0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x1a, 0x02, 0x08,
0x01, 0x12, 0x28, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54,
0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x44, 0x49, 0x52, 0x45,
0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46,
0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59,
0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x10, 0x04, 0x2a, 0x76, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72,
0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f,
0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x16, 0x0a,
0x12, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45,
0x52, 0x49, 0x43, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43,
0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x53, 0x55, 0x43, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x45,
0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45,
0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a,
0x7e, 0x0a, 0x1e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70,
0x65, 0x12, 0x2d, 0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f,
0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41,
0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x00,
0x12, 0x2d, 0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41,
0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54,
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x01, 0x42,
0x70, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x65, 0x70, 0x42, 0x08, 0x42, 0x65, 0x70, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x73, 0x79, 0x6e,
0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
0x67, 0x65, 0x6e, 0x2f, 0x62, 0x65, 0x70, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x03,
0x42, 0x65, 0x70, 0xca, 0x02, 0x03, 0x42, 0x65, 0x70, 0xe2, 0x02, 0x0f, 0x42, 0x65, 0x70, 0x5c,
0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x42, 0x65,
0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -28,20 +28,21 @@ type FileInfoTruncated struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedBy uint64 `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"`
Version *bep.Vector `protobuf:"bytes,9,opt,name=version,proto3" json:"version,omitempty"`
Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
SymlinkTarget []byte `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlink_target,omitempty"`
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocks_hash,omitempty"`
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
Type bep.FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=bep.FileInfoType" json:"type,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
BlockSize int32 `protobuf:"varint,13,opt,name=block_size,json=blockSize,proto3" json:"block_size,omitempty"`
Platform *bep.PlatformData `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedBy uint64 `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"`
Version *bep.Vector `protobuf:"bytes,9,opt,name=version,proto3" json:"version,omitempty"`
Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
SymlinkTarget []byte `protobuf:"bytes,17,opt,name=symlink_target,json=symlinkTarget,proto3" json:"symlink_target,omitempty"`
BlocksHash []byte `protobuf:"bytes,18,opt,name=blocks_hash,json=blocksHash,proto3" json:"blocks_hash,omitempty"`
PreviousBlocksHash []byte `protobuf:"bytes,20,opt,name=previous_blocks_hash,json=previousBlocksHash,proto3" json:"previous_blocks_hash,omitempty"`
Encrypted []byte `protobuf:"bytes,19,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
Type bep.FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=bep.FileInfoType" json:"type,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
BlockSize int32 `protobuf:"varint,13,opt,name=block_size,json=blockSize,proto3" json:"block_size,omitempty"`
Platform *bep.PlatformData `protobuf:"bytes,14,opt,name=platform,proto3" json:"platform,omitempty"`
// The local_flags fields stores flags that are relevant to the local
// host only. It is not part of the protocol, doesn't get sent or
// received (we make sure to zero it), nonetheless we need it on our
@@ -147,6 +148,13 @@ func (x *FileInfoTruncated) GetBlocksHash() []byte {
return nil
}
func (x *FileInfoTruncated) GetPreviousBlocksHash() []byte {
if x != nil {
return x.PreviousBlocksHash
}
return nil
}
func (x *FileInfoTruncated) GetEncrypted() []byte {
if x != nil {
return x.Encrypted
@@ -747,7 +755,7 @@ var file_dbproto_structs_proto_rawDesc = []byte{
0x1a, 0x0d, 0x62, 0x65, 0x70, 0x2f, 0x62, 0x65, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0xe5, 0x05, 0x0a, 0x11, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x72, 0x75,
0x22, 0x97, 0x06, 0x0a, 0x11, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x72, 0x75,
0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69,
0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1d,
@@ -763,107 +771,110 @@ var file_dbproto_structs_proto_rawDesc = []byte{
0x67, 0x65, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x79, 0x6d, 0x6c, 0x69,
0x6e, 0x6b, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x63,
0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x6e,
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65,
0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20,
0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x6e, 0x73, 0x18,
0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e,
0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65,
0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12,
0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0xe8,
0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61, 0x67,
0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73,
0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x73, 0x12, 0x37,
0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x61,
0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05,
0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x61, 0x69,
0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01,
0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6e,
0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x22, 0x91, 0x01, 0x0a, 0x0b, 0x46, 0x69, 0x6c,
0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e,
0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e,
0x76, 0x61, 0x6c, 0x69, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x0b,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x08, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e,
0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x33, 0x0a,
0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x73, 0x22, 0x5c, 0x0a, 0x15, 0x49, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0xe9, 0x07, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68,
0x22, 0xe6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72,
0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12,
0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74,
0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12,
0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x4e, 0x0a, 0x09, 0x43, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x53, 0x65, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12,
0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0xae, 0x01, 0x0a, 0x0e, 0x4f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x04,
0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62,
0x65, 0x6c, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x65, 0x6e,
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72,
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12,
0x29, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x74,
0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0x6e, 0x0a, 0x0e, 0x4f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x04,
0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x8c, 0x01, 0x0a, 0x0b, 0x63,
0x6f, 0x6d, 0x2e, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x0c, 0x53, 0x74, 0x72, 0x75,
0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67,
0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xa2,
0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xca,
0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xe2, 0x02, 0x13, 0x44, 0x62, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea,
0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x30, 0x0a, 0x14, 0x70, 0x72, 0x65,
0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73,
0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75,
0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x65,
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69,
0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x6e,
0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
0x64, 0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a,
0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69,
0x7a, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66,
0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73,
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c,
0x61, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68,
0x61, 0x73, 0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64, 0x65,
0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x73,
0x12, 0x37, 0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20, 0x01,
0x28, 0x05, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72,
0x61, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x07,
0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x25, 0x0a,
0x0e, 0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x22, 0x91, 0x01, 0x0a, 0x0b, 0x46,
0x69, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65,
0x70, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64,
0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e,
0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3f,
0x0a, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x0a,
0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x14, 0x2e, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22,
0x33, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x06,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62,
0x65, 0x70, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x73, 0x22, 0x5c, 0x0a, 0x15, 0x49, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a,
0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x12, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22,
0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0xe9,
0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61,
0x73, 0x68, 0x22, 0xe6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a,
0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69,
0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65,
0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20,
0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x0a,
0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x4e, 0x0a, 0x09, 0x43,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x62, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0xae, 0x01, 0x0a, 0x0e,
0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x2e,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c,
0x61, 0x62, 0x65, 0x6c, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f,
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
0x64, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72,
0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x6d,
0x6f, 0x74, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0x6e, 0x0a, 0x0e,
0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2e,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x8c, 0x01, 0x0a,
0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x0c, 0x53, 0x74,
0x72, 0x75, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69,
0x6e, 0x67, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x64, 0x62, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0xca, 0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xe2, 0x02, 0x13, 0x44, 0x62,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0xea, 0x02, 0x07, 0x44, 0x62, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (

View File

@@ -18,14 +18,30 @@ import (
"time"
)
type formattingHandler struct {
attrs []slog.Attr
groups []string
type LineFormat struct {
TimestampFormat string
LevelString bool
LevelSyslog bool
}
type formattingOptions struct {
LineFormat
out io.Writer
recs []*lineRecorder
timeOverride time.Time
}
type formattingHandler struct {
attrs []slog.Attr
groups []string
opts *formattingOptions
}
func SetLineFormat(f LineFormat) {
globalFormatter.LineFormat = f
}
var _ slog.Handler = (*formattingHandler)(nil)
func (h *formattingHandler) Enabled(context.Context, slog.Level) bool {
@@ -83,19 +99,19 @@ func (h *formattingHandler) Handle(_ context.Context, rec slog.Record) error {
}
line := Line{
When: cmp.Or(h.timeOverride, rec.Time),
When: cmp.Or(h.opts.timeOverride, rec.Time),
Message: sb.String(),
Level: rec.Level,
}
// If there is a recorder, record the line.
for _, rec := range h.recs {
for _, rec := range h.opts.recs {
rec.record(line)
}
// If there's an output, print the line.
if h.out != nil {
_, _ = line.WriteTo(h.out)
if h.opts.out != nil {
_, _ = line.WriteTo(h.opts.out, h.opts.LineFormat)
}
return nil
}
@@ -143,11 +159,9 @@ func (h *formattingHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
}
}
return &formattingHandler{
attrs: append(h.attrs, attrs...),
groups: h.groups,
recs: h.recs,
out: h.out,
timeOverride: h.timeOverride,
attrs: append(h.attrs, attrs...),
groups: h.groups,
opts: h.opts,
}
}
@@ -156,11 +170,9 @@ func (h *formattingHandler) WithGroup(name string) slog.Handler {
return h
}
return &formattingHandler{
attrs: h.attrs,
groups: append([]string{name}, h.groups...),
recs: h.recs,
out: h.out,
timeOverride: h.timeOverride,
attrs: h.attrs,
groups: append([]string{name}, h.groups...),
opts: h.opts,
}
}

View File

@@ -17,8 +17,11 @@ import (
func TestFormattingHandler(t *testing.T) {
buf := new(bytes.Buffer)
h := &formattingHandler{
out: buf,
timeOverride: time.Unix(1234567890, 0).In(time.UTC),
opts: &formattingOptions{
LineFormat: DefaultLineFormat,
out: buf,
timeOverride: time.Unix(1234567890, 0).In(time.UTC),
},
}
l := slog.New(h).With("a", "a")

View File

@@ -9,6 +9,7 @@ package slogutil
import (
"log/slog"
"maps"
"strings"
"sync"
)
@@ -39,6 +40,24 @@ func SetDefaultLevel(level slog.Level) {
globalLevels.SetDefault(level)
}
func SetLevelOverrides(sttrace string) {
pkgs := strings.Split(sttrace, ",")
for _, pkg := range pkgs {
pkg = strings.TrimSpace(pkg)
if pkg == "" {
continue
}
level := slog.LevelDebug
if cutPkg, levelStr, ok := strings.Cut(pkg, ":"); ok {
pkg = cutPkg
if err := level.UnmarshalText([]byte(levelStr)); err != nil {
slog.Warn("Bad log level requested in STTRACE", slog.String("pkg", pkg), slog.String("level", levelStr), Error(err))
}
}
globalLevels.Set(pkg, level)
}
}
type levelTracker struct {
mut sync.RWMutex
defLevel slog.Level

View File

@@ -7,6 +7,7 @@
package slogutil
import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -22,13 +23,22 @@ type Line struct {
Level slog.Level `json:"level"`
}
func (l *Line) WriteTo(w io.Writer) (int64, error) {
n, err := fmt.Fprintf(w, "%s %s %s\n", l.timeStr(), l.levelStr(), l.Message)
return int64(n), err
}
func (l *Line) timeStr() string {
return l.When.Format("2006-01-02 15:04:05")
func (l *Line) WriteTo(w io.Writer, f LineFormat) (int64, error) {
buf := new(bytes.Buffer)
if f.LevelSyslog {
_, _ = fmt.Fprintf(buf, "<%d>", l.syslogPriority())
}
if f.TimestampFormat != "" {
buf.WriteString(l.When.Format(f.TimestampFormat))
buf.WriteRune(' ')
}
if f.LevelString {
buf.WriteString(l.levelStr())
buf.WriteRune(' ')
}
buf.WriteString(l.Message)
buf.WriteRune('\n')
return buf.WriteTo(w)
}
func (l *Line) levelStr() string {
@@ -51,6 +61,19 @@ func (l *Line) levelStr() string {
}
}
func (l *Line) syslogPriority() int {
switch {
case l.Level < slog.LevelInfo:
return 7
case l.Level < slog.LevelWarn:
return 6
case l.Level < slog.LevelError:
return 4
default:
return 3
}
}
func (l *Line) MarshalJSON() ([]byte, error) {
// Custom marshal to get short level strings instead of default JSON serialisation
return json.Marshal(map[string]any{

View File

@@ -10,20 +10,26 @@ import (
"io"
"log/slog"
"os"
"strings"
"time"
)
var (
GlobalRecorder = &lineRecorder{level: -1000}
ErrorRecorder = &lineRecorder{level: slog.LevelError}
globalLevels = &levelTracker{
GlobalRecorder = &lineRecorder{level: -1000}
ErrorRecorder = &lineRecorder{level: slog.LevelError}
DefaultLineFormat = LineFormat{
TimestampFormat: time.DateTime,
LevelString: true,
}
globalLevels = &levelTracker{
levels: make(map[string]slog.Level),
descrs: make(map[string]string),
}
slogDef = slog.New(&formattingHandler{
recs: []*lineRecorder{GlobalRecorder, ErrorRecorder},
out: logWriter(),
})
globalFormatter = &formattingOptions{
LineFormat: DefaultLineFormat,
recs: []*lineRecorder{GlobalRecorder, ErrorRecorder},
out: logWriter(),
}
slogDef = slog.New(&formattingHandler{opts: globalFormatter})
)
func logWriter() io.Writer {
@@ -38,21 +44,4 @@ func logWriter() io.Writer {
func init() {
slog.SetDefault(slogDef)
// Handle legacy STTRACE var
pkgs := strings.Split(os.Getenv("STTRACE"), ",")
for _, pkg := range pkgs {
pkg = strings.TrimSpace(pkg)
if pkg == "" {
continue
}
level := slog.LevelDebug
if cutPkg, levelStr, ok := strings.Cut(pkg, ":"); ok {
pkg = cutPkg
if err := level.UnmarshalText([]byte(levelStr)); err != nil {
slog.Warn("Bad log level requested in STTRACE", slog.String("pkg", pkg), slog.String("level", levelStr), Error(err))
}
}
globalLevels.Set(pkg, level)
}
}

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
}
@@ -1772,22 +1772,23 @@ func (f jsonFileInfo) MarshalJSON() ([]byte, error) {
func fileIntfJSONMap(f protocol.FileInfo) map[string]interface{} {
out := map[string]interface{}{
"name": f.FileName(),
"type": f.FileType().String(),
"size": f.FileSize(),
"deleted": f.IsDeleted(),
"invalid": f.IsInvalid(),
"ignored": f.IsIgnored(),
"mustRescan": f.MustRescan(),
"noPermissions": !f.HasPermissionBits(),
"modified": f.ModTime(),
"modifiedBy": f.FileModifiedBy().String(),
"sequence": f.SequenceNo(),
"version": jsonVersionVector(f.FileVersion()),
"localFlags": f.FileLocalFlags(),
"platform": f.PlatformData(),
"inodeChange": f.InodeChangeTime(),
"blocksHash": f.FileBlocksHash(),
"name": f.FileName(),
"type": f.FileType().String(),
"size": f.FileSize(),
"deleted": f.IsDeleted(),
"invalid": f.IsInvalid(),
"ignored": f.IsIgnored(),
"mustRescan": f.MustRescan(),
"noPermissions": !f.HasPermissionBits(),
"modified": f.ModTime(),
"modifiedBy": f.FileModifiedBy().String(),
"sequence": f.SequenceNo(),
"version": jsonVersionVector(f.FileVersion()),
"localFlags": f.FileLocalFlags(),
"platform": f.PlatformData(),
"inodeChange": f.InodeChangeTime(),
"blocksHash": f.FileBlocksHash(),
"previousBlocksHash": f.PreviousBlocksHash,
}
if f.HasPermissionBits() {
out["permissions"] = fmt.Sprintf("%#o", f.FilePermissions())

View File

@@ -25,9 +25,10 @@ import (
)
const (
maxSessionLifetime = 7 * 24 * time.Hour
maxActiveSessions = 25
randomTokenLength = 64
maxSessionLifetime = 7 * 24 * time.Hour
maxActiveSessions = 25
randomTokenLength = 64
maxLoginRequestSize = 1 << 10 // one kibibyte for username+password
)
func emitLoginAttempt(success bool, username string, r *http.Request, evLogger events.Logger) {
@@ -182,7 +183,7 @@ func (m *basicAuthAndSessionMiddleware) passwordAuthHandler(w http.ResponseWrite
Password string
StayLoggedIn bool
}
if err := unmarshalTo(r.Body, &req); err != nil {
if err := unmarshalTo(http.MaxBytesReader(w, r.Body, maxLoginRequestSize), &req); err != nil {
l.Debugln("Failed to parse username and password:", err)
http.Error(w, "Failed to parse username and password.", http.StatusBadRequest)
return
@@ -336,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

@@ -23,6 +23,15 @@ func getRedactedConfig(s *service) config.Configuration {
if rawConf.GUI.User != "" {
rawConf.GUI.User = "REDACTED"
}
for folderIdx, folderCfg := range rawConf.Folders {
for deviceIdx, deviceCfg := range folderCfg.Devices {
if deviceCfg.EncryptionPassword != "" {
rawConf.Folders[folderIdx].Devices[deviceIdx].EncryptionPassword = "REDACTED"
}
}
}
return rawConf
}

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
}

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