Compare commits

...

274 Commits

Author SHA1 Message Date
Jakob Borg
5d8033343f chore: repo mirror job 2025-08-11 22:16:10 +02:00
Jakob Borg
c74d2a9872 chore: update man pages for 2.0 2025-08-11 19:33:32 +02:00
Jakob Borg
3da84804b6 build: just special case stable-v2 for Debian for now 2025-08-11 19:17:33 +02:00
Jakob Borg
5b75c6ddcb build: split apt archive into major version generations 2025-08-11 18:57:18 +02:00
Syncthing Release Automation
ae03854575 chore(gui, man, authors): update docs, translations, and contributors 2025-08-11 04:06:30 +00:00
tomasz1986
ad196173d0 chore(gui): remove redundant "authenticated" conditions from Actions menu (#10235) (#10237)
chore(gui): remove redundant "authenticated" conditions from Actions
menu (#10235)

Due to previous code changes, the whole Actions menu is only available
when the user is logged in. As such, there is no reason to have the same
ng-if="authenticated" condition repeated in other items belonging to it.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2025-08-10 22:13:53 +02:00
Jakob Borg
d682220305 chore: remove GUI "debugging" toggle, debug HTTP metrics (#10235)
This removes the `debugging` bool under GUI configuration, and two no
longer relevant development endpoints: `httpmetrics` (which I can't
imagine anyone using for anything -- if we need such metrics today, the
right place is the Prometheus exported metrics) and the `peerCompletion`
endpoint (previously used by integration tests).

The debugging bool initially enabled just those two endpoints, which are
not for end users. Then we added profiling and support bundles, which
are very useful indeed for end users to access, and they were hidden
behind the same debug flag. I don't see any reason for keeping that flag
now that these methods are more generally useful.

https://github.com/syncthing/docs/pull/949
2025-08-10 21:14:25 +02:00
Jakob Borg
29e10e00d2 chore(slogutil): ensure quoting of empty and confusing log values (#10236)
Clearer parsing (also for humans)
2025-08-10 08:23:23 +00:00
Jakob Borg
34f61ce464 fix: correct logging of our ID after startup & generate (#10234)
This is one place we actually want the full string.
2025-08-10 06:25:13 +00:00
Ross Smith II
adcbd31e62 fix(test): remove lib/logger from testmocks target (#10231) 2025-08-09 09:56:37 +02:00
Jakob Borg
431da839cf fix(slogutil): quote values with parentheses in them (#10229)
Avoids an obvious parsing ambiguity in log lines.
2025-08-07 09:47:50 +00:00
Jakob Borg
836045ee87 feat: switch logging framework (#10220)
This updates our logging framework from legacy freetext strings using
the `log` package to structured log entries using `log/slog`. I have
updated all INFO or higher level entries, but not yet DEBUG (😓)... So,
at a high level:

There is a slight change in log levels, effectively adding a new warning
level:

- DEBUG is still debug (ideally not for users but developers, though
this is something we need to work on)
- INFO is still info, though I've added more data here, effectively
making Syncthing more verbose by default (more on this below)
- WARNING is a new log level that is different from the _old_ WARNING
(more below)
- ERROR is what was WARNING before -- problems that must be dealt with,
and also bubbled as a popup in the GUI.

A new feature is that the logging level can be set per package to
something other than just debug or info, and hence I feel that we can
add a bit more things into INFO while moving some (in fact, most)
current INFO level warnings into WARNING. For example, I think it's
justified to get a log of synced files in INFO and sync failures in
WARNING. These are things that have historically been tricky to debug
properly, and having more information by default will be useful to many,
while still making it possible get close to told level of inscrutability
by setting the log level to WARNING. I'd like to get to a stage where
DEBUG is never necessary to just figure out what's going on, as opposed
to trying to narrow down a likely bug.

Code wise:

- Our logging object, generally known as `l` in each package, is now a
new adapter object that provides the old API on top of the newer one.
(This should go away once all old log entries are migrated.) This is
only for `l.Debugln` and `l.Debugf`.
- There is a new level tracker that keeps the log level for each
package.
- There is a nested setup of handlers, since the structure mandated by
`log/slog` is slightly convoluted (imho). We do this because we need to
do formatting at a "medium" level internally so we can buffer log lines
in text format but with separate timestamp and log level for the API/GUI
to consume.
- The `debug` API call becomes a `loglevels` API call, which can set the
log level to `DEBUG`, `INFO`, `WARNING` or `ERROR` per package. The GUI
is updated to handle this.
- Our custom `sync` package provided some debugging of mutexes quite
strongly integrated into the old logging framework, only turned on when
`STTRACE` was set to certain values at startup, etc. It's been a long
time since this has been useful; I removed it.
- The `STTRACE` env var remains and can be used the same way as before,
while additionally permitting specific log levels to be specified,
`STTRACE=model:WARN,scanner:DEBUG`.
- There is a new command line option `--log-level=INFO` to set the
default log level.
- The command line options `--log-flags` and `--verbose` go away, but
are currently retained as hidden & ignored options since we set them by
default in some of our startup examples and Syncthing would otherwise
fail to start.

Sample format messages:

```
2009-02-13 23:31:30 INF A basic info line (attr1="val with spaces" attr2=2 attr3="val\"quote" a=a log.pkg=slogutil)
2009-02-13 23:31:30 INF An info line with grouped values (attr1=val1 foo.attr2=2 foo.bar.attr3=3 a=a log.pkg=slogutil)
2009-02-13 23:31:30 INF An info line with grouped values via logger (foo.attr1=val1 foo.attr2=2 a=a log.pkg=slogutil)
2009-02-13 23:31:30 INF An info line with nested grouped values via logger (bar.foo.attr1=val1 bar.foo.attr2=2 a=a log.pkg=slogutil)
2009-02-13 23:31:30 WRN A warning entry (a=a log.pkg=slogutil)
2009-02-13 23:31:30 ERR An error (a=a log.pkg=slogutil)
```

---------

Co-authored-by: Ross Smith II <ross@smithii.com>
2025-08-07 11:19:36 +02:00
Ross Smith II
49462448d0 feat(ignore): add .stignore escaping on Windows (#10205)
Based on the discussion in
https://forum.syncthing.net/t/towards-syncthing-2-0/24072/35 This PR
adds the ability for Windows users to use the pipe character (|) to
escape the metacharacters *, ?, [, and { in .stignore files.

Additionally, this PR adds the ability for the user to set the escape
character to backslash, or any character they want, by adding a line in
the form:

  #escape=X

(where X is any single rune), to the top of an .stignore file.

This would allow users to use the same .stignore file across platforms,
by simply adding

  #escape=\

to the top of the file.

### Testing

All tests pass in CI.

### Documentation

See https://github.com/syncthing/docs/pull/919

Fixes #10057: Support escaping in .stignore files on Windows
Fixes #7547: Ignore pattern with \[ and \] does not work
2025-08-05 09:55:39 +00:00
Jakob Borg
e3424ad503 fix(model): properly set folder state "syncing" when copying data (#10227)
Prior to this fix, the folder would only get marked as "syncing" once we
started downloading data from the network. However in some cases there
will be a lot of data that can be reused locally and we spend
significant time copying blocks before downloading anything; in that
case, the folder would appear as "preparing to sync" while it was in
fact moving lots of data.

This fixes that, making it "syncing" as soon as it begins either copying
or downloading data.
2025-08-05 09:47:44 +00:00
Syncthing Release Automation
5703423c00 chore(gui, man, authors): update docs, translations, and contributors 2025-08-04 04:11:16 +00:00
Alex Ionescu
356ec26c87 fix(gui): fix identicon generation (#10228)
### Purpose

Identicon generation is supposed to consider the first 15 characters of
a device ID, e.g. if the ID is `ABCDEFG-HIJKLMN-...`, the identicon
should be based on `ABCDEFGHIJKLMN`.

However, the current implementation only strips the first dash,
resulting in `ABCDEFGHIJKLM-`, so the last character is essentially
fixed for all IDs. This corresponds to the lower-middle pixel in
identicons always being "off" (see screenshots below).

The fix is simple: Just add the `g` flag to the regex used to strip
dashes.

### Screenshots

Old vs. new, light theme:

<img width="130" height="55" alt="light-old"
src="https://github.com/user-attachments/assets/7aaf5a2d-bc8e-4fd9-af94-2e8d723e5369"
/>

<img width="130" height="55" alt="light-new"
src="https://github.com/user-attachments/assets/b91a789b-5dbc-4d46-99e0-84d89f634e1f"
/>

Old vs. new, dark theme:

<img width="130" height="55" alt="dark-old"
src="https://github.com/user-attachments/assets/c3de5d4b-83d6-41fa-98da-18dd720462d3"
/>

<img width="130" height="55" alt="dark-new"
src="https://github.com/user-attachments/assets/4d49f563-0ee6-40df-bae4-89149abf9e7e"
/>

Old vs. new, black theme:

<img width="130" height="55" alt="black-old"
src="https://github.com/user-attachments/assets/4c2e75a9-e658-4bdf-b9cc-e3dbc375cde3"
/>

<img width="130" height="55" alt="black-new"
src="https://github.com/user-attachments/assets/c321c3d7-7bbb-433f-b750-2a688956ea40"
/>

Only ~50% of identicons will be affected, since it's based on the parity
of the 15th character.
2025-08-03 15:48:57 +02:00
Daniil Gentili
d37cb02e40 refactor(scanner): use recommended pattern for slice pool (#10225)
### Purpose

Uses recommended pattern for slice pools to avoid copying the slice
struct, suggested by the linter and actually used in the go stdlib, for
example in `net/http/h2_bundle.go`.
2025-08-01 11:27:53 +02:00
Daniil Gentili
953944e54e chore(fs): slightly reduce memory usage of IsParent (#10223)
### Purpose

Small optimizations for IsParent and IsInternal, to avoid needless
allocations.
2025-07-31 14:48:04 +00:00
Daniil Gentili
6e26fab3a0 chore(scanner): reduce memory pressure by using pools inside hasher (#10222) 2025-07-30 19:09:00 +02:00
Syncthing Release Automation
532e30eb6b chore(gui, man, authors): update docs, translations, and contributors 2025-07-28 04:07:18 +00:00
Marcus B Spencer
54bb987fae chore(config): remove fallback STUN servers that are CNAMEs to stun.counterpath.com (#10219)
ref
https://forum.syncthing.net/t/my-local-dns-server-technitium-is-getting-spammed-with-stun-lookups-that-are-failing/24627/2?u=marbens

### Purpose

Reduces unnecessary load on CounterPath's server(s).

### Testing

STUN is still functional, and appears to get the correct external ports,
if enabled.
2025-07-24 13:55:42 +02:00
Syncthing Release Automation
74367d2f66 chore(gui, man, authors): update docs, translations, and contributors 2025-07-21 04:06:40 +00:00
Syncthing Release Automation
0f6750c8f5 chore(gui, man, authors): update docs, translations, and contributors 2025-07-14 04:05:46 +00:00
tomasz1986
c8c38f735f fix(gui): show revert buttons only when folder is idle (fixes #10191) (#10212)
Currently, the Revert Local Changes button for Receive Only folders, and
the Delete Unexpected Items button for Receive Encrypted folders buttons
are shown even when the folder is already performing other operations.
Because of the above, pressing the button seems to have no effect, as
its operation can only proceed after the previous operations have
completed. This confuses the user, who then may keep trying to press the
buttons again and again with no visible result.

Therefore, show the two buttons only when the folders are actually idle,
without performing other operations at the same time. This change makes
them behave similarly to the Override Changes button, which is also only
displayed for Send Only folders when they are idle.

Signed-off-by: Tomasz Wilczyński twilczynski@naver.com
2025-07-12 14:08:11 +00:00
tomasz1986
fa4bd5c057 chore(gui): update fancytree from 2.38.0 to 2.38.5 (ref #10051, ref #10155) (#10214)
Update the jQuery Fancytree Plugin to the newest version. Apart from
keeping it up-to-date out of principle, this may also help with further
investigation of issue #10155, which is related to the plugin.

Signed-off-by: Tomasz Wilczyński twilczynski@naver.com
2025-07-12 13:02:50 +00:00
tomasz1986
36fb5425a5 chore(gui): fix "Shut Down" spelling in Actions (#10213)
chore(gui): Fix "Shut Down" spelling in Actions

Currently, the word is written as "Shutdown". However, similarly to
"Log Out", it is used as a verb here, thus it should be written as two
separate words, i.e. "Shut Down".

Signed-off-by: Tomasz Wilczyński twilczynski@naver.com
2025-07-12 14:52:51 +02:00
Marcus B Spencer
32a913c0ff refactor(beacon, osutil, upnp, netutil): only use anet on Android (#10211)
Add a wrapper that uses anet on Android, but net on other platforms.

### Purpose

Fixes
https://forum.syncthing.net/t/workaround-for-android-local-discovery/20403/12

### Testing

Run two Syncthing instances with Global Discovery disabled. Pair them
with each other, don't hardcode their addresses, and verify they
connect.
2025-07-08 08:18:51 +02:00
Jakob Borg
e8cfc8acfb build: improve next version calculation for bumped prereleases 2025-07-06 20:56:56 +02:00
Jakob Borg
7c07610ab2 fix: allow deleted files to win conflict resolution (#10207)
We've always, since the introduction of conflicts, had the policy that
deletes lose against any other change, for safety's sake. This is a
problem, however, because it means the sort order of versions is not a
total order.

That is, given two versions `A` and `B` that are currently in conflict,
we will sort them in a given order (let's say `A, B`, so `A < B` for
ordering purposes: we say "A wins over B" or "A is newer than B") and
consider the first in the list the winner. The loser (who has `B` on
disk) will process the conflict at some point and move the file to a
conflict copy and announce `A'` as the resolved conflict. The winner
(with `A` on disk) doesn't do anything.

However, if `A` is deleted the ordering changes. We still have `A < B`
and, of course, `Adel < A` (this is not even a conflict, just linear
order). In most sane systems this would imply the ordering `Adel < A <
B`, however in our case we in fact have `B < Adel` because any version
wins over a deleted one, so there is no logical ordering at all of the
files at this point. `Adel < A < B < Adel ???` In practice the deleted
version may end up at the head or the tail of the list, depending on the
order we do the compares.

Hence, at this point, "whatever" happens and it's not guaranteed to make
any sense. 😬

I propose that we resolve this my simply letting deletes be versions
like anything else and maintain a total ordering based on just version
vectors with the existing tie breakers like always. That means a delete
can win in a conflict situation, and the result should be that the file
is moved to a conflict copy on the losing device. I think this retains
the data safety to almost the same degree as previously, while removing
probably an entire class of strange out of sync bugs...

---

(A potential wrinkle here is that, ideally, we wouldn't even create the
conflict copy when the delete and the losing version represent the same
data -- same as when we handle normal modification conflicts. However,
the deleted FileInfo doesn't carry any information on what the contents
were, so we can't do that right now. A possible future extension would
be to carry the block list hash of the deleted data in the deleted
FileInfo and use that for this purpose, but I don't want to complicate
this PR with that. The block list hash itself also isn't a
protocol-defined thing at the moment, it's something implementation
dependent that we just use locally.)
2025-07-06 15:22:03 +02:00
Jakob Borg
ff88430efb feat: add debug commands for folder counts and files (#10206)
This adds two debugging commands that print information directly from
the database; one for folder counts, and one for file metadata for files
matching a pattern in a folder. E.g.,

```
% syncthing debug database-counts p3jms-73gps
DEVICE   TYPE       FLAGS    DELETED  COUNT  SIZE
-local-  FILE       -------  ---      0      0
-local-  FILE       --G----  ---      2473   70094796496
-local-  DIRECTORY  -------  ---      0      0
-local-  DIRECTORY  --G----  ---      19     2432
PSEUDOP  FILE       -------  ---      2473   70094796496
PSEUDOP  FILE       -nG----  ---      0      0
PSEUDOP  DIRECTORY  -------  ---      19     2432
PSEUDOP  DIRECTORY  -nG----  ---      0      0
```

```
% syncthing debug database-file p3jms-73gps 20240929-DSCF1387
DSCF1387
DEVICE   TYPE  NAME                          SEQUENCE  DELETED  MODIFIED                        SIZE      FLAGS    VERSION             BLOCKLIST
-local-  FILE  Austin/20240929-DSCF1387.raf  1204      ---      2024-09-29T01:10:54Z            48911888  --G----  HX2ELNU:1744213700  fsQdMvUL
PSEUDOP  FILE  Austin/20240929-DSCF1387.raf  22279     ---      2024-09-29T01:10:54Z            48911888  -------  HX2ELNU:1744213700  fsQdMvUL
-local-  FILE  Austin/20240929-DSCF1387.xmp  1196      ---      2024-10-16T08:08:35.137501751Z  5579      --G----  HX2ELNU:1744213700  xDGMnepi
PSEUDOP  FILE  Austin/20240929-DSCF1387.xmp  19910     ---      2024-10-16T08:08:35.137501751Z  5579      -------  HX2ELNU:1744213700  xDGMnepi
```

The local flag bits get a string representation for the bitmask,

```
	FlagLocalUnsupported:   "u",
	FlagLocalIgnored:       "i",
	FlagLocalMustRescan:    "r",
	FlagLocalReceiveOnly:   "e",
	FlagLocalGlobal:        "G",
	FlagLocalNeeded:        "n",
	FlagLocalRemoteInvalid: "v",
```
2025-07-04 15:46:24 +02:00
Catfriend1
06dd8ee6d7 fix(pmp, netutil): workaround native code denied to discover gateway ipv4 addr on Android 14+ (#10204)
### Purpose

As discussed on the forum:
https://forum.syncthing.net/t/reviving-nat-pmp-in-v2-x-on-android-14/24554

TL;DR
Android 14+ only lets java code get the gateway IPv4 address which is
used in SyncthingNative’s NAT-PMP feature.

So I’ve added the java code to the wrapper, got the router IP address
and feeded it to SyncthingNative by setting the env var
“FALLBACK_NET_GATEWAY_IPV4”.

This revives the NAT feature:

> [Z36WU] INFO: Detected 1 NAT service

### Testing

Local build and test via Android emulator (AVD 15).
2025-07-02 20:40:38 +02:00
Jakob Borg
c0aa7b436c chore: disable golangci-lint wsl_v5 check
Apparently they renamed a check so it snuck in despite being disabled
2025-06-30 23:29:45 +02:00
Syncthing Release Automation
b80fa9dcd2 chore(gui, man, authors): update docs, translations, and contributors 2025-06-30 04:01:54 +00:00
Jakob Borg
95187bcc64 chore(protocol): minor cleanup of ClusterConfig messages; remove DisableTempIndexes option (#10202)
This makes a couple of backwards compatible changes to the
ClusterConfig:

- Remove the `ignore_permissions` and `ignore_delete` booleans which
we've never read or used for anything
- Remove the `disable_temp_indexes` boolean and option entirely. We did
use this one, and about 1% of users have set the option. The only thing
it does is inhibits sending of periodical DownloadProgress messages
while downloading data, which is a minuscule bandwidth optimisation
given that we're already sending data at the time.
- Change the `read_only` boolean (which indicated send-only folders) to
an enum `FolderType`, where the values zero and one match the existing
usage. Again, we don't actually use this value, but I can see that we
might want to and then it makes more sense for it to be more
comprehensive.
- Change the `paused` boolean to an enum `StopReason`, where zero
indicates not stopped and one indicates paused, exactly the same wire
representation as previously but leaves space for additional stop
reasons (errors etc).
2025-06-29 10:18:51 +02:00
Catfriend1
f2a5b62733 build: unset build ID in generated binaries (#10203) 2025-06-28 12:32:07 +00:00
ardevd
385ca6772c chore(gui): added spacing between folder name and error message (#10201)
### Purpose
Filesystem watcher errors didnt have any whitespace between the share
name and the error message, making it hard to read. A simple colon and
whitespace solves this issue
2025-06-28 09:06:45 +00:00
Simon Frei
88c307b65b chore(config): increase max concurrent writes default (#10200)
I lately wanted some photos on my phone, and watched them sync
excrutiatingly slowly. I am used to android being slow, but not that
slow. This restriction caught my eye and I increased it beyond the
limit (didn't spot it at first), and I did see a clear improvement. Of
course as always with such a one-off test, I might also have
hallucinated it, but it seems plausible with the slow thing in android
being some layer between the actual filesystem and apps.

Also increase the max limit, mostly just because I don't see any reason
to restrict it that low - not that I have a particular reason to want
more.

I also changed the xml default to 0: The `prepare` code will change it
to the actual default - no need to change that anymore if we change the
default in the future.
2025-06-28 08:59:50 +00:00
Catfriend1
9d425b0588 fix(beacon, osutil, upnp): fix local discovery send and intf detection on Android (#10196)
Before:
- Local discovery on Android 10+ is broken. The phone receives local
discovery packets from other devices running Syncthing on the same
network, e.g. a computer. But it doesn't send its own local discovery
packets.
- Startup of the beacon/broadcast.go and beacon/multicast.go "services"
subsequently fail, see the log entries of "service.go" with "2 of 2
failures, backing off".

Root cause:
- Android 10+ restricts determining the network interfaces for privacy
reasons. The interfaces and IP addresses cannot be determined.
- There's a bug in the go "net" library. I can actually get the
interfaces, but the fix was not implemented by the go team.

Workaround:
- The "community" found a workaround by creating a light wrapper around
"net" called "anet" library.
- "anet" adjusts the behaviour on Android 10+ and gets the interfaces
plus their IP addresses, as required by Syncthing.

After:
- By using the "anet" lib, Syncthing is able to get the interface ip
addresses and put them into the "AllAddresses" string array.
- The "AllAddresses" string array is then announced on the local
discovery multicast and broadcast packets, if enabled in Syncthing's
config.
- By correctly getting the interfaces and IP addresses using "anet" in
"beacon/broadcast.go" and "beacon/multicast.go", the services start up
fine again.

Verification: 
- I've built "libSyncthingNative.so" with this PR applied for Android
and put it into Syncthing-Fork v1.29.7.5 for testing. My two phones,
Android 10 and Android 15 (arm64-v8a) immediately discovered each other
using local discovery.
- I can see the "sent XX bytes" and "recv XX bytes" on both phones in
the log filtering for "SyncthingNativeCode" :-).

Personal note:
- Please go light on me, and, if it's not demanded too much of your
time, please help me on this. I am no go programmer. Most things you
think are easy or common sense aren't part of my knowledge set. I'd just
like to help and hope we somehow can drive this home together to fix the
problem.

----

ref: https://github.com/Catfriend1/syncthing-android/pull/1501
ref: https://github.com/Catfriend1/syncthing-android/issues/1500
ref: https://github.com/wlynxg/anet/blob/main/interface.go &
https://github.com/wlynxg/anet/blob/main/interface_android.go

With that fix, I can see the broadcast/multicast lines again and my
phone can be discovered by other phones running the Syncthing app which
wasn't possible before on Android 10+.

```
[ET76H] .346892 broadcast.go:107: DEBUG: sent 185 bytes to 192.168.x.255:21027
[ET76H] .347114 multicast.go:86: DEBUG: sent 185 bytes to [ff12::8384]:21027 on wlan0
```

---------

Co-authored-by: Marcus B Spencer <marcus@marcusspencer.us>
2025-06-25 18:18:12 +00:00
Syncthing Release Automation
cf84a260ca chore(gui, man, authors): update docs, translations, and contributors 2025-06-23 04:02:01 +00:00
Jakob Borg
c4e024c7e3 build: fix detection of next rc version 2025-06-20 11:17:48 +02:00
Jakob Borg
c5a29b5b26 fix(model): don't clobber local flags when receiving index (#10190) 2025-06-20 07:08:06 +00:00
Marcus B Spencer
4c64843d60 feat(connections, nat): add UDP portmapping/pinhole for QUIC (fixes #7403) (#10171)
Fixes #7403.

Tested by enabling UPnP on the router, and checking on the router page
that the external ports of the UDP mappings match what is shown in the
logs and the internal ports matching the QUIC listening port.
2025-06-20 04:24:45 +00:00
Jakob Borg
b4ff96d754 chore(model): log folder removal
Relevant to #10189, #8416
2025-06-18 19:33:41 +02:00
Jakob Borg
21c5ac2161 chore: remove bad comment in authors script
Closes #10185
2025-06-17 12:27:12 +02:00
tomasz1986
6fc0b41f97 feat(gui): add option to limit bandwidth in LAN to Settings (ref #10046) (#10182)
gui: Add option to limit bandwidth in LAN to Settings (ref #10046)

Currently, the option to limit bandwidth in LAN is available only via
the Advanced Configuration, which makes it difficult to discover by new
users, who are confused why their bandwidth limits are not working.

For this reason, make the option easily discoverable by adding it
directly to Connections in the normal Settings in the Web GUI.

Ref:
https://github.com/syncthing/syncthing/issues/10046
https://github.com/syncthing/syncthing/issues/2046
https://github.com/syncthing/syncthing/issues/2569
https://forum.syncthing.net/t/upload-rate-not-work/19025

https://forum.syncthing.net/t/rate-limits-dont-work-over-lan-in-v1-20-1/18521

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>

### Screenshots


![image](https://github.com/user-attachments/assets/bd38b3ab-a053-4992-ba86-7fb8b3ba09d9)

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2025-06-17 09:46:38 +02:00
yparitcher
0b0b2143ed fix(protocol): slightly loosen/correct ownership comparison criteria (fixes #9879) (#10176)
Only Require either matching UID & GID OR matching Names.

If the 2 devices have a different Name => UID mapping, they can never be
totaly equal. Therefore when syncing we try matching the Name and fall
back to the UID. However when scanning for changes we currently require
both the Name & UID to match. This leads to forever having out of sync
files back and forth, or local additions when receive only.

This patch does not change the sending behavoir. It only change what we
decide is equal for exisiting files with mismapped Name => UID,

The added testcases show the change: Test 1,5,6 are the same as current.
Test 2,3 Are what change with this patch (from false to true). Test 4 is
a subset of test 2 they is currently special cased as true, which does
not chnage.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-06-16 15:12:33 +00:00
Jakob Borg
af64140c61 fix(model): avoid flashing "Sync Waiting" unnecessarily (#10181) 2025-06-16 12:53:02 +02:00
Syncthing Release Automation
1c68062231 chore(gui, man, authors): update docs, translations, and contributors 2025-06-16 04:00:36 +00:00
Jakob Borg
4d92855d76 build: release job needs full checkout with tags 2025-06-15 10:37:37 +02:00
Jakob Borg
1c6f542cb7 build: use proper ref for build action 2025-06-15 10:21:03 +02:00
Jakob Borg
b28066c85d build: use access token to trigger release builds 2025-06-15 10:14:13 +02:00
Simon Frei
71c8a2c36f fix(db): remove invalid member from FileMetadata (#10180) 2025-06-15 09:12:25 +02:00
Simon Frei
e4ab7b4ff3 fix(watchaggregator): properly handle sub-second watch durations (fixes #9927) (#10179)
I'll let Audrius words from the ticket explain this :)

> I'm a bit lost, time.Duration is an int64, yet watcher delay is float,
> anything sub 1s gets rounded down to 0, so you just end up going into
an
> infinite loop.


https://github.com/syncthing/syncthing/issues/9927#issuecomment-2967736106
2025-06-14 00:16:22 +02:00
Simon Frei
8b978d4712 chore: add migration for remote invalid local flag (#10174)
Follow to resp. migration for the change in this commit:

7b319111d3

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-06-13 21:28:07 +00:00
Simon Frei
7b319111d3 fix: track invalid files in LocalFlags to fix global count (#10170)
Move the "invalid" bit to a local flag, making it easier to track in counts etc.
2025-06-13 07:33:31 +02:00
Simon Frei
cb7cea93a2 chore(model): remove redundant removal of internal fields in indexsender (#10173)
While it doesn't hurt, it's unnecessary since the big protobuf
modernisation, that also introduced types separate from the generated
ones for internal use. Those fields are already dropped when converting
to the wire in protocol.
2025-06-12 22:08:21 +00:00
Jakob Borg
20257faf54 build: compat entry for Go 1.25 2025-06-11 22:40:20 +02:00
ardevd
c14abebd68 refactor(syncthing): use named constant for SIGHUP (#10168) 2025-06-09 20:31:01 +00:00
ardevd
b1a1a90045 chore(syncthing): ensure response body is closed in upgrade request (#10169) 2025-06-09 22:10:17 +02:00
Jakob Borg
8afc9855f2 feat: use Ed25519 keys for sync connections (#10162)
This updates our key generation to use Ed25519 keys/certificates for
sync connections. Certificates for browser use remain ECDSA for wider
compatibility.

Ed25519 is more modern and has fewer concerns for the future than the
ECDSA curves we used previously. It is supported from Go 1.13 and
forwards, which is Syncthing 1.3.0 (October 2019).
2025-06-09 05:48:01 +00:00
Marcus B Spencer
4215058911 fix(gui): don't show dial errors for paused devices (fixes #10166) (#10167)
### Purpose

Fixes the problem where paused devices show errors from dials from
previous disconnections (#10166).

### Testing

Tested manually by reproducing using the steps in the mentioned issue.

### Screenshots

Before:

![dial
errors](https://github.com/user-attachments/assets/c12a5566-beb2-4b27-9fcb-5a6d1397028d)

After:

![no dial
errors](https://github.com/user-attachments/assets/7a31e1e6-243a-4b15-b3a1-cf226b58abe0)

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-06-09 05:38:07 +00:00
Jakob Borg
9fb1a18dbf fix(strelaypoolsrv): trivial error handling fix 2025-06-09 07:25:31 +02:00
Ross Smith II
064213ceb8 fix(fs): check for unsupported error on modern Windows (fixes #10164) (#10165)
### Purpose

Locally, on Windows 11, and on the windows-2025 GitHub runner (go 1.23
and 1.24), the `TestCopyRange` test is failing with `The request is not
supported.`

On windows-2022 and windows-2019:
```go
err == syscall.ENOTSUP
```
worked, but on Windows 11 and windows-2025, we need:
```go
errors.Is(err, errors.ErrUnsupported)
```

### Testing

Tested on Windows 11, windows-2019, windows-2022, and
[windows-2025](https://github.com/rasa/syncthing/actions/runs/15525123437/job/43703630634#step:7:2811).
2025-06-09 07:20:46 +02:00
Syncthing Release Automation
0211251b34 chore(gui, man, authors): update docs, translations, and contributors 2025-06-09 04:00:17 +00:00
Jakob Borg
1903da569b build: explicitly trigger build after pushing release tag (#10160)
Because just pushing the tag with a non-Actions token doesn't suffice,
apparently
2025-06-07 14:22:39 +00:00
Jakob Borg
b6a7beca1f build: build both Debian armel and armhf (though they are the same for us) (#10159)
Current "arm" is wrong
2025-06-07 16:04:28 +02:00
Jakob Borg
7b83e7403e build: limit golangci-lint to pull requests
Since all the existing code isn't clean
2025-06-07 15:04:30 +02:00
Jakob Borg
1915a470e9 chore: update AUTHORS 2025-06-07 14:31:58 +02:00
Jakob Borg
0b100296e1 Merge branch 'v2'
* v2: (62 commits)
  build: add dependency for next-version script
  docs: add release note mention of platforms no longer built
  build: streamline gathering of facts, checkouts (#10158)
  build: more resilient pushes to releases
  chore(etc): add option dash to upstart config
  chore(fs): linter complaints
  chore(model): the easier linter complaints
  chore(internal): linter complaints
  chore(sqlite): linter complaints
  build: allow v2 into APT candidate channel
  docs: link to Docker image, APT, in release notes
  build: refactor builds for forks/PRs
  build: use same GitHub token for releases as for translation etc pushes
  refactor(sqlite): move deleted flag into logical order in schema
  feat(config): enable multiple connections by default (#10151)
  docs: mention subcommands in release notes, use for all 2.0 releases
  docs: adjust release notes for v2.0.0
  docs: add relnotes for v2.0.0
  build: upgrade setup-zig action (#10134)
  fix(versioner): correct fs creation in test
  ...
2025-06-07 14:18:48 +02:00
Jakob Borg
e6ed3acf5f build: add dependency for next-version script 2025-06-07 14:18:12 +02:00
Jakob Borg
9f95bf3573 docs: add release note mention of platforms no longer built 2025-06-07 13:35:21 +02:00
Jakob Borg
b05ece0681 build: more resilient pushes to releases 2025-06-07 13:18:58 +02:00
Jakob Borg
5381178c46 build: streamline gathering of facts, checkouts (#10158) 2025-06-07 13:11:52 +02:00
Jakob Borg
e7f4f8306c Merge branch 'main' into v2
* main:
  build: more resilient pushes to releases
2025-06-07 09:35:00 +02:00
Jakob Borg
9922a3abd9 build: more resilient pushes to releases 2025-06-07 09:34:49 +02:00
Jakob Borg
40ab668a73 chore(etc): add option dash to upstart config 2025-06-07 08:20:48 +02:00
Jakob Borg
10d20c4800 chore(fs): linter complaints 2025-06-06 13:45:44 +02:00
Jakob Borg
700bb75016 chore(model): the easier linter complaints 2025-06-06 13:45:44 +02:00
Jakob Borg
e25de22705 chore(internal): linter complaints 2025-06-06 13:45:44 +02:00
Jakob Borg
ef6d561c66 chore(sqlite): linter complaints 2025-06-06 13:45:44 +02:00
Jakob Borg
3c92999406 build: allow v2 into APT candidate channel 2025-06-06 11:00:55 +02:00
Jakob Borg
e61b8a1ae8 docs: link to Docker image, APT, in release notes 2025-06-05 19:21:01 +02:00
Jakob Borg
706409d2f3 Merge branch 'main' into v2
* main:
  docs: link to Docker image, APT, in release notes
  build: also create relaysrv and discosrv releases
  fix(stupgrades): return latest stable & pre for each major
  fix(syncthing): avoid writing panic log to nil fd (#10154)
2025-06-05 19:19:34 +02:00
Jakob Borg
e9133ef82b docs: link to Docker image, APT, in release notes 2025-06-05 19:19:05 +02:00
Jakob Borg
67ba20d777 build: also create relaysrv and discosrv releases 2025-06-05 19:19:05 +02:00
Jakob Borg
21da0d7890 fix(stupgrades): return latest stable & pre for each major 2025-06-05 19:19:05 +02:00
ardevd
ebbe57d0ab fix(syncthing): avoid writing panic log to nil fd (#10154)
### Purpose

This change fixes a logical bug in the panic log writing where we could
end up writing to a uninitialized file descriptor.

On the very first iteration, `panicFd` is nil. We enter the if `panicFd
== nil { … }` block, check for “panic:” or “fatal error:”, and if
neither matches, we skip instantiating `panicFd` altogether. However,
immediately after, still within `if panicFd == nil { … }`, we call
`panicFd.WriteString("Panic at ...")`. But `panicFd` would in this case
be `nil`, which will cause a run‐time panic.

It's not clear to me why panicFd is only initialized if the lines start
with "panic:" or "fatal error:" so I've left that logic untouched. With
this change we at least avoid the risk of writing to a nil
filedescriptor.
## Authorship

Your name and email will be added automatically to the AUTHORS file
based on the commit metadata.

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-06-03 07:39:21 +02:00
Jakob Borg
9cf8fca03f Merge branch 'main' into v2
* main:
  chore: copyright in next-version script
2025-06-02 20:42:16 +02:00
Jakob Borg
f4abc71dcc chore: copyright in next-version script 2025-06-02 20:41:42 +02:00
Jakob Borg
2712f566ab Merge branch 'main' into v2
* main:
  build: include "v" prefix in version tags...
2025-06-02 20:00:00 +02:00
Jakob Borg
8aa02da93a build: include "v" prefix in version tags... 2025-06-02 19:59:45 +02:00
Jakob Borg
ac3f390afa Merge branch 'main' into v2
* main:
  build: use own script instead of svu
  chore(gui, man, authors): update docs, translations, and contributors
2025-06-02 19:50:34 +02:00
Jakob Borg
0e560486db build: use own script instead of svu
We use a slightly different handling of features between prereleases.
2025-06-02 19:49:23 +02:00
Syncthing Release Automation
57d413099d chore(gui, man, authors): update docs, translations, and contributors 2025-06-02 05:24:58 +00:00
Jakob Borg
8d37e8f307 Merge branch 'main' into v2
* main:
  feat(config): expose folder and device info as metrics (fixes #9519) (#10148)
  chore: add issue types to GitHub issue templates
  build: remove schedule from PR metadata job
  chore(protocol): only allow enc. password changes on cluster config (#10145)
  chore(protocol): don't start connection routines a second time (#10146)
2025-05-31 17:10:00 +02:00
Jakob Borg
1fdf07933c feat(config): expose folder and device info as metrics (fixes #9519) (#10148)
Tihs makes it easier to use metrics based on device and folder labels,
names, and other attributes. Other metrics which are based on folder or
device ID can be joined with these info metrics to enrich their label
sets.

```
# HELP syncthing_config_device_info Provides additional information labels on devices
# TYPE syncthing_config_device_info gauge
syncthing_config_device_info{device="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU",introducer="false",name="s1",paused="false",untrusted="false"} 1

# HELP syncthing_config_folder_info Provides additional information labels on folders
# TYPE syncthing_config_folder_info gauge
syncthing_config_folder_info{folder="default",label="The default folder",path="s2",paused="false",type="sendreceive"} 1
```

With this you can e.g. query for

```
syncthing_connections_active * on(device) group_left syncthing_config_device_info
```

Fixes #9519 
Closes #10074 
Closes #10147
2025-05-31 17:09:23 +02:00
Jakob Borg
d49df1e44c build: refactor builds for forks/PRs
Make sure as much as possible runs for forks and PRs as well, while
keeping the release specific stuff out of the way.
2025-05-31 09:52:27 +02:00
Jakob Borg
50480f6ccb build: use same GitHub token for releases as for translation etc pushes 2025-05-31 08:50:42 +02:00
Jakob Borg
15f693d93c refactor(sqlite): move deleted flag into logical order in schema 2025-05-31 08:39:11 +02:00
Jakob Borg
8e934a8c69 feat(config): enable multiple connections by default (#10151)
This changes the default number of connections from one to three (one
metadata + two data connections). This should give some advantages of
multiple connections, while also not being an overwhelming change for
larger installations. (Though those may need to tweak their settings
anyway, as always.)
2025-05-30 22:04:55 +02:00
Jakob Borg
c50678618f chore: add issue types to GitHub issue templates 2025-05-30 11:57:27 +02:00
Jakob Borg
8094b459e4 build: remove schedule from PR metadata job
It shouldn't have touched non-PR issues, but it did
2025-05-30 11:57:27 +02:00
Simon Frei
6765867a2e chore(protocol): only allow enc. password changes on cluster config (#10145)
In practice we already always call SetPassword and ClusterConfig
together. However it's not just "sensible" to do that, it's required: If
the passwords change, the remote device needs to know about that to
check that the enc. setup is valid/consistent (e.g. tokens match,
folder-type is appropriate, ...).
And with the passwords set later, there's no point in adding them as
part of creating a new connection.

This is a "followup" (if one can call it that 4 years later :) ) to
resp. fix for the following commit:
924b96856f

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-05-30 09:52:47 +02:00
Simon Frei
4fb8ee6a6f chore(protocol): don't start connection routines a second time (#10146) 2025-05-30 06:28:42 +00:00
Jakob Borg
79bac43800 Merge branch 'main' into v2
* main:
  build: properly propagate build tags to Debian build (#10144)
  fix(protocol): avoid deadlock with concurrent connection start and close (#10140)
  build: add labeler workflow for PRs (#10143)
  build(deps): update our notify package from upstream (#10142)
  build(deps): update dependencies (#10141)
  docs: general notes about v2 coming (#10135)
2025-05-29 17:10:03 +02:00
Jakob Borg
674834ccf4 build: properly propagate build tags to Debian build (#10144)
Previously all were ignored except noupgrade which was hard coded...
2025-05-29 15:06:57 +00:00
Jakob Borg
3bd2bff23b fix(protocol): avoid deadlock with concurrent connection start and close (#10140) 2025-05-29 14:56:58 +00:00
Jakob Borg
40660c5fb7 build: add labeler workflow for PRs (#10143)
Use labels to categorise release notes
2025-05-29 10:04:08 +02:00
Jakob Borg
d940d094a1 build(deps): update our notify package from upstream (#10142) 2025-05-28 15:04:24 +00:00
Jakob Borg
9d67727989 build(deps): update dependencies (#10141) 2025-05-28 13:52:08 +00:00
Jakob Borg
6f51700a7f docs: general notes about v2 coming (#10135)
This adds a file that will be prepended to release notes (tag messages,
GitHub releases, forum posts) for v1 releases. I'd like there to be
something there to flag that things are going to change.
2025-05-27 10:01:04 +02:00
Jakob Borg
43d33dbeb5 docs: mention subcommands in release notes, use for all 2.0 releases 2025-05-27 08:16:09 +02:00
Jakob Borg
bb91f53641 Merge branch 'main' into v2
* main:
  refactor: use slices package for sorting (#10136)
  build: handle multiple general release notes
  build: no need to build on the branches that just trigger tags
2025-05-26 21:40:54 +02:00
Marcel Meyer
598915193a refactor: use slices package for sorting (#10136)
Few more complicated usages of the sort packages are left.

### Purpose

Make progress towards replacing the sort package with slices package.
2025-05-26 20:37:49 +02:00
Jakob Borg
905e5ec07f build: handle multiple general release notes 2025-05-26 16:27:23 +02:00
Jakob Borg
5945a8c5bd docs: adjust release notes for v2.0.0 2025-05-26 15:27:53 +02:00
Jakob Borg
4075b886d0 build: no need to build on the branches that just trigger tags 2025-05-26 15:21:21 +02:00
Jakob Borg
e39dcc5c58 docs: add relnotes for v2.0.0 2025-05-26 14:54:24 +02:00
Jakob Borg
46d2c59b24 build: upgrade setup-zig action (#10134) 2025-05-26 12:53:47 +00:00
Jakob Borg
54f6b5c2ee Merge branch 'main' into v2
* main:
  build: use specific token for pushing release tags
  fix(gui): update `uncamel()` to handle strings like 'IDs' (fixes #10128) (#10131)
  refactor: use slices package for sort (#10132)
  build: process for automatic release tags (#10133)
  chore(gui, man, authors): update docs, translations, and contributors
2025-05-26 14:22:30 +02:00
Jakob Borg
cade790198 build: use specific token for pushing release tags 2025-05-26 14:13:02 +02:00
Luke Hamburg
98555a9a80 fix(gui): update uncamel() to handle strings like 'IDs' (fixes #10128) (#10131)
> ⚠️ resubmission targeting `main` instead of `v2`

### Purpose

Updates `uncamel()` function in
[uncamelFilter.js](https://github.com/syncthing/syncthing/blob/v2/gui/default/syncthing/core/uncamelFilter.js)
to fix camelCase conversion edge cases, see #10128

This adds an array called `reservedStrings` which will be printed as-is,
e.g. `IDs`, `LAN` etc. I pre-populated this with what I believe makes
sense, but of course this is easily updated.

### Testing

I compiled all the config variables I could find in
`syncthing/lib/config/*configuration.go` and tested this new function
against them. Everything seemed to pass.

### Screenshot


![Image](https://github.com/user-attachments/assets/af8c9821-58b3-4a6a-8462-bead8a6d845a)
2025-05-26 11:43:38 +00:00
Marcel Meyer
48b757cac1 refactor: use slices package for sort (#10132)
The sort package is still used in places that were not trivial to
change. Since Go 1.21 slices package can be uswed for sort. See
https://go.dev/doc/go1.21#slices

### Purpose

Make some progress with the migration to a more up-to-date syntax.
2025-05-26 13:37:26 +02:00
Jakob Borg
58c85fc9db build: process for automatic release tags (#10133)
Make the release tagging consistent. Push to release branch to create a
stable release; push to release-rc to release a new candidate.
2025-05-26 13:33:53 +02:00
Syncthing Release Automation
ddd98a818a chore(gui, man, authors): update docs, translations, and contributors 2025-05-26 03:55:20 +00:00
Jakob Borg
99b707c141 fix(versioner): correct fs creation in test 2025-05-25 22:03:19 +02:00
Jakob Borg
39d6692109 Merge branch 'main' into v2
* main:
  fix(syncthing): ensure both config and data dirs exist at startup (fixes #10126) (#10127)
  fix(versioner): fix perms of created folders (fixes #9626) (#10105)
  refactor: use slices.Contains to simplify code (#10121)
2025-05-25 10:00:53 +02:00
Jakob Borg
64b5a1b738 fix(syncthing): ensure both config and data dirs exist at startup (fixes #10126) (#10127)
Previously we'd only ensure the config dir, which is often but not
always the same as the data dir.

Fixes #10126
2025-05-25 08:10:17 +02:00
Ashish Bhate
1a131a56f2 fix(versioner): fix perms of created folders (fixes #9626) (#10105)
As suggested in the linked issue, I've updated the versioner code to use
the permissions of the corresponding directory in the synced folder,
when creating the folder in the versions directory

### Testing
- Some tests are included with the PR. Happy to add more if you think
there are some edge-cases that we're missing.
- I've tested manually on linux to confirm the permissions of the
created directories.
- I haven't tested on Windows or OSX (I don't have access to these OS)
2025-05-24 07:35:32 +02:00
pullmerge
beda37f28b refactor: use slices.Contains to simplify code (#10121)
There is a [new function](https://pkg.go.dev/slices@go1.21.0#Contains)
added in the go1.21 standard library, which can make the code more
concise and easy to read.
2025-05-23 10:36:06 +00:00
Jakob Borg
1b8a8032f0 build: target ARMv6 for linux-arm builds 2025-05-22 12:27:35 +02:00
Jakob Borg
3423de24ea Revert "build: use Go 1.24.2 specifically"
This reverts commit 4bc17bc588.
2025-05-22 12:03:41 +02:00
Jakob Borg
6532715641 Merge branch 'main' into v2
* main:
  build(deps): update dependency due to build breakage (#10120)
2025-05-22 12:02:56 +02:00
Jakob Borg
2532ac35cf build(deps): update dependency due to build breakage (#10120) 2025-05-21 06:52:29 +00:00
Jakob Borg
832fa094a3 Merge branch 'main' into v2
* main:
  chore: move golangci-lint & meta to separate PR-only workflow (#10119)
2025-05-21 08:35:12 +02:00
Jakob Borg
bcd30ceaec chore: move golangci-lint & meta to separate PR-only workflow (#10119)
For now. Existing code is not golangci-lint clean, but new PRs should
be, ideally.
2025-05-21 08:32:49 +02:00
Jakob Borg
78bfe643a8 chore: bump config version, prevent accidental downgrade 2025-05-20 15:37:19 +02:00
Jakob Borg
0a58747eb2 chore: further minor lint fixes 2025-05-20 15:04:33 +02:00
Jakob Borg
96b03fac04 chore: trivial lint fix 2025-05-20 14:34:20 +02:00
Jakob Borg
085455d72e feat: add syncthing debug database-statistics command (#10117)
This adds a command that shows database statistics. Currently it
requires a fork of the sqlite package to add the dbstats virtual table;
the modernc variant already has it.

This also provides the canonical mapping between folder ID and database
file, for tinkerers...

```
% ./bin/syncthing debug database-statistics
DATABASE                 FOLDER ID    TABLE                                  SIZE     FILL
========                 ====== ==    =====                                  ====     ====
main.db                  -            folders                               4 KiB    8.4 %
main.db                  -            folders_database_name                 4 KiB    6.0 %
main.db                  -            kv                                    4 KiB   41.1 %
main.db                  -            schemamigrations                      4 KiB    3.9 %
main.db                  -            sqlite_autoindex_folders_1            4 KiB    3.7 %
...
folder.0007-txpxsvyd.db  w3ejt-fn4dm  indexids                              4 KiB    1.5 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  kv                                    4 KiB    0.8 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  mtimes                              608 KiB   81.5 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  schemamigrations                      4 KiB    3.9 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_autoindex_blocklists_1      4108 KiB   89.5 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_autoindex_blocks_1        700020 KiB   88.1 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_autoindex_devices_1            4 KiB    3.6 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_autoindex_kv_1                 4 KiB    0.6 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_schema                        12 KiB   45.9 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_sequence                       4 KiB    1.0 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_stat1                          4 KiB   12.2 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  sqlite_stat4                          4 KiB    0.2 %
folder.0007-txpxsvyd.db  w3ejt-fn4dm  (total)                         1906020 KiB   92.8 %
main.db + children       -            (total)                         2205888 KiB   92.0 %
```
2025-05-20 14:27:08 +02:00
Jakob Borg
72849690c9 fix(model): index handler error handling 2025-05-20 14:26:14 +02:00
Jakob Borg
f09cca52f2 Merge branch 'main' into v2
* main:
  build: reactivate golangci-lint (#10118)
  chore(gui): add Serbian (sr) translation template (#10116)
  chore(gui, man, authors): update docs, translations, and contributors
2025-05-20 14:05:29 +02:00
Jakob Borg
9a3493c2f4 build: reactivate golangci-lint (#10118)
With DeepSource becoming (imho) less and less useful, let's get this one
back on track. It will likely require adjusting over time.
2025-05-20 14:03:43 +02:00
André Colomb
fa404d5a0d chore(gui): add Serbian (sr) translation template (#10116)
Based on user request from Weblate, user `@vlazic`.
2025-05-19 21:06:38 +00:00
Syncthing Release Automation
73ad18fbfb chore(gui, man, authors): update docs, translations, and contributors 2025-05-19 03:56:31 +00:00
Jakob Borg
a4db309b39 chore: refine author list generation
Now applies a slightly narrower definition of "author", being one that
has touched code in a file that exists today (tracking renames).
2025-05-17 16:56:56 +02:00
Jakob Borg
4bc17bc588 build: use Go 1.24.2 specifically
https://github.com/golang/go/issues/73617
2025-05-17 00:37:36 +02:00
Jakob Borg
964c8d7d65 fix(model): correct bufferpool handling; simplify (#10113)
The copier routine refactor resulted in bad buffer pool handling,
putting a buffer back into the pool twice. This simplifies and removes
the danger prone Upgrade() method.
2025-05-16 22:50:13 +02:00
Jakob Borg
bacf506e90 Merge branch 'main' into v2
* main:
  chore(gui, man, authors): update docs, translations, and contributors
  fix(config): mark audit log options as needing restart (fixes #10099) (#10100)
  fix(config): deep copy configuration defaults (fixes #9916) (#10101)
2025-05-16 16:17:43 +02:00
Syncthing Release Automation
1dd264894a chore(gui, man, authors): update docs, translations, and contributors 2025-05-12 03:54:02 +00:00
Marcus B Spencer
8c3d2f3bc5 fix(config): mark audit log options as needing restart (fixes #10099) (#10100)
### Testing

Change the `auditEnabled` option and you should get a prompt in the Web
GUI.
Restart and change the `auditFile` option, and you should get that same
prompt.

The prompt you should get is shown in the screenshots below.

### Screenshots


![Screenshot_20250507_122546](https://github.com/user-attachments/assets/23ce7c42-5e60-4f88-ac58-f312a9a1f5cc)

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-05-09 10:49:11 +00:00
Hazem Krimi
702ed8ecc1 fix(config): deep copy configuration defaults (fixes #9916) (#10101)
### Purpose

Setting default configuration was not working properly since the
defaults struct is not deeply copied.

### Testing

Try running commands to change default configuration and either inspect
`config.xml` or `/rest/config` result to see the applied changed.
Example:
```
./syncthing cli config defaults folder versioning params set keep 5
```
2025-05-09 07:40:32 +02:00
Jakob Borg
70bb4459be Merge branch 'main' into v2
* main:
  chore(gui, man, authors): update docs, translations, and contributors
  feat(gui): close a modal when pressing ESC after switching modal tabs (fixes #9489) (#10092)
2025-05-06 09:59:02 +02:00
Syncthing Release Automation
b038650810 chore(gui, man, authors): update docs, translations, and contributors 2025-05-05 03:52:42 +00:00
Simon Frei
821d6f43ac chore(model): refactor copier for more flatness (#10094)
Flattened the copier code more. Also removing and moving some
parameters/return values to simplify things. Generally rely less on
return values, e.g. by handling errors right away and using `state` to
do the right thing (e.g. abort on failure).

Supposed to be a refactor without any behaviour changes, except for
fixing a tiny regression on folder order: We used to try copying from
the same folder first, but lost that property at some point (also sent a
PR fixing only that, I'd merge that first making this refactor only).
2025-05-04 09:23:57 +02:00
Hazem Krimi
a16bf555c0 feat(gui): close a modal when pressing ESC after switching modal tabs (fixes #9489) (#10092)
### Purpose

As stated in #9489 after clicking on a tab link to switch tabs in a
modal you can no longer close the modal through clicking the ESC key
unless you click anywhere on the modal to focus on it again.

### Testing

- Click on a modal that has tabs like "Settings" or "Add Folder" and
switch tabs then click on ESC.
- Check if clicking outside of a modal in the backdrop should still
close the modal.

### Demo


https://github.com/user-attachments/assets/a010db9a-72f7-4160-a7db-ddfebffb4834
2025-05-02 14:53:54 +00:00
Simon Frei
fa7b81e1cf fix(model): use same folder first in copier (#10093)
Where `folderFilesystems` and `folders` is built, there's a comment
spelling out the purpose: To have the same folder first, as that's the
most likely to get hits. Plus a copy is possibly more efficient than
from another folder, e.g. if that's on a different filesystem. We lost
that behaviour during some unrelated change.

(Also sneaking in a comment fix on yesterdays change.)
2025-05-02 13:15:26 +02:00
Jakob Borg
516f1aa0c7 Merge branch 'main' into v2
* main:
  build(deps): update dependencies (#10091)
2025-05-01 14:11:27 -05:00
Simon Frei
6b94599467 chore(db, model): simplify per hash DB lookup in copier (#10080)
This is a draft because I haven't adjusted all the tests yet, I'd like
to get feedback on the change overall first, before spending time on
that.

In my opinion the main win of this change is in it's lower complexity
resp. fewer moving parts. It should also be faster as it only does one
query instead of two, but I have no idea if that's practically
relevant.

This also mirrors the v1 DB, where a block map key had the name
appended. Not that this is an argument for the change, it was mostly
reassuring me that I might not be missing something key here
conceptually (I might still be of course, please tell me :) ).

And the change isn't mainly intrinsically motivated, instead it came
up while fixing a bug in the copier. And the nested nature of that code
makes the fix harder, and "un-nesting" it required me to understand
what's happening. This change fell out of that.
2025-05-01 13:44:25 -05:00
xjtdy888
f183d1cbec chore(syncthing): ensure migrated database is closed before exiting (#10076)
After opening the database, we performed some checks, such as whether
the migration had already been successfully completed. If so, the
function returned immediately, and the database was not closed.

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-05-01 18:36:35 +00:00
Jakob Borg
cd6ea60fa1 build(deps): update dependencies (#10091)
Without bumping Go version
2025-05-01 18:15:37 +00:00
Simon Frei
58bf2b5515 fix(model): close fd immediately in copier (#10079) 2025-05-01 10:15:02 -05:00
Jakob Borg
d28be1b711 fix: handle null database name in getGolderDB 2025-04-30 14:34:53 -05:00
Jakob Borg
47e3147d0b fix: don't hold main database update lock when tidying folder databases 2025-04-30 14:28:05 -05:00
Jakob Borg
2159dfd27d Merge branch 'main' into v2
* main:
  fix(strelaysrv): make the session limiter session-dependent (fixes #10072) (#10073)
  build: artifact uploads destination OCI
  chore(gui, man, authors): update docs, translations, and contributors
  chore(gui): use go list --deps for dependency list (#10071)
2025-04-30 10:11:33 -05:00
domain
0bf21d9db2 fix(strelaysrv): make the session limiter session-dependent (fixes #10072) (#10073)
### Purpose

Make the session limiter only apply to current session.

### Testing

Relay 2 or more sessions and check if the sum of the connection speed
can exceed the specified per-session rate.

2 sessions (-global-rate=50000000 and -per-session-rate=6250000):


![图片](https://github.com/user-attachments/assets/133e531a-ed49-4890-aef7-821c628bcfc8)

1 session (-global-rate=50000000 and -per-session-rate=6250000):


![图片](https://github.com/user-attachments/assets/ac89ea53-2d8e-4347-9bbc-4780d85e38d7)
2025-04-30 14:25:01 +00:00
Jakob Borg
f61843ef2e build: artifact uploads destination OCI 2025-04-29 14:01:25 -05:00
Syncthing Release Automation
23e8366f8d chore(gui, man, authors): update docs, translations, and contributors 2025-04-28 03:52:12 +00:00
Jakob Borg
ed252ed6d7 fix(sqlite): hold update lock while generating folder idx 2025-04-27 23:19:07 +05:30
Ross Smith II
93e72cc83f chore(gui): use go list --deps for dependency list (#10071) 2025-04-26 02:24:31 +00:00
Jakob Borg
abe34fc1f6 Merge branch 'main' into v2
* main:
  feat(config): add option for audit file (fixes #9481) (#10066)
  chore(api): log X-Forwarded-For (#10035)
  chore(gui): update dependency copyrights, add script for periodic maintenance (#10067)
  chore(gui, man, authors): update docs, translations, and contributors
  chore(syncthing): remove support for TLS 1.2 sync connections (#10064)
  fix(osutil): give threads same I/O priority on Linux (#10063)
  chore(stun): switch lookup warning to debug level
  chore(gui, man, authors): update docs, translations, and contributors
2025-04-24 08:47:52 +07:00
Simon Frei
be002362b3 fix(model): loop-break regression while block copying in puller (#10069) 2025-04-24 08:29:30 +07:00
Marcus B Spencer
190dff142c feat(config): add option for audit file (fixes #9481) (#10066) 2025-04-23 22:32:23 +07:00
bt90
c667ada63a chore(api): log X-Forwarded-For (#10035)
### Purpose

Fix https://github.com/syncthing/syncthing/issues/9336

The `emitLoginAttempt` function now checks for the presence of an
`X-Forwarded-For` header. The IP from this header is only used if the
connecting host is either on loopback or on the same LAN.

In the case of a host pretending to be a proxy, we'd still have both IPs
in the logs, which should make this much less critical from a security
standpoint.

### Testing

1. directly via localhost
2. via proxy an localhost

#### Logs

```
[3JPXJ] 2025/04/11 15:00:40 INFO: Wrong credentials supplied during API authorization from 127.0.0.1
[3JPXJ] 2025/04/11 15:03:04 INFO: Wrong credentials supplied during API authorization from 192.168.178.5 proxied by 127.0.0.1
```

#### Event API

```
  {
    "id": 23,
    "globalID": 23,
    "time": "2025-04-11T15:00:40.578577402+02:00",
    "type": "LoginAttempt",
    "data": {
      "remoteAddress": "127.0.0.1",
      "success": false,
      "username": "sdfsd"
    }
  },
  {
    "id": 24,
    "globalID": 24,
    "time": "2025-04-11T15:03:04.423403976+02:00",
    "type": "LoginAttempt",
    "data": {
      "proxy": "127.0.0.1",
      "remoteAddress": "192.168.178.5",
      "success": false,
      "username": "sdfsd"
    }
  }
```

### Documentation

https://github.com/syncthing/docs/pull/907

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-04-23 06:01:13 +00:00
Jakob Borg
50480b89fc chore(syncthing): remove "default" folder concept (#10068)
This removes the creation of the `default` folder on startup. My feeling
is that the concept is not widely used or appreciated.
2025-04-23 05:59:24 +00:00
Ross Smith II
93ae30d889 chore(gui): update dependency copyrights, add script for periodic maintenance (#10067)
### Purpose

This PR parses the output of `go mod graph` and updates the copyright
list in our [about
modal](486eebc4ac/gui/default/syncthing/core/aboutModalView.html (L38)).

If there are no changes, the program is silent. Otherwise, it reports
what additions, and deletions it made. It does not rewrite existing
copyright notices, but it does remove notices that we no longer use, as
well as add new ones.

It uses a GitHub API to try to determine the copyright string in the
license file. If one is not found, it defaults to `Copyright &copy;
<this_year> the <owner/repo> authors`. If a proper copyright is found,
simply update the notice in `aboutModalView.html`, and it will be used.
2025-04-23 12:41:05 +07:00
Syncthing Release Automation
486eebc4ac chore(gui, man, authors): update docs, translations, and contributors 2025-04-21 03:52:26 +00:00
Jakob Borg
ff33d976d1 chore(syncthing): remove support for TLS 1.2 sync connections (#10064)
This cleans up the option to allow old TLS 1.2 sync connections. The
flag existed for compatibility with old Syncthing versions that don't
support TLS 1.3, which is approximately Syncthing 1.2.2 (September 2019)
and older. ("Approximately" because it depends on the Go version it's
built with and that's when we switched to building with Go 1.13.)

Ref #10062 because it reminded me this exists.
2025-04-21 10:30:43 +07:00
TheCreeper
69890b4282 fix(osutil): give threads same I/O priority on Linux (#10063) 2025-04-21 02:30:52 +00:00
Jakob Borg
533c9a6ab0 chore(stun): switch lookup warning to debug level 2025-04-17 07:29:10 +07:00
Syncthing Release Automation
9521bb3931 chore(gui, man, authors): update docs, translations, and contributors 2025-04-14 03:51:01 +00:00
Jakob Borg
25e03ef9ab Merge branch 'main' into v2
* main:
  chore: add missing copyright in new files from infra branch (#10055)
2025-04-13 14:46:30 +02:00
Jakob Borg
e46a0f99c3 chore: add missing copyright in new files from infra branch (#10055)
Let's see if it passes
2025-04-13 09:25:16 +00:00
Jakob Borg
ed6575411f Merge branch 'main' into v2
* main:
  feat(stdiscosrv): configurable desired not-found rate
  chore(blobs): generalised blob storage
  chore(stdiscosrv): path style s3
  feat(ursv): add os/arch/distribution metric
  chore(strelaypoolsrv): limit number of returned relays
  build(infra): run in Docker environment for pushes
  chore(stupgrades): expose latest release as a metric
  feat(api, gui): allow authentication bypass for metrics (#10045)
2025-04-13 09:44:09 +02:00
Jakob Borg
ed97e365b2 Merge branch 'infrastructure'
* infrastructure:
  feat(stdiscosrv): configurable desired not-found rate
  chore(blobs): generalised blob storage
  chore(stdiscosrv): path style s3
  feat(ursv): add os/arch/distribution metric
  chore(strelaypoolsrv): limit number of returned relays
  build(infra): run in Docker environment for pushes
  chore(stupgrades): expose latest release as a metric
2025-04-13 09:41:45 +02:00
Jakob Borg
b4776ea4e0 feat(stdiscosrv): configurable desired not-found rate 2025-04-13 09:41:16 +02:00
Jakob Borg
b5ffd0a796 chore(blobs): generalised blob storage 2025-04-13 09:41:16 +02:00
Jakob Borg
c74299b59a chore(stdiscosrv): path style s3 2025-04-13 09:40:14 +02:00
Jakob Borg
8b6d837483 feat(ursv): add os/arch/distribution metric 2025-04-13 09:40:14 +02:00
Jakob Borg
3e74b3dee2 chore(strelaypoolsrv): limit number of returned relays
Avoid unnecessarily enormous responses by returning a random subset of
relays.
2025-04-13 09:40:14 +02:00
Jakob Borg
2902da996c build(infra): run in Docker environment for pushes 2025-04-13 09:40:14 +02:00
Jakob Borg
f6f144bf17 chore(stupgrades): expose latest release as a metric 2025-04-13 09:40:11 +02:00
Sébastien WENSKE
ab5c42f4a0 feat(api, gui): allow authentication bypass for metrics (#10045)
### Purpose

Give the ability to skip authentication for prometheus metrics
("/metrics").

### Testing

When authentication is enabled and "Metrics Without Auth" is checked
(not the default), the "/metrics" path remains accessible even when
disconnected.

### Screenshots


![image](https://github.com/user-attachments/assets/144b696b-dd72-46f4-94d5-cd21848e4a4c)

### Documentation

https://github.com/syncthing/docs/pull/906
2025-04-13 07:35:57 +00:00
Jakob Borg
780b8fd3bc Merge branch 'main' into v2
* main:
  build: push artifacts to Azure (#10044)
  fix(syncthing): use separate lock file instead of locking the certificate (fixes #10053) (#10054)
  fix(syncthing): use separate lock file instead of locking the certificate (fixes #10053) (#10054)
2025-04-12 15:16:36 +02:00
Jakob Borg
7db3f7eaac Merge branch 'release-1.29.5'
* release-1.29.5:
  build: push artifacts to Azure (#10044)
  fix(syncthing): use separate lock file instead of locking the certificate (fixes #10053) (#10054)
2025-04-12 14:57:04 +02:00
Jakob Borg
f0b666269b build: push artifacts to Azure (#10044)
Provider migration
2025-04-12 14:55:24 +02:00
Jakob Borg
190a59842c fix(syncthing): use separate lock file instead of locking the certificate (fixes #10053) (#10054)
Apparently that nukes the cert under some circumstances on some Windows
🤷
2025-04-12 14:49:23 +02:00
Jakob Borg
40888c1a66 fix(syncthing): use separate lock file instead of locking the certificate (fixes #10053) (#10054)
Apparently that nukes the cert under some circumstances on some Windows
🤷
2025-04-12 14:46:57 +02:00
Jakob Borg
ddea2e449c fix(db): version vector serialisation :( (#10050)
ffs
2025-04-09 17:46:49 +02:00
Jakob Borg
7cfa871d58 fix(db): skip invalid files as remote need when local is deleted 2025-04-09 16:24:17 +02:00
Jakob Borg
95b39a791d Merge branch 'main' into v2
* main:
  fix(gui): fix previous commit
  fix(gui): mark unseen disconnected devices as inactive (#10048)
  fix(strings): differentiate setup(n) and set(v) up (#10024)
  chore(fs): changes to allow Filesystem to be implemented externally (#10040)
  chore(config): resolve primary STUN servers via SRV record (fixes #10029) (#10031)
  build: push artifacts to Azure (#10044)
  chore(gui, man, authors): update docs, translations, and contributors
2025-04-09 15:40:25 +02:00
Jakob Borg
fa0d933e49 fix(gui): fix previous commit 2025-04-09 15:39:09 +02:00
Tommy van der Vorst
e0c1abc5fe fix(sqlite): apply options (#10049)
@calmh it seems `sqlite.Open` forgets to apply options supplied to it
(currently only the delete retention interval).
2025-04-09 06:29:46 +02:00
tomasz1986
8372c0288f fix(gui): mark unseen disconnected devices as inactive (#10048)
Currently, the "Disconnected (Inactive)" status is only given to devices
that have not been seen for 7 days or longer. However, this is not the
case when adding a new device, or after resetting the database. Those
devices are only marked as "Disconnected", and they will stay like that
even if a long time passes without any connectivity. Moreover, the lack
of an "Inactive" status may confuse the user to believe that their
disconnect is only temporary.

For this reason, always mark devices that have not been seen yet as
"Disconnected (Inactive)".

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2025-04-08 22:08:00 +02:00
Paul Donald
5f5d672a7d fix(strings): differentiate setup(n) and set(v) up (#10024)
Correct GUI strings, translations and comments to use proper grammar.
2025-04-08 12:45:05 +00:00
Tommy van der Vorst
d23cd197e1 chore(fs): changes to allow Filesystem to be implemented externally (#10040)
### Purpose

The `fs.Filesystem` interface contains two parts that cannot be
implemented externally because they are private:

* `filesystemWrapperType`: this PR changes `unwrapFilesystem` to
downcast to a specific concrete type
* `underlying`: this PR simply moves it to an unexported interface

### Testing

Regular tests pass.
2025-04-08 12:39:39 +00:00
bt90
d7ca483df1 chore(config): resolve primary STUN servers via SRV record (fixes #10029) (#10031)
### Purpose

Fixes #10029

### Testing

```
[3JPXJ] 2025/04/03 14:36:44.601454 stun.go:146: DEBUG: Running stun for Stun@udp://[::]:22000 via fyc5mja4mz5s0vmz1txx.syncthing.net:9999
[3JPXJ] 2025/04/03 14:36:54.185157 stun.go:170: DEBUG: Stun@udp://[::]:22000 stun discovery on fyc5mja4mz5s0vmz1txx.syncthing.net:9999 resulted in no address
[3JPXJ] 2025/04/03 14:36:54.185204 stun.go:146: DEBUG: Running stun for Stun@udp://[::]:22000 via stun.internetcalls.com:3478
```

### Documentation

https://github.com/syncthing/docs/pull/904
2025-04-08 12:23:57 +00:00
Jakob Borg
e48be98cd5 build: push artifacts to Azure (#10044)
Provider migration
2025-04-08 09:43:19 +02:00
Jakob Borg
cbded11c43 Merge branch 'main' into v2
* main:
  fix(config): zero filesystemtype is "basic" (#10038)
2025-04-07 11:43:08 +02:00
Jakob Borg
d5aa991b73 chore(db): use pseudo random naming for folder databases 2025-04-07 11:35:31 +02:00
Jakob Borg
05210d0325 fix(db): wrong prepare method 2025-04-07 10:58:14 +02:00
Jakob Borg
55da878452 chore: improved perf stats 2025-04-07 09:10:16 +02:00
Syncthing Release Automation
e9a2ff3aa6 chore(gui, man, authors): update docs, translations, and contributors 2025-04-07 03:50:00 +00:00
Jakob Borg
c9650fc7d5 chore(model): delay starting a pull while there are incoming index updates (#10041)
This adds a simple delay to the process for starting the pull, by
default one second. In practice this means we're likely to wait for
initial index transfer, or multiple messages sent as part of a larger
change. This is better because we're more likely to have the whole
change for the purpose of handling renames etc, and also it's more
efficient to do one larger puller iteration instead of multiple while
also processing changes.

It does however introduce a certain amount of delay into the sync
process, so it can be tuned down or turned off entirely.
2025-04-06 14:31:02 +02:00
Jakob Borg
cf1cf85ce6 chore(db): use one SQLite database per folder (#10042)
This changes the database structure to use one database per folder, with
a small main database to coordinate. Reverts the prior change to buffer
all files in memory when pulling, meaning there is now a phase where the
WAL file will grow significantly, at least for initial sync of folders
with many directories.

---------

Co-authored-by: bt90 <btom1990@googlemail.com>
2025-04-06 14:30:43 +02:00
Jakob Borg
2301f72c5b fix(config): zero filesystemtype is "basic" (#10038)
For legacy purposes
2025-04-04 19:28:39 +00:00
Jakob Borg
7d51b1b620 Merge branch 'main' into v2
* main:
  fix(config): properly apply defaults when reading folder configuration (#10034)
  chore(model): add metric for total number of conflicts (#10037)
  build: replace underscore in Debian version (#10032)
2025-04-04 19:05:08 +02:00
Tommy van der Vorst
f7c8efd93c fix(config): properly apply defaults when reading folder configuration (#10034) 2025-04-04 16:46:12 +00:00
Sébastien WENSKE
3e7ccf7c48 chore(model): add metric for total number of conflicts (#10037) 2025-04-04 09:24:04 -07:00
Jakob Borg
fa3b9acca3 chore(db): buffer pulled files for smaller WAL (#10036)
We can't hold a long select open while pulling.
2025-04-04 08:15:59 +02:00
bt90
bae976905c chore(db): fix debug logging (#10033)
Looks like a copy&paste error
2025-04-03 20:21:39 +02:00
bt90
6bc2784e9a build: replace underscore in Debian version (#10032)
The workflow building Debian packages chokes on branches containing
underscores:

```
{:timestamp=>"2025-04-03T10:31:46.749835+0000", :message=>"Invalid package configuration: The version looks invalid for Debian packages. Debian version field must contain only alphanumerics and . (period), + (plus), - (hyphen) or ~ (tilde). I have '1.29.5~dev.13.ga38df11f~srv_stun' which which isn't valid.", :level=>:error}
```

This replaces the offending `_` with a `~` which should yield a valid
version.
2025-04-03 14:28:33 +02:00
Jakob Borg
1dbdd6b720 Merge branch 'main' into v2
* main:
  feat(fs, config): add support for custom filesystem type construction (#9887)
  build(deps): update dependencies (#10020)
2025-04-03 10:21:01 +02:00
Tommy van der Vorst
f15d50c2e8 feat(fs, config): add support for custom filesystem type construction (#9887)
For Synctrain I would like to create a virtual filesystem that exposes
iOS' photo library. This can only be accessed through APIs.
2025-04-03 10:12:23 +02:00
Jakob Borg
8a2d8ebf81 chore: configurable delete retention interval (#10030)
Command line flag, as it also needs to be able to take effect during
migration.
2025-04-03 09:55:19 +02:00
Jakob Borg
b88aea34b6 fix(syncthing): make directory flags global for all commands (#10028)
The home/config/data flags and end vars apply equally to all subcommands
2025-04-03 08:58:46 +02:00
Jakob Borg
82a0dd8eaa chore(db): use shorter read transactions and periodic checkpoint for smaller WAL (#10027)
Also make sure our journal size limit is in effect when checkpointing.
2025-04-02 22:19:34 +02:00
Jakob Borg
4096a35b86 fix(db): handle large numbers of blocks in update (#10025)
Avoid failure when inserting file with very large block list
2025-04-02 19:35:37 +02:00
Jakob Borg
86cbc2486f chore: forget deleted files older than six months (fixes #6284) (#10023)
This reduces the number of file entries we carry in the database,
sometimes significantly. The downside is that if a file is deleted while
a device is offline, and that device comes back more than the cutoff
interval (six months) later, those files will get resurrected at some
point.
2025-04-02 14:58:59 +02:00
bt90
0bcc31d058 chore(db): increase journal limit to 64MiB (#10022)
The current limit is far too low for our workloads. Perhaps we should
aim even higher than the 64MiB this patch proposes?

Citing the sqlite docs:

> [...] after committing a transaction the rollback journal file may
remain in the file-system. **This increases performance for subsequent
transactions since overwriting an existing file is faster than append to
a file**, but it also consumes file-system space.

tl;dr: if the limit is too low, we're shooting ourselves in the foot in
terms of performance.
2025-04-02 14:52:44 +02:00
Jakob Borg
2c3a890d2f fix(syncthing): remove duplicate --no-console flag 2025-04-02 12:26:24 +02:00
Jakob Borg
f9007ed106 build(deps): update dependencies (#10020)
deps deps deps
2025-04-02 08:51:37 +02:00
Jakob Borg
2953630bc3 Merge branch 'main' into v2
* main:
  chore(fs): speed up case normalization (#10013)
  chore(config): remove discontinued secondary STUN servers (fixes #10011) (#10012)
  chore(gui, man, authors): update docs, translations, and contributors
  fix(stun): better error handling (ref #10008) (#10010)
  fix(config): remove discontinued primary STUN server (fixes #10008) (#10009)
  fix(gui): validate device ID in canonical form (fixes #7291) (#10006)
2025-04-01 13:43:33 +02:00
Jakob Borg
a99e670ebb chore: harmonise command line flags (#10007)
(v2 change)

This cleans up the command line parsing a little:
- Remove the hack for supporting legacy single-dash long options (e.g.
`-home`), thus enabling actual short options
- Move legacy imperative flags from under the serve command into
separate commands, e.g. `syncthing serve --paths` to see the paths list
is now `syncthing paths`, `syncthing --upgrade-check` is now `syncthing
upgrade --check`
- Add environment variable support for all remaining flags for the
`serve` command (with one exception, left for the reader to discover),
as these are now all modifiers and not imperative

```
% syncthing --help
Usage: syncthing <command>

Flags:
  -h, --help    Show context-sensitive help.

Commands:
  serve                  Run Syncthing (default)
  cli                    Command line interface for Syncthing
  browser                Open GUI in browser, then exit
  decrypt                Decrypt or verify an encrypted folder
  device-id              Show device ID, then exit
  generate               Generate key and config, then exit
  paths                  Show configuration paths, then exit
  upgrade                Perform or check for upgrade, then exit
  version                Show current version, then exit
  debug                  Various debugging commands
  install-completions    Print commands to install shell completions

Run "syncthing <command> --help" for more information on a command.
```

```
% syncthing serve --help
Usage: syncthing serve [flags]

Run Syncthing (default)

Flags:
  -h, --help                          Show context-sensitive help.

  -C, --config=PATH                   Set configuration directory (config and keys) ($STCONFDIR)
  -D, --data=PATH                     Set data directory (database and logs) ($STDATADIR)
  -H, --home=PATH                     Set configuration and data directory ($STHOMEDIR)
      --allow-newer-config            Allow loading newer than current config version ($STALLOWNEWERCONFIG)
      --audit                         Write events to audit file ($STAUDIT)
      --auditfile=PATH                Specify audit file (use "-" for stdout, "--" for stderr) ($STAUDITFILE)
      --db-maintenance-interval=8h    Database maintenance interval ($STDBMAINTINTERVAL)
      --gui-address=URL               Override GUI address (e.g. "http://192.0.2.42:8443") ($STGUIADDRESS)
      --gui-apikey=API-KEY            Override GUI API key ($STGUIAPIKEY)
      --no-console                    Hide console window ($STHIDECONSOLE)
      --logfile=PATH                  Log file name (see below) ($STLOGFILE)
      --logflags=BITS                 Select information in log line prefix (see below) ($STLOGFLAGS)
      --log-max-old-files=N           Number of old files to keep (zero to keep only current) ($STNUMLOGFILES)
      --log-max-size=BYTES            Maximum size of any file (zero to disable log rotation) ($STLOGMAXSIZE)
      --no-browser                    Do not start browser ($STNOBROWSER)
      --no-default-folder             Don't create the "default" folder on first startup ($STNODEFAULTFOLDER)
      --no-port-probing               Don't try to find free ports for GUI and listen addresses on first startup ($STNOPORTPROBING)
      --no-restart                    Do not restart Syncthing when exiting due to API/GUI command, upgrade, or crash ($STNORESTART)
      --no-upgrade                    Disable automatic upgrades ($STNOUPGRADE)
      --paused                        Start with all devices and folders paused ($STPAUSED)
      --unpaused                      Start with all devices and folders unpaused ($STUNPAUSED)
      --verbose                       Print verbose log output ($STVERBOSE)
      --debug-gui-assets-dir=PATH     Directory to load GUI assets from ($STGUIASSETS)
      --debug-perf-stats              Write running performance statistics to perf-$pid.csv (Unix only) ($STPERFSTATS)
      --debug-profile-block           Write block profiles to block-$pid-$timestamp.pprof every 20 seconds ($STBLOCKPROFILE)
      --debug-profile-cpu             Write a CPU profile to cpu-$pid.pprof on exit ($STCPUPROFILE)
      --debug-profile-heap            Write heap profiles to heap-$pid-$timestamp.pprof each time heap usage increases ($STHEAPPROFILE)
      --debug-profiler-listen=ADDR    Network profiler listen address ($STPROFILER)
      --debug-reset-delta-idxs        Reset delta index IDs, forcing a full index exchange
...
```
2025-04-01 13:42:16 +02:00
bt90
05cc6b0f43 chore(fs): speed up case normalization (#10013)
### Purpose

Resurrecting https://github.com/syncthing/syncthing/pull/9365

### Testing

Current benchmark results:

```
goos: linux
goarch: amd64
pkg: github.com/syncthing/syncthing/lib/fs
cpu: AMD EPYC 7763 64-Core Processor                
                                           │  ../old.txt  │             ../new.txt              │
                                           │    sec/op    │   sec/op     vs base                │
UnicodeLowercase/ASCII_lowercase-4            43.68n ± 4%   12.19n ± 1%  -72.09% (p=0.000 n=10)
UnicodeLowercase/ASCII_mixedcase_start-4     200.65n ± 2%   59.49n ± 3%  -70.35% (p=0.000 n=10)
UnicodeLowercase/ASCII_mixedcase_end-4        95.50n ± 2%   59.10n ± 2%  -38.12% (p=0.000 n=10)
UnicodeLowercase/Latin1_lowercase-4           122.5n ± 1%   131.4n ± 1%   +7.27% (p=0.000 n=10)
UnicodeLowercase/Latin1_mixedcase_start-4     339.9n ± 2%   309.2n ± 1%   -9.05% (p=0.000 n=10)
UnicodeLowercase/Latin1_mixedcase_end-4       183.6n ± 2%   174.3n ± 1%   -5.04% (p=0.000 n=10)
UnicodeLowercase/Unicode_lowercase-4          456.6n ± 1%   440.5n ± 1%   -3.53% (p=0.000 n=10)
UnicodeLowercase/Unicode_mixedcase_start-4    625.9n ± 1%   595.6n ± 1%   -4.83% (p=0.000 n=10)
UnicodeLowercase/Unicode_mixedcase_end-4      516.2n ± 1%   495.5n ± 1%   -4.02% (p=0.000 n=10)
geomean                                       214.1n        150.4n       -29.72%

                                           │  ../old.txt  │             ../new.txt              │
                                           │     B/op     │    B/op     vs base                 │
UnicodeLowercase/ASCII_lowercase-4           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/ASCII_mixedcase_start-4     24.00 ± 0%     24.00 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/ASCII_mixedcase_end-4       24.00 ± 0%     24.00 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_lowercase-4          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_mixedcase_start-4    32.00 ± 0%     32.00 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_mixedcase_end-4      32.00 ± 0%     32.00 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_lowercase-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_mixedcase_start-4   48.00 ± 0%     48.00 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_mixedcase_end-4     48.00 ± 0%     48.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                 ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                           │  ../old.txt  │             ../new.txt              │
                                           │  allocs/op   │ allocs/op   vs base                 │
UnicodeLowercase/ASCII_lowercase-4           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/ASCII_mixedcase_start-4     1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/ASCII_mixedcase_end-4       1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_lowercase-4          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_mixedcase_start-4    1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Latin1_mixedcase_end-4      1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_lowercase-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_mixedcase_start-4   1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
UnicodeLowercase/Unicode_mixedcase_end-4     1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                 ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

I think the `+7%` for the lowercase Latin1 testcase is easily outweighed
by the ASCII and unicode improvements 🙂
2025-04-01 13:41:57 +02:00
Marcus B Spencer
1efcfeb3ad chore(config): remove discontinued secondary STUN servers (fixes #10011) (#10012)
Similarly to #10009, we will remove some discontinued STUN servers,
except instead of being the official primary server, it's some
unofficial secondary STUN servers.

### Testing

Use a STUN client (like [`pystun3`](https://pypi.org/project/pystun3))
to probe that the removed STUN servers are inactive.

### Documentation

syncthing/docs#902
2025-03-31 06:41:33 +00:00
Syncthing Release Automation
93195911bd chore(gui, man, authors): update docs, translations, and contributors 2025-03-31 03:50:00 +00:00
Jakob Borg
6085e3a5eb fix(stun): better error handling (ref #10008) (#10010) 2025-03-30 11:56:29 -07:00
Marcus B Spencer
e5b72da607 fix(config): remove discontinued primary STUN server (fixes #10008) (#10009)
The mechanism for primary STUN servers, is still intact, in case this
gets retried with a different domain.

### Purpose

As seen in [stun.syncthing.net doesn’t resolve
anymore](https://forum.syncthing.net/t/stun-syncthing-net-doesnt-resolve-anymore/24075/2?u=marbens)
on the forums, stun.syncthing.net has been shut down, so I think it's
probably a good idea to remove it.

### Testing

1. Have two or more devices
2. Disable Relaying
3. Have no Internet ports open on either end for incoming connections
trigger STUN)
4. Enable the `stun` debugging facility in the Actions -> Logs ->
Debugging Facilities
5. Verify that it doesn't output something like this within a few
seconds:
```
2025-03-30 05:51:32 Enabled debug data for "stun"
2025-03-30 05:51:47 Starting stun for Stun@udp://[::]:22000
2025-03-30 05:51:47 Running stun for Stun@udp://[::]:22000 via stun.syncthing.net:3478
2025-03-30 05:51:47 Stun@udp://[::]:22000 stun addr resolution on stun.syncthing.net:3478: lookup stun.syncthing.net: no such host
```

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-03-30 15:17:55 +02:00
mathias4833
0d6117d585 fix(gui): validate device ID in canonical form (fixes #7291) (#10006)
### Purpose

In the GUI, the device ID validation was case-sensitive and didn’t
account for dash variations, which allowed users to enter an existing
device ID without receiving proper feedback.

This fix ensures the ID is validated in its canonical form, thus
preventing the user from submitting the request if the device ID already
exists.

### Testing

To test this change, try adding a new device with an ID that matches an
existing device, but with a different case or dashes.
2025-03-29 17:52:02 +01:00
Jakob Borg
f1e136a17b build: also run APT publish for v2 tags 2025-03-29 15:29:01 +01:00
Jakob Borg
025905fcdf chore: switch database engine to sqlite (fixes #9954) (#9965)
Switch the database from LevelDB to SQLite, for greater stability and
simpler code.

Co-authored-by: Tommy van der Vorst <tommy@pixelspark.nl>
Co-authored-by: bt90 <btom1990@googlemail.com>
2025-03-29 13:50:08 +01:00
Jakob Borg
b1c8f88a44 chore: remove weak hashing which does not pull its weight (#10005)
We've had weak/rolling hashing in the code for quite a while. It was a
popular request for a while, based on the belief that rsync does this
and we should too. However, the benefit is quite small; we save on
average about 0.8% of transferred blocks over the population as a whole:

<img width="974" alt="Screenshot 2025-03-28 at 17 09 02"
src="https://github.com/user-attachments/assets/bbe10dea-f85e-4043-9823-7cef1220b4a2"
/>

This would be fine if the cost was comparably low, however the downside
of attempting rolling hash matching is that we (by default) do a
complete file read on the destination in order to look for matches
before we starting pulling blocks for the file. For any larger file this
means a sometimes long, I/O-intensive pause before the file starts
syncing, for usually no benefit.

I propose we simply rip off the bandaid and save the effort.
2025-03-29 13:21:10 +01:00
Jakob Borg
1a25ae32ca chore: remove abandoned next-gen-gui experiment (#10004)
It didn't go anywhere, it adds no value where it is.
2025-03-29 13:20:35 +01:00
tomasz1986
629971687d feat(gui): explanation to options enabled or disabled per folder type (#9367)
Currently, some options are automatically enabled or disabled depending
on the folder type. However, there is no explanation in the GUI on why
the options are like that. Thus, add short explanatory notes to each
case, where the option is either disabled or enabled according to the
current folder type.
2025-03-28 15:17:08 +00:00
Tommy van der Vorst
3c955a9706 chore(lib): expose model methods to obtain progress (#9886)
### Purpose

This exposes four methods from `Model` through `Internals`. It allows
apps like Synctrain to obtain information about local/remote need and
sync progress.

### Testing

No testing seems necessary, functions are exported verbatim.

### Screenshots

N/a

### Documentation

Not public API, I am aware this interface may change at any time.

## Authorship

OK.

Co-authored-by: Ross Smith II <ross@smithii.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-03-28 13:44:01 +00:00
Ross Smith II
7f3c8dbff1 build: move nightly build schedule to separate workflow (#10000)
This allows users to easily disable nightly builds in their forks,
simply by disabling the
build-nightly action.

### Testing

I tested it in my fork, and it works.
2025-03-27 09:31:51 +00:00
Jakob Borg
7762e39fb3 chore(syncthing): use file lock on certificate to prevent multiple instances (#10003)
This adds the locking from the SQLite branch, in preparation, so that we
do not inadvertently permit running an instance of each.
2025-03-27 09:26:21 +00:00
Jakob Borg
4235b2c406 chore(ur): add RSS to reported stats (#10002)
For easier comparison in the future.
2025-03-27 10:17:10 +01:00
Syncthing Release Automation
3fd090bfa7 chore(gui, man, authors): update docs, translations, and contributors 2025-03-24 03:49:44 +00:00
Syncthing Release Automation
6dfa54efa6 chore(gui, man, authors): update docs, translations, and contributors 2025-03-17 03:49:35 +00:00
mathias4833
67575e1736 fix(api): prevent tilde expansion in path suggestions (fixes #9990) (#9992)
### Purpose

Path autocompletion wasn't working when using `~` as a shortcut for the
home directory. The issue occurred because the tilde was expanded to
/home/user, which caused the suggestion to no longer match the input
(thus preventing the autocompletion from appearing in the suggestion
list).

To fix this, I replaced the custom `parentAndBase` function, which
handled path splitting in a more complex way, with `filepath.Split` from
the standard `path/filepath` package. This prevents tilde expansion
while keeping the expected behavior for path splitting.

### Testing

The issue has been tested manually on Linux.

### Screenshots


![screenshot](https://github.com/user-attachments/assets/49dd96e2-6d75-4476-946d-0dfb2ac474ef)
2025-03-15 21:06:38 +01:00
Jakob Borg
65923fc255 fix(syncthing): don't auto upgrade to higher major on startup (#9989)
We avoided upgrading to newer major versions during normal auto upgrade
procedures, but currently not in the initial upgrade check on startup.
2025-03-13 07:59:19 +00:00
Jakob Borg
aea763868f build(deps): update dependencies (#9988) 2025-03-13 07:41:05 +00:00
Syncthing Release Automation
26b134ae7b chore(gui, man, authors): update docs, translations, and contributors 2025-03-10 03:45:18 +00:00
Emil Lundberg
893071d2ba refactor(api): extract method configMuxBuilder.postAdjustGui and add test coverage (#9979)
This is extracted from PR #9175. This deduplicates `SetPassword` calls
and makes `postAdjustGui` a single place where PR #9175 can add
another adjustment step for sanitizing changes to WebAuthn
credentials.

This also adds tests to validate that the refactored logic was not
broken.
2025-03-09 21:31:06 +01:00
Emil Lundberg
435f2d2178 refactor(api): make shutdown timeout configurable for tests (#9980)
This is extracted from PR #9175, which adds some tests that seem to
need a longer shutdown timeout when running on GitHub Actions.
2025-03-07 12:50:33 +01:00
Emil Lundberg
8461ca539b refactor(api): deduplicate HTTP test helpers and allow session cookie access (#9977)
These refactorizations were made in [PR #9175][1] to accommodate a few
new variants of authentication method and body content. On request from
reviewers, this PR extracts it as a smaller refactorization to review in
isolation.

### Purpose

This extracts a shared `httpRequest` base function from `httpGet` and
`httpPost`, which will be used in PR #9175 for new helper functions
`httpGetCsrf` (hiding all optional parameters except the CSRF token),
`httpPostCsrf` (same) and `httpPostCsrfAuth` (hiding basic auth
parameters). A `getSessionCookie` function is also extracted from
`hasSessionCookie` and will be used to test that concurrent WebAuthn
authentications result in separate sessions (indicated by different
session cookies).
2025-03-07 11:07:01 +01:00
Jakob Borg
fb977dc61d build: correct API call for Weblate statistics
Something changed...
2025-03-03 08:11:29 +01:00
Jakob Borg
ee7ab4ce25 build(deps): update dependencies (#9978) 2025-03-01 21:33:13 +00:00
polyfloyd
c3ce9713d9 chore(etc): remove /usr/bin prefix from Linux .desktop files (#9966)
Exec accepts just the program name and will look for it in $PATH. This
makes these files work on NixOS which does not create a /usr/bin
directory.
2025-02-28 20:59:07 +01:00
Jakob Borg
6a147091c5 build: use Go 1.24, minimum is Go 1.23 (#9960) 2025-02-12 10:16:46 +01:00
Jakob Borg
6208c36417 fix(policy): do not require multiple maintainers for build changes 2025-02-12 09:47:09 +01:00
Syncthing Release Automation
453fd20eeb chore(gui, man, authors): update docs, translations, and contributors 2025-02-10 03:46:14 +00:00
Tommy van der Vorst
28f0cffdb6 chore(fs): build kqueue instead of fsevents watcher on iOS (#9950)
### Purpose

On iOS, the FSEvents API for watching files (also used on macOS) is not
available, but `kqueue` is. This PR ensures `kqueue` support is built on
iOS instead of the FSEvents based watcher implementation.

Before this PR, you could already use the `kqueue` build option to force
its usage. Unfortunately `gomobile`, the tool that I use to build
Syncthing for iOS and macOS for Synctrain, does not support setting
different build flags for iOS and macOS (unless I build separately for
each, which is a bit of a hassle because XCode nonsense). I am assuming
there are good reasons to support FSEvents even though `kqueue` is also
available on macOS (but I'm not sure why?). I do know FSEvents has been
working fine for me on macOS so it seems best to use FSEvents on macOS
and kqueue on iOS.

Note that this also requires https://github.com/syncthing/notify/pull/4
to be merged in `synchting/notify` (until that is done, this PR will
fail to build on iOS due to `notify` still trying to link to `fsevents`
stuff when the `kqueue` build flag is not set).

### Testing

I compiled both `syncthing/notify` and syncthing with this PR applied,
and used that to successfully build the Synctrain iOS app, which after
this PR works fine and should follow up file changes a bit quicker.

### Screenshots

n/a

### Documentation

n/a

## Authorship

Your name and email will be added automatically to the AUTHORS file
based on the commit metadata.

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-02-07 15:40:53 +00:00
Jakob Borg
87c16c6cf5 build(deps): update dependencies (#9951) 2025-02-07 08:44:26 +00:00
dashangcun
5495c98e63 refactor: using slices.Contains to simplify the code (#9918)
### Purpose

This is a [new function](https://pkg.go.dev/slices@go1.21.0#Contains)
added in the go1.21 standard library, which can make the code more
concise and easy to read.

### Testing

Describe what testing has been done, and how the reviewer can test the
change
if new tests are not included.

### Screenshots

If this is a GUI change, include screenshots of the change. If not,
please
feel free to just delete this section.

### Documentation

If this is a user visible change (including API and protocol changes),
add a link here
to the corresponding pull request on https://github.com/syncthing/docs
or describe
the documentation changes necessary.

## Authorship

Your name and email will be added automatically to the AUTHORS file
based on the commit metadata.

Signed-off-by: dashangcun <907225865@qq.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2025-02-07 08:21:24 +00:00
Jakob Borg
da7d5ce608 build: switch to cloud code signing for Windows (#9948)
The requirements for Windows code signing changed in 2023, so that newly
generated certificates can only be stored in hardware modules. Luckily,
I managed to snag a three year certificate before that so it hasn't
affected us so much. Now though, it does, because our cert is expiring
in March.

This changes the code signing process for Windows to use a cloud
service, Azure Trusted Signing. This appears to work equally well and
outsources the problem entirely, while also being cheaper than the
actual certificate was to begin with. 🤷

The signing entity will be Kastelo AB and not the Syncthing Foundation,
because the latter is almost impossible to get a certificate for as it's
not a normal corporate entity whose existence can be verified, etc. This
is also how it was prior to the latest certificate; it's not ideal, but
I think it's acceptable under the circumstances.
2025-02-06 10:43:23 +01:00
Syncthing Release Automation
b300c297c6 chore(gui, man, authors): update docs, translations, and contributors 2025-02-03 03:45:29 +00:00
Syncthing Release Automation
124673f7a8 chore(gui, man, authors): update docs, translations, and contributors 2025-01-27 03:45:14 +00:00
Jakob Borg
0395cf2bc0 fix(model): clarify errors on Windows user/group lookup (fixes #9929) (#9930)
Currently, this just results in a very ambiguous `setting metadata: lookup
failed` while it could report what it's looking up and why it failed
(not found, etc).
2025-01-20 09:59:05 +01:00
Syncthing Release Automation
36cd70040a chore(gui, man, authors): update docs, translations, and contributors 2025-01-20 03:45:10 +00:00
Jakob Borg
1fbd396ffa chore(scanner): don't warn about cancelled scan (#9920)
We expect a context cancellation when a folder is restarted during a
scan.
2025-01-13 17:35:55 +00:00
Syncthing Release Automation
2834bad85e chore(gui, man, authors): update docs, translations, and contributors 2025-01-13 03:47:27 +00:00
583 changed files with 19697 additions and 63207 deletions

View File

@@ -1,6 +1,7 @@
name: Feature request
description: File a new feature request
labels: ["enhancement", "needs-triage"]
type: Feature
body:
- type: textarea

View File

@@ -1,6 +1,7 @@
name: Bug report
description: If you're actually looking for support instead, see "I need help / I have a question".
labels: ["bug", "needs-triage"]
type: Bug
body:
- type: markdown
attributes:

23
.github/labeler.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
version: 1
labels:
- label: enhancement
title: ^feat\b
- label: bug
title: ^fix\b
- label: documentation
title: ^docs\b
- label: chore
title: ^chore\b
- label: chore
title: ^refactor\b
- label: build
title: ^build\b
- label: dependencies
title: ^build\(deps\)\b

52
.github/regsync.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
version: 1
creds:
- registry: docker.io
user: "{{env \"DOCKERHUB_USERNAME\"}}"
pass: "{{env \"DOCKERHUB_TOKEN\"}}"
defaults:
ratelimit:
min: 100
retry: 1m
parallel: 4
sync:
- source: ghcr.io/syncthing/syncthing
target: docker.io/syncthing/syncthing
type: repository
tags:
allow:
- latest
- rc
- edge
- \d+
- \d+\.\d+
- \d+\.\d+\.\d+
- \d+\.\d+\.\d+-rc\.\d+
- source: ghcr.io/syncthing/relaysrv
target: docker.io/syncthing/relaysrv
type: repository
tags:
allow:
- latest
- rc
- edge
- \d+
- \d+\.\d+
- \d+\.\d+\.\d+
- \d+\.\d+\.\d+-rc\.\d+
- source: ghcr.io/syncthing/discosrv
target: docker.io/syncthing/discosrv
type: repository
tags:
allow:
- latest
- rc
- edge
- \d+
- \d+\.\d+
- \d+\.\d+\.\d+
- \d+\.\d+\.\d+-rc\.\d+

17
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
changelog:
exclude:
labels:
- dependencies
categories:
- title: Fixes
labels:
- bug
- title: Features
labels:
- enhancement
- title: Other
labels:
- '*'

View File

@@ -7,7 +7,7 @@ on:
- infra-*
env:
GO_VERSION: "~1.23.0"
GO_VERSION: "~1.24.0"
CGO_ENABLED: "0"
BUILD_USER: docker
BUILD_HOST: github.syncthing.net
@@ -21,7 +21,7 @@ jobs:
name: Build and push Docker images
if: github.repository == 'syncthing/syncthing'
runs-on: ubuntu-latest
environment: release
environment: docker
strategy:
matrix:
pkg:

18
.github/workflows/build-nightly.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Build Syncthing (Nightly)
on:
schedule:
# Run nightly build at 05:00 UTC
- cron: '00 05 * * *'
workflow_dispatch:
permissions:
contents: write
packages: write
jobs:
build-syncthing:
uses: ./.github/workflows/build-syncthing.yaml
# if we only want nightlies to run for specific users:
# if: contains(fromJSON('["syncthing", "calmh"]'), github.repository_owner)
secrets: inherit

View File

File diff suppressed because it is too large Load Diff

18
.github/workflows/mirrors.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Mirrors
on: [push, delete]
jobs:
codeberg:
name: Mirror to Codeberg
if: github.repository_owner == 'syncthing'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: yesolutions/mirror-action@master
with:
REMOTE: ssh://git@codeberg.org/${{ github.repository }}.git
GIT_SSH_PRIVATE_KEY: ${{ secrets.CODEBERG_PUSH_KEY }}
GIT_SSH_NO_VERIFY_HOST: "true"

27
.github/workflows/pr-metadata.yaml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: PR metadata
on:
pull_request_target:
types:
- opened
- reopened
- edited
- synchronize
permissions:
contents: read
pull-requests: write
jobs:
#
# Set labels on PRs, which are then used to categorise release notes
#
labels:
name: Set labels
runs-on: ubuntu-latest
steps:
- uses: srvaroa/labeler@v1
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -0,0 +1,60 @@
name: Release Syncthing
on:
push:
branches:
- release
- release-rc*
permissions:
contents: write
jobs:
create-release-tag:
name: Create release tag
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- uses: actions/setup-go@v5
with:
go-version: stable
- name: Determine version to release
run: |
if [[ "$GITHUB_REF_NAME" == "release" ]] ; then
next=$(go run ./script/next-version.go)
else
next=$(go run ./script/next-version.go --pre)
fi
echo "NEXT=$next" >> $GITHUB_ENV
echo "Next version is $next"
prev=$(git describe --exclude "*-*" --abbrev=0)
echo "PREV=$prev" >> $GITHUB_ENV
echo "Previous version is $prev"
- name: Determine release notes
run: |
go run ./script/relnotes.go --new-ver "$NEXT" --branch "$GITHUB_REF_NAME" --prev-ver "$PREV" > notes.md
env:
GITHUB_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- name: Create and push tag
run: |
git config --global user.name 'Syncthing Release Automation'
git config --global user.email 'release@syncthing.net'
git tag -a -F notes.md --cleanup=whitespace "$NEXT"
git push origin "$NEXT"
- name: Trigger the build
uses: benc-uk/workflow-dispatch@v1
with:
workflow: build-syncthing.yaml
ref: refs/tags/${{ env.NEXT }}
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}

1
.gitignore vendored
View File

@@ -17,5 +17,4 @@ deb
*.bz2
/repos
/proto/scripts/protoc-gen-gosyncthing
/gui/next-gen-gui
/compat.json

View File

@@ -1,39 +1,84 @@
version: "2"
linters:
enable-all: true
default: all
disable:
- cyclop
- depguard
- err113
- exhaustive
- exhaustruct
- forbidigo
- funcorder
- funlen
- gci
- gochecknoglobals
- gochecknoinits
- gocognit
- goconst
- gocyclo
- godot
- godox
- gofmt
- goimports
- gomoddirectives
- inamedparam
- interfacebloat
- ireturn
- lll
- maintidx
- mnd
- musttag
- nestif
- nlreturn
- noinlineerr
- nonamedreturns
- paralleltest
- prealloc
- predeclared
- protogetter
- scopelint
- recvcheck
- revive
- tagalign
- tagliatelle
- testpackage
- usetesting # go 1.24
- varnamelen
- whitespace
- wrapcheck
- wsl
issues:
exclude-dirs:
- internal/gen
- cmd/dev
- repos
- wsl_v5
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- internal/gen
- internal/db/olddb
- cmd/dev
- repos
- third_party$
- builtin$
- examples$
- _test\.go$
rules:
# relax the slog rules for debug lines, for now
- linters: [sloglint]
source: Debug
settings:
sloglint:
context: "scope"
static-msg: true
msg-style: capitalized
key-naming-case: camel
formatters:
enable:
- gofumpt
exclusions:
generated: lax
paths:
- internal/gen
- cmd/dev
- repos
- third_party$
- builtin$
- examples$

View File

@@ -42,7 +42,6 @@ approval_rules:
paths:
- ^[^/]+\.md
- ^\.policy\.yml
- ^\.github/
- ^LICENSE
requires:
count: 1

116
AUTHORS
View File

@@ -13,118 +13,113 @@
# contents of this file.
#
Aaron Bieber (qbit) <qbit@deftly.net>
Jakob Borg (calmh) <jakob@nym.se> <jakob@kastelo.net> <jborg@coreweave.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com> <github@audrius.rocks>
Simon Frei (imsodin) <freisim93@gmail.com>
Tomasz Wilczyński <5626656+tomasz1986@users.noreply.github.com> <twilczynski@naver.com>
Alexander Graf (alex2108) <register-github@alex-graf.de>
Alexandre Viau (aviau) <alexandre@alexandreviau.net> <aviau@debian.org>
Anderson Mesquita (andersonvom) <andersonvom@gmail.com>
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
Antony Male (canton7) <antony.male@gmail.com>
Ben Schulz (uok) <ueomkail@gmail.com> <uok@users.noreply.github.com>
bt90 <btom1990@googlemail.com>
Caleb Callaway (cqcallaw) <enlightened.despot@gmail.com>
Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@users.noreply.github.com>
Emil Lundberg <emil@emlun.se>
Eric P <eric@kastelo.net>
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>
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>
Wulf Weich (wweich) <wweich@users.noreply.github.com> <wweich@gmx.de> <wulf@weich-kr.de>
Adam Piggott (ProactiveServices) <aD@simplypeachy.co.uk> <simplypeachy@users.noreply.github.com> <ProactiveServices@users.noreply.github.com> <adam@proactiveservices.co.uk>
Adel Qalieh (adelq) <aqalieh95@gmail.com> <adelq@users.noreply.github.com>
Alan Pope <alan@popey.com>
Alberto Donato <albertodonato@users.noreply.github.com>
Aleksey Vasenev <margtu-fivt@ya.ru>
Alessandro G. (alessandro.g89) <alessandro.g89@gmail.com>
Alex Ionescu <github@ionescu.sh>
Alex Lindeman <139387+aelindeman@users.noreply.github.com>
Alex Xu <alex.hello71@gmail.com>
Alexander Graf (alex2108) <register-github@alex-graf.de>
Alexander Seiler <seileralex@gmail.com>
Alexandre Alves <alexandrealvesdb.contact@gmail.com>
Alexandre Viau (aviau) <alexandre@alexandreviau.net> <aviau@debian.org>
Aman Gupta <aman@tmm1.net>
Anatoli Babenia <anatoli@rainforce.org>
Anderson Mesquita (andersonvom) <andersonvom@gmail.com>
Andreas Sommer <andreas.sommer87@googlemail.com>
andresvia <andres.via@gmail.com>
Andrew Dunham (andrew-d) <andrew@du.nham.ca>
Andrew Meyer <andrewm.bpi@gmail.com>
Andrew Rabert (nvllsvm) <ar@nullsum.net> <6550543+nvllsvm@users.noreply.github.com>
Andrey D (scienmind) <scintertech@cryptolab.net> <scienmind@users.noreply.github.com>
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
andyleap <andyleap@gmail.com>
Anjan Momi <anjan@momi.ca>
Anthony Goeckner <agoeckner@users.noreply.github.com>
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
Antony Male (canton7) <antony.male@gmail.com>
Anur <anurnomeru@163.com>
Aranjedeath <Aranjedeath@users.noreply.github.com>
ardevd <ardevd@users.noreply.github.com>
Arkadiusz Tymiński <gevleeog@gmail.com>
Aroun <login@b-vo.fr>
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
Artur Zubilewicz <AkaZecik@users.noreply.github.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com> <github@audrius.rocks>
Ashish Bhate <bhate.ashish@gmail.com>
Aurélien Rainone <476650+arl@users.noreply.github.com>
BAHADIR YILMAZ <bahadiryilmaz32@gmail.com>
Bart De Vries (mogwa1) <devriesb@gmail.com>
Beat Reichenbach <44111292+beatreichenbach@users.noreply.github.com>
Ben Curthoys (bencurthoys) <ben@bencurthoys.com>
Ben Schulz (uok) <ueomkail@gmail.com> <uok@users.noreply.github.com>
Ben Shepherd (benshep) <bjashepherd@gmail.com>
Ben Sidhom (bsidhom) <bsidhom@gmail.com>
Benedikt Heine (bebehei) <bebe@bebehei.de>
Benedikt Morbach <benedikt.morbach@googlemail.com>
Benjamin Nater <17193640+bn4t@users.noreply.github.com>
Benno Fünfstück <benno.fuenfstueck@gmail.com>
Benny Ng (tpng) <benny.tpng@gmail.com>
boomsquared <54829195+boomsquared@users.noreply.github.com>
Boqin Qin <bobbqqin@bupt.edu.cn>
Boris Rybalkin <ribalkin@gmail.com>
Brandon Philips (philips) <brandon@ifup.org>
Brendan Long (brendanlong) <self@brendanlong.com>
Brian R. Becker (brbecker) <brbecker@gmail.com>
bt90 <btom1990@googlemail.com>
Caleb Callaway (cqcallaw) <enlightened.despot@gmail.com>
Carsten Hagemann (carstenhag) <moter8@gmail.com> <carsten@chagemann.de>
Catfriend1 <16361913+Catfriend1@users.noreply.github.com>
Cathryne Linenweaver (Cathryne) <cathryne.linenweaver@gmail.com> <Cathryne@users.noreply.github.com> <katrinleinweber@MAC.local>
Cedric Staniewski (xduugu) <cedric@gmx.ca>
chenrui <rui@meetup.com>
Chih-Hsuan Yen <yan12125@gmail.com> <1937689+yan12125@users.noreply.github.com>
Choongkyu <choongkyu.kim+gh@gmail.com> <vapidlyrapid+gh@gmail.com>
Chris Howie (cdhowie) <me@chrishowie.com>
Chris Joel (cdata) <chris@scriptolo.gy>
Chris Tonkinson <chris@masterbran.ch>
Christian Kujau <ckujau@users.noreply.github.com>
Christian Prescott <me@christianprescott.com>
chucic <chucic@seznam.cz>
cjc7373 <niuchangcun@gmail.com>
Colin Kennedy (moshen) <moshen.colin@gmail.com>
Cromefire_ <tim.l@nghorst.net> <26320625+cromefire@users.noreply.github.com>
cui fliter <imcusg@gmail.com>
Cyprien Devillez <cypx@users.noreply.github.com>
d-volution <49024624+d-volution@users.noreply.github.com>
Dale Visser <dale.visser@live.com>
Dan <benda.daniel@gmail.com>
Daniel Barczyk <46358936+DanielBarczyk@users.noreply.github.com>
Daniel Bergmann (brgmnn) <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@users.noreply.github.com>
Daniel Martí (mvdan) <mvdan@mvdan.cc>
Daniel Padrta <64928366+danpadcz@users.noreply.github.com>
Daniil Gentili <daniil@daniil.it>
Darshil Chanpura (dtchanpura) <dtchanpura@gmail.com> <dcprime314@gmail.com>
dashangcun <907225865@qq.com>
David Rimmer (dinosore) <dinosore@dbrsoftware.co.uk>
deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
DeflateAwning <11021263+DeflateAwning@users.noreply.github.com>
Denis A. (dva) <denisva@gmail.com>
Dennis Wilson (snnd) <dw@risu.io>
dependabot-preview[bot] <dependabot-preview[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <49699333+dependabot[bot]@users.noreply.github.com>
derekriemer <derek.riemer@colorado.edu>
DerRockWolf <50499906+DerRockWolf@users.noreply.github.com>
desbma <desbma@users.noreply.github.com>
Devon G. Redekopp <devon@redekopp.com>
diemade <spamkill@posteo.ch>
digital <didev@dinid.net>
Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com>
Dmitry Saveliev (dsaveliev) <d.e.saveliev@gmail.com>
domain <32405309+szu17dmy@users.noreply.github.com>
Domenic Horner <domenic@tgxn.net>
Dominik Heidler (asdil12) <dominik@heidler.eu>
Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
Elliot Huffman <thelich2@gmail.com>
Emil Hessman (ceh) <emil@hessman.se>
Emil Lundberg <emil@emlun.se>
Eng Zer Jun <engzerjun@gmail.com>
entity0xfe <109791748+entity0xfe@users.noreply.github.com> <entity0xfe@my.domain>
Eric Lesiuta <elesiuta@gmail.com>
Eric P <eric@kastelo.net>
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
Evan Spensley <94762716+0evan@users.noreply.github.com>
Evgeny Kuznetsov <evgeny@kuznetsov.md>
Federico Castagnini (facastagnini) <federico.castagnini@gmail.com>
Felix <53702818+f-eliks@users.noreply.github.com>
Felix Ableitner (Nutomic) <me@nutomic.com>
@@ -138,7 +133,6 @@ ghjklw <malo@jaffre.info>
Gilli Sigurdsson (gillisig) <gilli@vx.is>
Gleb Sinyavskiy <zhulik.gleb@gmail.com>
Graham Miln (grahammiln) <graham.miln@dssw.co.uk> <graham.miln@miln.eu>
greatroar <61184462+greatroar@users.noreply.github.com>
Greg <gco@jazzhaiku.com>
guangwu <guoguangwu@magic-shield.com>
gudvinr <gudvinr@gmail.com>
@@ -146,56 +140,42 @@ Gusted <postmaster@gusted.xyz> <williamzijl7@hotmail.com>
Han Boetes <han@boetes.org>
HansK-p <42314815+HansK-p@users.noreply.github.com>
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
Hazem Krimi <me@hazemkrimi.tech>
Heiko Zuerker (Smiley73) <heiko@zuerker.org>
Hireworks <129852174+hireworksltd@users.noreply.github.com>
Hugo Locurcio <hugo.locurcio@hugo.pro>
Iain Barnett <iainspeed@gmail.com>
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
ignacy123 <ignacy.buczek@onet.pl>
Ikko Ashimine <eltociear@gmail.com>
Ilya Brin <464157+ilyabrin@users.noreply.github.com>
Iskander Sharipov (Alex) <quasilyte@gmail.com>
Jaakko Hannikainen (jgke) <jgke@jgke.fi>
Jacek Szafarkiewicz (hadogenes) <szafar@linux.pl>
Jack Croft <jccroft1@users.noreply.github.com>
Jacob <jyundt@gmail.com>
Jake Peterson (acogdev) <jake@acogdev.com>
Jakob Borg (calmh) <jakob@nym.se> <jakob@kastelo.net> <jborg@coreweave.com>
James O'Beirne <wild-github@au92.org>
James Patterson (jpjp) <jamespatterson@operamail.com> <jpjp@users.noreply.github.com>
janost <janost@tuta.io>
Jaroslav Lichtblau <svetlemodry@users.noreply.github.com>
Jaroslav Malec (dzarda) <dzardacz@gmail.com>
jaseg <githubaccount@jaseg.net>
Jaspitta <ste.scarpitta@gmail.com>
Jauder Ho <jauderho@users.noreply.github.com>
Jaya Chithra (jayachithra) <s.k.jayachithra@gmail.com>
Jaya Kumar <jaya.kumar@ict.nl>
Jeffery To <jeffery.to@gmail.com>
jelle van der Waa <jelle@vdwaa.nl>
Jens Diemer (jedie) <github.com@jensdiemer.de> <git@jensdiemer.de>
Jerry Jacobs (xor-gate) <jerry.jacobs@xor-gate.org> <xor-gate@users.noreply.github.com>
Jesse Lucas <jesse@jesselucas.com>
Jochen Voss (seehuhn) <voss@seehuhn.de>
Johan Andersson <j@i19.se>
Johan Vromans (sciurius) <jvromans@squirrel.nl>
John Rinehart (fuzzybear3965) <johnrichardrinehart@gmail.com>
Jonas Thelemann <e-mail@jonas-thelemann.de>
Jonathan <artback@protonmail.com> <jonagn@gmail.com>
Jonathan Cross <jcross@gmail.com>
Jonta <359397+Jonta@users.noreply.github.com>
Jose Manuel Delicado (jmdaweb) <jmdaweb@hotmail.com> <jmdaweb@users.noreply.github.com>
jtagcat <git-514635f7@jtag.cat> <git-12dbd862@jtag.cat>
Julian Lehrhuber <jul13579@users.noreply.github.com>
Jörg Thalheim <Mic92@users.noreply.github.com>
Jędrzej Kula <kula.jedrek@gmail.com>
K.B.Dharun Krishna <kbdharunkrishna@gmail.com>
Kalle Laine <pahakalle@protonmail.com>
Kapil Sareen <kapilsareen584@gmail.com>
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
Kebin Liu <lkebin@gmail.com>
Keith Harrison <keithh@protonmail.com>
Keith Turner <kturner@apache.org>
Kelong Cong (kc1212) <kc04bc@gmx.com> <kc1212@users.noreply.github.com>
Ken'ichi Kamada (kamadak) <kamada@nanohz.org>
Kevin Allen (ironmig) <kma1660@gmail.com>
@@ -204,31 +184,27 @@ Kevin White, Jr. (kwhite17) <kevinwhite1710@gmail.com>
klemens <ka7@github.com>
Kurt Fitzner (Kudalufi) <kurt@va1der.ca> <kurt.fitzner@gmail.com>
kylosus <33132401+kylosus@users.noreply.github.com>
Lars K.W. Gohlke (lkwg82) <lkwg82@gmx.de>
Lars Lehtonen <lars.lehtonen@gmail.com>
Laurent Arnoud <laurent@spkdev.net>
Laurent Etiemble (letiemble) <laurent.etiemble@gmail.com> <laurent.etiemble@monobjc.net>
Leo Arias (elopio) <yo@elopio.net>
Liu Siyuan (liusy182) <liusy182@gmail.com> <liusy182@hotmail.com>
Lode Hoste (Zillode) <zillode@zillode.be>
Lord Landon Agahnim (LordLandon) <lordlandon@gmail.com>
LSmithx2 <42276854+lsmithx2@users.noreply.github.com>
luchenhan <168071714+luchenhan@users.noreply.github.com>
Lukas Lihotzki <lukas@lihotzki.de>
Luke Hamburg <1992842+luckman212@users.noreply.github.com>
luzpaz <luzpaz@users.noreply.github.com>
Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
Marc Pujol (kilburn) <kilburn@la3.org>
Marcel Meyer <mm.marcelmeyer@gmail.com>
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
marco-m <marco.molteni@laposte.net>
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>
Martchus <martchus@gmx.net>
Martin Polehla <p0l0us@users.noreply.github.com>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Mateusz Ż <thedead4fun@live.com>
mathias4833 <67101597+mathias4833@users.noreply.github.com>
Matic Potočnik <hairyfotr@gmail.com>
Matt Burke (burkemw3) <mburke@amplify.com> <burkemw3@gmail.com>
Matt Robenolt <matt@ydekproductions.com>
@@ -236,15 +212,10 @@ Matteo Ruina <matteo.ruina@gmail.com>
Maurizio Tomasi <ziotom78@gmail.com>
Max <github@germancoding.com>
Max Schulze (kralo) <max.schulze@online.de> <kralo@users.noreply.github.com>
maxice8 <30738253+maxice8@users.noreply.github.com>
MaximAL <almaximal@ya.ru>
Maxime Thirouin <m@moox.io>
Maximilian <maxi.rostock@outlook.de> <public@complexvector.space>
mclang <1721600+mclang@users.noreply.github.com>
Michael Jephcote (Rewt0r) <rewt0r@gmx.com> <Rewt0r@users.noreply.github.com>
Michael Ploujnikov (plouj) <ploujj@gmail.com>
Michael Rienstra <mrienstra@gmail.com>
Michael Tilli (pyfisch) <pyfisch@gmail.com>
MichaIng <micha@dietpi.com>
Migelo <miha@filetki.si>
Mike Boone <mike@boonedocks.net>
@@ -253,7 +224,6 @@ MikolajTwarog <43782609+MikolajTwarog@users.noreply.github.com>
Mingxuan Lin <gdlmx@users.noreply.github.com>
mv1005 <49659413+mv1005@users.noreply.github.com>
Nate Morrison (nrm21) <natemorrison@gmail.com>
Naveen <172697+naveensrinivasan@users.noreply.github.com>
nf <nf@wh3rd.net>
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
Nick Busey <NickBusey@users.noreply.github.com>
@@ -268,14 +238,13 @@ NoLooseEnds <jon.koslung@gmail.com>
Oliver Freyermuth <o.freyermuth@googlemail.com>
orangekame3 <miya.org.0309@gmail.com>
otbutz <tbutz@optitool.de>
Otiel <Otiel@users.noreply.github.com>
overkill <22098433+0verk1ll@users.noreply.github.com>
Oyebanji Jacob Mayowa <oyebanji05@gmail.com>
Pablo <pbaeyens31+github@gmail.com>
Pascal Jungblut (pascalj) <github@pascalj.com> <mail@pascal-jungblut.com>
Paul Brit <paulbrit44@gmail.com>
Paul Donald <newtwen+github@gmail.com>
Pawel Palenica (qepasa) <pawelpalenica11@gmail.com>
Paweł Rozlach <vespian@users.noreply.github.com>
perewa <cavalcante.ten@gmail.com>
Peter Badida <KeyWeeUsr@users.noreply.github.com>
Peter Dave Hello <hsu@peterdavehello.org>
@@ -285,18 +254,16 @@ Phani Rithvij <phanirithvij2000@gmail.com>
Phil Davis <phil.davis@inf.org>
Philippe Schommers (filoozoom) <philippe@schommers.be>
Phill Luby (pluby) <phill.luby@newredo.com>
Pier Paolo Ramon <ramonpierre@gmail.com>
Piotr Bejda (piobpl) <piotrb10@gmail.com>
Pramodh KP (pramodhkp) <pramodh.p@directi.com> <1507241+pramodhkp@users.noreply.github.com>
polyfloyd <polyfloyd@users.noreply.github.com>
pullmerge <166967364+pullmerge@users.noreply.github.com>
Quentin Hibon <qh.public@yahoo.com>
Rahmi Pruitt <rjpruitt16@gmail.com>
red_led <red-led@users.noreply.github.com>
Richard Hartmann <RichiH@users.noreply.github.com>
Robert Carosi (nov1n) <robert@carosi.nl>
Roberto Santalla <roobre@users.noreply.github.com>
Robin Schoonover <robin@cornhooves.org>
Roman Zaynetdinov (zaynetro) <romanznet@gmail.com>
Ross Smith II (rasa) <ross@smithii.com>
rubenbe <github-com-00ff86@vandamme.email>
Ruslan Yevdokymov <38809160+ruslanye@users.noreply.github.com>
Ryan Qian <i@bitbili.net>
@@ -308,32 +275,27 @@ Sergey Mishin (ralder) <ralder@yandex.ru>
Sertonix <83883937+Sertonix@users.noreply.github.com>
Severin von Wnuck-Lipinski <ss7@live.de>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com> <shdalv@microsoft.com>
Simon Frei (imsodin) <freisim93@gmail.com>
Simon Mwepu <simonmwepu@gmail.com>
Simon Pickup <simon@pickupinfinity.com>
Sly_tom_cat <slytomcat@mail.ru>
Sonu Kumar Saw <31889738+dev-saw99@users.noreply.github.com>
Stefan Kuntz (Stefan-Code) <stefan.github@gmail.com> <Stefan.github@gmail.com>
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
Suhas Gundimeda (snugghash) <suhas.gundimeda@gmail.com> <snugghash@gmail.com>
Sven Bachmann <dev@mcbachmann.de>
Syncthing Automation <automation@syncthing.net>
Syncthing Release Automation <release@syncthing.net>
Sébastien WENSKE <sebastien@wenske.fr>
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
Terrance <git@terrance.allofti.me>
TheCreeper <TheCreeper@users.noreply.github.com>
Thomas <9749173+uhthomas@users.noreply.github.com>
Thomas Hipp <thomashipp@gmail.com>
Tim Abell (timabell) <tim@timwise.co.uk>
Tim Howes (timhowes) <timhowes@berkeley.edu>
Tim Nordenfur <tim@gurka.se>
Tobias Frölich <40638719+tobifroe@users.noreply.github.com>
Tobias Klauser <tobias.klauser@gmail.com>
Tobias Nygren (tnn2) <tnn@nygren.pp.se>
Tobias Tom (tobiastom) <t.tom@succont.de>
Tom Jakubowski <tom@crystae.net>
Tomasz Wilczyński <5626656+tomasz1986@users.noreply.github.com> <twilczynski@naver.com>
Tommy Thorn <tommy-github-email@thorn.ws>
Tommy van der Vorst <tommy-github@pixelspark.nl> <tommy@pixelspark.nl>
Tully Robinson (tojrobinson) <tully@tojr.org>
Tyler Brazier (tylerbrazier) <tyler@tylerbrazier.com>
@@ -351,10 +313,10 @@ WangXi <xib1102@icloud.com>
Will Rouesnel <wrouesnel@wrouesnel.com>
William A. Kennington III (wkennington) <william@wkennington.com>
wouter bolsterlee <wouter@bolsterl.ee>
Wulf Weich (wweich) <wweich@users.noreply.github.com> <wweich@gmx.de> <wulf@weich-kr.de>
xarx00 <xarx00@users.noreply.github.com>
Xavier O. (damajor) <damajor@gmail.com>
xjtdy888 (xjtdy888) <xjtdy888@163.com>
xjtdy888 (xjtdy888) <xjtdy888@163.com> <xjtdy888@gmail.com>
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>
yparitcher <y@paritcher.com>
佛跳墙 <daoquan@qq.com>
落心 <luoxin.ttt@gmail.com>

192
build.go
View File

@@ -15,7 +15,6 @@ import (
"bytes"
"compress/flate"
"compress/gzip"
"encoding/base64"
"encoding/json"
"errors"
"flag"
@@ -39,27 +38,26 @@ import (
)
var (
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
run string
benchRun string
buildOut string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
withNextGenGUI = os.Getenv("BUILD_NEXT_GEN_GUI") != ""
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
run string
benchRun string
buildOut string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
)
type target struct {
@@ -290,10 +288,10 @@ func runCommand(cmd string, target target) {
build(target, tags)
case "test":
test(strings.Fields(extraTags), "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
test(strings.Fields(extraTags), "github.com/syncthing/syncthing/internal/...", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
case "bench":
bench(strings.Fields(extraTags), "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
bench(strings.Fields(extraTags), "github.com/syncthing/syncthing/internal/...", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/...")
case "integration":
integration(false)
@@ -331,7 +329,7 @@ func runCommand(cmd string, target target) {
writeCompatJSON()
case "deb":
buildDeb(target)
buildDeb(target, tags)
case "vet":
metalintShort()
@@ -381,7 +379,6 @@ func parseFlags() {
flag.IntVar(&numVersions, "num-versions", numVersions, "Number of versions for changelog command")
flag.StringVar(&run, "run", "", "Specify which tests to run")
flag.StringVar(&benchRun, "bench", "", "Specify which benchmarks to run")
flag.BoolVar(&withNextGenGUI, "with-next-gen-gui", withNextGenGUI, "Also build 'newgui'")
flag.StringVar(&buildOut, "build-out", "", "Set the '-o' value for 'go build'")
flag.Parse()
}
@@ -454,10 +451,6 @@ func benchArgs() []string {
}
func install(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
@@ -481,16 +474,12 @@ func install(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
args := []string{"install", "-v"}
args := []string{"install"}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
func build(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
@@ -513,7 +502,7 @@ func build(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
args := []string{"build", "-v"}
args := []string{"build"}
if buildOut != "" {
args = append(args, "-o", buildOut)
}
@@ -525,13 +514,6 @@ func setBuildEnvVars() {
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
if os.Getenv("CGO_ENABLED") == "" {
switch goos {
case "darwin", "solaris":
default:
os.Setenv("CGO_ENABLED", "0")
}
}
}
func appendParameters(args []string, tags []string, pkgs ...string) []string {
@@ -610,7 +592,7 @@ func buildZip(target target, tags []string) {
fmt.Println(filename)
}
func buildDeb(target target) {
func buildDeb(target target, tags []string) {
os.RemoveAll("deb")
// "goarch" here is set to whatever the Debian packages expect. We correct
@@ -624,7 +606,7 @@ func buildDeb(target target) {
goarch = "arm"
}
build(target, []string{"noupgrade"})
build(target, append(tags, "noupgrade"))
for i := range target.installationFiles {
target.installationFiles[i].src = strings.Replace(target.installationFiles[i].src, "{{binary}}", target.BinaryName(), 1)
@@ -646,6 +628,9 @@ func buildDeb(target target) {
// than just 0.14.26. This rectifies that.
debver = strings.Replace(debver, "-", "~", -1)
}
if strings.Contains(debver, "_") {
debver = strings.Replace(debver, "_", "~", -1)
}
args := []string{
"-t", "deb",
"-s", "dir",
@@ -747,12 +732,9 @@ func shouldBuildSyso(dir string) (string, error) {
sysoPath := filepath.Join(dir, "cmd", "syncthing", "resource.syso")
// See https://github.com/josephspurrier/goversioninfo#command-line-flags
armOption := ""
if strings.Contains(goarch, "arm") {
armOption = "-arm=true"
}
if _, err := runError("goversioninfo", "-o", sysoPath, armOption); err != nil {
arm := strings.HasPrefix(goarch, "arm")
a64 := strings.Contains(goarch, "64")
if _, err := runError("goversioninfo", "-o", sysoPath, fmt.Sprintf("-arm=%v", arm), fmt.Sprintf("-64=%v", a64)); err != nil {
return "", errors.New("failed to create " + sysoPath + ": " + err.Error())
}
@@ -824,43 +806,11 @@ func lazyRebuildAssets() {
shouldRebuild := shouldRebuildAssets("lib/api/auto/gui.files.go", "gui") ||
shouldRebuildAssets("cmd/infra/strelaypoolsrv/auto/gui.files.go", "cmd/infra/strelaypoolsrv/gui")
if withNextGenGUI {
shouldRebuild = buildNextGenGUI() || shouldRebuild
}
if shouldRebuild {
rebuildAssets()
}
}
func buildNextGenGUI() bool {
// Check if we need to run the npm process, and if so also set the flag
// to rebuild Go assets afterwards. The index.html is regenerated every
// time by the build process. This assumes the new GUI ends up in
// next-gen-gui/dist/next-gen-gui.
if !shouldRebuildAssets("gui/next-gen-gui/index.html", "next-gen-gui") {
// The GUI is up to date.
return false
}
runPrintInDir("next-gen-gui", "npm", "install")
runPrintInDir("next-gen-gui", "npm", "run", "build", "--", "--prod", "--subresource-integrity")
rmr("gui/tech-ui")
for _, src := range listFiles("next-gen-gui/dist") {
rel, _ := filepath.Rel("next-gen-gui/dist", src)
dst := filepath.Join("gui", rel)
if err := copyFile(src, dst, 0o644); err != nil {
fmt.Println("copy:", err)
os.Exit(1)
}
}
return true
}
func shouldRebuildAssets(target, srcdir string) bool {
info, err := os.Stat(target)
if err != nil {
@@ -920,7 +870,6 @@ func testmocks() {
"github.com/syncthing/syncthing/lib/connections",
"github.com/syncthing/syncthing/lib/discover",
"github.com/syncthing/syncthing/lib/events",
"github.com/syncthing/syncthing/lib/logger",
"github.com/syncthing/syncthing/lib/model",
"github.com/syncthing/syncthing/lib/protocol",
}
@@ -951,6 +900,7 @@ func weblate() {
func ldflags(tags []string) string {
b := new(strings.Builder)
b.WriteString("-w")
b.WriteString(" -buildid=")
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Version=%s", version)
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Stamp=%d", buildStamp())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.User=%s", buildUser())
@@ -972,6 +922,9 @@ func rmr(paths ...string) {
}
func getReleaseVersion() (string, error) {
if ver := os.Getenv("VERSION"); ver != "" {
return strings.TrimSpace(ver), nil
}
bs, err := os.ReadFile("RELEASE")
if err != nil {
return "", err
@@ -1016,7 +969,7 @@ func getGitVersion() (string, error) {
}
func getVersion() string {
// First try for a RELEASE file,
// First try for a RELEASE file or $VERSION env var,
if ver, err := getReleaseVersion(); err == nil {
return ver
}
@@ -1345,10 +1298,7 @@ func zipFile(out string, files []archiveFile) {
}
func codesign(target target) {
switch goos {
case "windows":
windowsCodesign(target.BinaryName())
case "darwin":
if goos == "darwin" {
macosCodesign(target.BinaryName())
}
}
@@ -1372,70 +1322,6 @@ func macosCodesign(file string) {
}
}
func windowsCodesign(file string) {
st := "signtool.exe"
if path := os.Getenv("CODESIGN_SIGNTOOL"); path != "" {
st = path
}
for i, algo := range []string{"sha1", "sha256"} {
args := []string{"sign", "/fd", algo}
if f := os.Getenv("CODESIGN_CERTIFICATE_FILE"); f != "" {
args = append(args, "/f", f)
} else if b := os.Getenv("CODESIGN_CERTIFICATE_BASE64"); b != "" {
// Decode the PFX certificate from base64.
bs, err := base64.RawStdEncoding.DecodeString(b)
if err != nil {
log.Println("Codesign: signing failed: decoding base64:", err)
return
}
// Write it to a temporary file
f, err := os.CreateTemp("", "codesign-*.pfx")
if err != nil {
log.Println("Codesign: signing failed: creating temp file:", err)
return
}
_ = f.Chmod(0o600) // best effort remove other users' access
defer os.Remove(f.Name())
if _, err := f.Write(bs); err != nil {
log.Println("Codesign: signing failed: writing temp file:", err)
return
}
if err := f.Close(); err != nil {
log.Println("Codesign: signing failed: closing temp file:", err)
return
}
// Use that when signing
args = append(args, "/f", f.Name())
}
if p := os.Getenv("CODESIGN_CERTIFICATE_PASSWORD"); p != "" {
args = append(args, "/p", p)
}
if tr := os.Getenv("CODESIGN_TIMESTAMP_SERVER"); tr != "" {
switch algo {
case "sha256":
args = append(args, "/tr", tr, "/td", algo)
default:
args = append(args, "/t", tr)
}
}
if i > 0 {
args = append(args, "/as")
}
args = append(args, file)
bs, err := runError(st, args...)
if err != nil {
log.Printf("Codesign: signing failed: %v: %s", err, string(bs))
return
}
log.Println("Codesign: successfully signed", file, "using", algo)
}
}
func metalint() {
lazyRebuildAssets()
runPrint(goCmd, "test", "-run", "Metalint", "./meta")

View File

@@ -23,6 +23,7 @@ case "${1:-default}" in
prerelease)
script authors
script copyrights
build weblate
pushd man ; ./refresh.sh ; popd
git add -A gui man AUTHORS

View File

@@ -72,7 +72,7 @@ func main() {
if *standardBlocks || blockSize < protocol.MinBlockSize {
blockSize = protocol.BlockSize(fi.Size())
}
bs, err := scanner.Blocks(context.TODO(), fd, blockSize, fi.Size(), nil, true)
bs, err := scanner.Blocks(context.TODO(), fd, blockSize, fi.Size(), nil)
if err != nil {
log.Fatal(err)
}

View File

@@ -8,6 +8,7 @@ package main
import (
"bytes"
"cmp"
"compress/gzip"
"context"
"io"
@@ -15,7 +16,7 @@ import (
"math"
"os"
"path/filepath"
"sort"
"slices"
"time"
)
@@ -177,8 +178,8 @@ func (d *diskStore) inventory() error {
})
return nil
})
sort.Slice(d.currentFiles, func(i, j int) bool {
return d.currentFiles[i].mtime < d.currentFiles[j].mtime
slices.SortFunc(d.currentFiles, func(a, b currentFile) int {
return cmp.Compare(a.mtime, b.mtime)
})
var oldest time.Duration
if len(d.currentFiles) > 0 {

View File

@@ -10,7 +10,7 @@ to NAT or firewall issues.
There is very little reason why you'd want to run this yourself, as
`relaypoolsrv` is just used for announcement and lookup of public relay
servers. If you are looking to setup a private or a public relay, please
servers. If you are looking to set up a private or a public relay, please
check the documentation for
[relaysrv](https://github.com/syncthing/relaysrv), which also explains how
to join the default public pool.

View File

@@ -17,6 +17,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
@@ -29,8 +30,8 @@ import (
_ "github.com/syncthing/syncthing/lib/automaxprocs"
"github.com/syncthing/syncthing/lib/geoip"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/relay/client"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
)
@@ -110,10 +111,11 @@ var (
requestProcessors = 8
geoipLicenseKey = os.Getenv("GEOIP_LICENSE_KEY")
geoipAccountID, _ = strconv.Atoi(os.Getenv("GEOIP_ACCOUNT_ID"))
maxRelaysReturned = 100
requests chan request
mut = sync.NewRWMutex()
mut sync.RWMutex
knownRelays = make([]*relay, 0)
permanentRelays = make([]*relay, 0)
evictionTimers = make(map[string]*time.Timer)
@@ -141,6 +143,7 @@ func main() {
flag.IntVar(&requestQueueLen, "request-queue", requestQueueLen, "Queue length for incoming test requests")
flag.IntVar(&requestProcessors, "request-processors", requestProcessors, "Number of request processor routines")
flag.StringVar(&geoipLicenseKey, "geoip-license-key", geoipLicenseKey, "License key for GeoIP database")
flag.IntVar(&maxRelaysReturned, "max-relays-returned", maxRelaysReturned, "Maximum number of relays returned for a normal endpoint query")
flag.Parse()
@@ -331,6 +334,10 @@ func handleEndpointShort(rw http.ResponseWriter, r *http.Request) {
relays = append(relays, relayShort{URL: slimURL(r.URL)})
}
mut.RUnlock()
if len(relays) > maxRelaysReturned {
rand.Shuffle(relays)
relays = relays[:maxRelaysReturned]
}
_ = json.NewEncoder(rw).Encode(map[string][]relayShort{
"relays": relays,
@@ -613,7 +620,7 @@ func createTestCertificate() tls.Certificate {
}
certFile, keyFile := filepath.Join(tmpDir, "cert.pem"), filepath.Join(tmpDir, "key.pem")
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365)
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365, false)
if err != nil {
log.Fatalln("Failed to create test X509 key pair:", err)
}

View File

@@ -13,7 +13,6 @@ import (
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
)
@@ -28,8 +27,6 @@ func init() {
{URL: "known2"},
{URL: "known3"},
}
mut = new(sync.RWMutex)
}
// Regression test: handleGetRequest should not modify permanentRelays.

View File

@@ -6,10 +6,10 @@ import (
"encoding/json"
"net"
"net/http"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/syncthing/syncthing/lib/sync"
)
var (
@@ -104,7 +104,7 @@ func refreshStats() {
mut.RUnlock()
now := time.Now()
wg := sync.NewWaitGroup()
var wg sync.WaitGroup
results := make(chan statsFetchResult, len(relays))
for _, rel := range relays {
@@ -173,7 +173,7 @@ func fetchStats(relay *relay) *stats {
var stats stats
if json.NewDecoder(response.Body).Decode(&stats); err != nil {
if err := json.NewDecoder(response.Body).Decode(&stats); err != nil {
return nil
}
return &stats

View File

@@ -24,6 +24,7 @@ import (
"github.com/alecthomas/kong"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/syncthing/syncthing/internal/slogutil"
_ "github.com/syncthing/syncthing/lib/automaxprocs"
"github.com/syncthing/syncthing/lib/httpcache"
"github.com/syncthing/syncthing/lib/upgrade"
@@ -58,10 +59,10 @@ func server(params *cli) error {
if err != nil {
return fmt.Errorf("metrics: %w", err)
}
slog.Info("Metrics listener started", "addr", params.MetricsListen)
slog.Info("Metrics listener started", slogutil.Address(params.MetricsListen))
go func() {
if err := http.Serve(metricsListen, mux); err != nil {
slog.Warn("Metrics server returned", "error", err)
slog.Warn("Metrics server returned", slogutil.Error(err))
}
}()
}
@@ -75,9 +76,9 @@ func server(params *cli) error {
go func() {
for range time.NewTicker(params.CacheTime).C {
slog.Info("Refreshing cached releases", "url", params.URL)
slog.Info("Refreshing cached releases", slogutil.URI(params.URL))
if err := cache.Update(context.Background()); err != nil {
slog.Error("Failed to refresh cached releases", "url", params.URL, "error", err)
slog.Error("Failed to refresh cached releases", slogutil.URI(params.URL), slogutil.Error(err))
}
}
}()
@@ -109,7 +110,7 @@ func server(params *cli) error {
if err != nil {
return fmt.Errorf("listen: %w", err)
}
slog.Info("Main listener started", "addr", params.Listen)
slog.Info("Main listener started", slogutil.Address(params.Listen))
return srv.Serve(srvListener)
}
@@ -201,17 +202,21 @@ func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// looking for a prerelease at all.
func filterForLatest(rels []upgrade.Release) []upgrade.Release {
var filtered []upgrade.Release
var havePre bool
havePre := make(map[string]bool)
haveStable := make(map[string]bool)
for _, rel := range rels {
if !rel.Prerelease {
// We found a stable version, we're good now.
major, _, _ := strings.Cut(rel.Tag, ".")
if !rel.Prerelease && !haveStable[major] {
// Remember the first non-pre for each major
filtered = append(filtered, rel)
break
haveStable[major] = true
continue
}
if rel.Prerelease && !havePre {
// We remember the first prerelease we find.
if rel.Prerelease && !havePre[major] && !haveStable[major] {
// We remember the first prerelease we find, unless we've
// already found a non-pre of the same major.
filtered = append(filtered, rel)
havePre = true
havePre[major] = true
}
}
return filtered
@@ -258,9 +263,10 @@ func filterForCompabitility(rels []upgrade.Release, ua, osv string) []upgrade.Re
}
type cachedReleases struct {
url string
mut sync.RWMutex
current []upgrade.Release
url string
mut sync.RWMutex
current []upgrade.Release
latestRel, latestPre string
}
func (c *cachedReleases) Releases() []upgrade.Release {
@@ -274,8 +280,26 @@ func (c *cachedReleases) Update(ctx context.Context) error {
if err != nil {
return err
}
latestRel, latestPre := "", ""
for _, rel := range rels {
if !rel.Prerelease && latestRel == "" {
latestRel = rel.Tag
}
if rel.Prerelease && latestPre == "" {
latestPre = rel.Tag
}
if latestRel != "" && latestPre != "" {
break
}
}
c.mut.Lock()
c.current = rels
if latestRel != c.latestRel || latestPre != c.latestPre {
metricLatestReleaseInfo.DeleteLabelValues(c.latestRel, c.latestPre)
metricLatestReleaseInfo.WithLabelValues(latestRel, latestPre).Set(1)
c.latestRel = latestRel
c.latestPre = latestPre
}
c.mut.Unlock()
return nil
}

View File

@@ -27,4 +27,10 @@ var (
Subsystem: "upgrade",
Name: "http_requests",
}, []string{"target", "result"})
metricLatestReleaseInfo = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "syncthing",
Subsystem: "upgrade",
Name: "latest_release_info",
Help: "Release information",
}, []string{"latest_release", "latest_pre"})
)

View File

@@ -26,9 +26,12 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/puzpuzpuz/xsync/v3"
"github.com/syncthing/syncthing/internal/blob"
"github.com/syncthing/syncthing/internal/blob/azureblob"
"github.com/syncthing/syncthing/internal/blob/s3"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/geoip"
"github.com/syncthing/syncthing/lib/s3"
"github.com/syncthing/syncthing/lib/ur/contract"
)
@@ -40,11 +43,15 @@ type CLI struct {
DumpFile string `env:"UR_DUMP_FILE" default:"reports.jsons.gz"`
DumpInterval time.Duration `env:"UR_DUMP_INTERVAL" default:"5m"`
S3Endpoint string `name:"s3-endpoint" hidden:"true" env:"UR_S3_ENDPOINT"`
S3Region string `name:"s3-region" hidden:"true" env:"UR_S3_REGION"`
S3Bucket string `name:"s3-bucket" hidden:"true" env:"UR_S3_BUCKET"`
S3AccessKeyID string `name:"s3-access-key-id" hidden:"true" env:"UR_S3_ACCESS_KEY_ID"`
S3SecretKey string `name:"s3-secret-key" hidden:"true" env:"UR_S3_SECRET_KEY"`
S3Endpoint string `name:"s3-endpoint" env:"UR_S3_ENDPOINT"`
S3Region string `name:"s3-region" env:"UR_S3_REGION"`
S3Bucket string `name:"s3-bucket" env:"UR_S3_BUCKET"`
S3AccessKeyID string `name:"s3-access-key-id" env:"UR_S3_ACCESS_KEY_ID"`
S3SecretKey string `name:"s3-secret-key" env:"UR_S3_SECRET_KEY"`
AzureBlobAccount string `name:"azure-blob-account" env:"UR_AZUREBLOB_ACCOUNT"`
AzureBlobKey string `name:"azure-blob-key" env:"UR_AZUREBLOB_KEY"`
AzureBlobContainer string `name:"azure-blob-container" env:"UR_AZUREBLOB_CONTAINER"`
}
var (
@@ -77,6 +84,7 @@ var (
{regexp.MustCompile(`\ssyncthing@archlinux`), "Arch (3rd party)"},
{regexp.MustCompile(`@debian`), "Debian (3rd party)"},
{regexp.MustCompile(`@fedora`), "Fedora (3rd party)"},
{regexp.MustCompile(`@openSUSE`), "openSUSE (3rd party)"},
{regexp.MustCompile(`\sbrew@`), "Homebrew (3rd party)"},
{regexp.MustCompile(`\sroot@buildkitsandbox`), "LinuxServer.io (3rd party)"},
{regexp.MustCompile(`\sports@freebsd`), "FreeBSD (3rd party)"},
@@ -97,42 +105,48 @@ func (cli *CLI) Run() error {
urListener, err := net.Listen("tcp", cli.Listen)
if err != nil {
slog.Error("Failed to listen (usage reports)", "error", err)
slog.Error("Failed to listen (usage reports)", slogutil.Error(err))
return err
}
slog.Info("Listening (usage reports)", "address", urListener.Addr())
slog.Info("Listening (usage reports)", slogutil.Address(urListener.Addr()))
internalListener, err := net.Listen("tcp", cli.ListenInternal)
if err != nil {
slog.Error("Failed to listen (internal)", "error", err)
slog.Error("Failed to listen (internal)", slogutil.Error(err))
return err
}
slog.Info("Listening (internal)", "address", internalListener.Addr())
slog.Info("Listening (internal)", slogutil.Address(internalListener.Addr()))
var geo *geoip.Provider
if cli.GeoIPAccountID != 0 && cli.GeoIPLicenseKey != "" {
geo, err = geoip.NewGeoLite2CityProvider(context.Background(), cli.GeoIPAccountID, cli.GeoIPLicenseKey, os.TempDir())
if err != nil {
slog.Error("Failed to load GeoIP", "error", err)
slog.Error("Failed to load GeoIP", slogutil.Error(err))
return err
}
go geo.Serve(context.TODO())
}
// s3
// Blob storage
var s3sess *s3.Session
var blobs blob.Store
if cli.S3Endpoint != "" {
s3sess, err = s3.NewSession(cli.S3Endpoint, cli.S3Region, cli.S3Bucket, cli.S3AccessKeyID, cli.S3SecretKey)
blobs, err = s3.NewSession(cli.S3Endpoint, cli.S3Region, cli.S3Bucket, cli.S3AccessKeyID, cli.S3SecretKey)
if err != nil {
slog.Error("Failed to create S3 session", "error", err)
slog.Error("Failed to create S3 session", slogutil.Error(err))
return err
}
} else if cli.AzureBlobAccount != "" {
blobs, err = azureblob.NewBlobStore(cli.AzureBlobAccount, cli.AzureBlobKey, cli.AzureBlobContainer)
if err != nil {
slog.Error("Failed to create Azure blob store", slogutil.Error(err))
return err
}
}
if _, err := os.Stat(cli.DumpFile); err != nil && s3sess != nil {
if err := cli.downloadDumpFile(s3sess); err != nil {
slog.Error("Failed to download dump file", "error", err)
if _, err := os.Stat(cli.DumpFile); err != nil && blobs != nil {
if err := cli.downloadDumpFile(blobs); err != nil {
slog.Error("Failed to download dump file", slogutil.Error(err))
}
}
@@ -153,8 +167,8 @@ func (cli *CLI) Run() error {
go func() {
for range time.Tick(cli.DumpInterval) {
if err := cli.saveDumpFile(srv, s3sess); err != nil {
slog.Error("Failed to write dump file", "error", err)
if err := cli.saveDumpFile(srv, blobs); err != nil {
slog.Error("Failed to write dump file", slogutil.Error(err))
}
}
}()
@@ -192,8 +206,8 @@ func (cli *CLI) Run() error {
return metricsSrv.Serve(urListener)
}
func (cli *CLI) downloadDumpFile(s3sess *s3.Session) error {
latestKey, err := s3sess.LatestKey()
func (cli *CLI) downloadDumpFile(blobs blob.Store) error {
latestKey, err := blobs.LatestKey(context.Background())
if err != nil {
return fmt.Errorf("list latest S3 key: %w", err)
}
@@ -201,7 +215,7 @@ func (cli *CLI) downloadDumpFile(s3sess *s3.Session) error {
if err != nil {
return fmt.Errorf("create dump file: %w", err)
}
if err := s3sess.Download(fd, latestKey); err != nil {
if err := blobs.Download(context.Background(), latestKey, fd); err != nil {
_ = fd.Close()
return fmt.Errorf("download dump file: %w", err)
}
@@ -212,7 +226,7 @@ func (cli *CLI) downloadDumpFile(s3sess *s3.Session) error {
return nil
}
func (cli *CLI) saveDumpFile(srv *server, s3sess *s3.Session) error {
func (cli *CLI) saveDumpFile(srv *server, blobs blob.Store) error {
fd, err := os.Create(cli.DumpFile + ".tmp")
if err != nil {
return fmt.Errorf("creating dump file: %w", err)
@@ -233,13 +247,13 @@ func (cli *CLI) saveDumpFile(srv *server, s3sess *s3.Session) error {
}
slog.Info("Dump file saved")
if s3sess != nil {
if blobs != nil {
key := fmt.Sprintf("reports-%s.jsons.gz", time.Now().UTC().Format("2006-01-02"))
fd, err := os.Open(cli.DumpFile)
if err != nil {
return fmt.Errorf("opening dump file: %w", err)
}
if err := s3sess.Upload(fd, key); err != nil {
if err := blobs.Upload(context.Background(), key, fd); err != nil {
return fmt.Errorf("uploading dump file: %w", err)
}
_ = fd.Close()
@@ -294,7 +308,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
lr := &io.LimitedReader{R: r.Body, N: 40 * 1024}
bs, _ := io.ReadAll(lr)
if err := json.Unmarshal(bs, &rep); err != nil {
log.Error("Failed to decode JSON", "error", err)
log.Error("Failed to decode JSON", slogutil.Error(err))
http.Error(w, "JSON Decode Error", http.StatusInternalServerError)
return
}
@@ -304,7 +318,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
rep.Address = addr
if err := rep.Validate(); err != nil {
log.Error("Failed to validate report", "error", err)
log.Error("Failed to validate report", slogutil.Error(err))
http.Error(w, "Validation Error", http.StatusInternalServerError)
return
}
@@ -351,6 +365,9 @@ func (s *server) addReport(rep *contract.Report) bool {
break
}
}
rep.DistDist = rep.Distribution
rep.DistOS = rep.OS
rep.DistArch = rep.Arch
_, loaded := s.reports.LoadAndStore(rep.UniqueID, rep)
return loaded
@@ -378,7 +395,7 @@ func (s *server) load(r io.Reader) {
if err := dec.Decode(&rep); errors.Is(err, io.EOF) {
break
} else if err != nil {
slog.Error("Failed to load record", "error", err)
slog.Error("Failed to load record", slogutil.Error(err))
break
}
s.addReport(&rep)

View File

@@ -66,7 +66,7 @@ type contextKey int
const idKey contextKey = iota
func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator, useHTTP, compression bool) *apiSrv {
func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator, useHTTP, compression bool, desiredNotFoundRate float64) *apiSrv {
return &apiSrv{
addr: addr,
cert: cert,
@@ -77,13 +77,13 @@ func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator,
seenTracker: &retryAfterTracker{
name: "seenTracker",
bucketStarts: time.Now(),
desiredRate: 250,
desiredRate: desiredNotFoundRate / 2,
currentDelay: notFoundRetryUnknownMinSeconds,
},
notSeenTracker: &retryAfterTracker{
name: "notSeenTracker",
bucketStarts: time.Now(),
desiredRate: 250,
desiredRate: desiredNotFoundRate / 2,
currentDelay: notFoundRetryUnknownMaxSeconds / 2,
},
}

View File

@@ -111,11 +111,11 @@ func BenchmarkAPIRequests(b *testing.B) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go db.Serve(ctx)
api := newAPISrv("127.0.0.1:0", tls.Certificate{}, db, nil, true, true)
api := newAPISrv("127.0.0.1:0", tls.Certificate{}, db, nil, true, true, 1000)
srv := httptest.NewServer(http.HandlerFunc(api.handler))
kf := b.TempDir() + "/cert"
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7)
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7, true)
if err != nil {
b.Fatal(err)
}

View File

@@ -24,11 +24,11 @@ import (
"github.com/puzpuzpuz/xsync/v3"
"google.golang.org/protobuf/proto"
"github.com/syncthing/syncthing/internal/blob"
"github.com/syncthing/syncthing/internal/gen/discosrv"
"github.com/syncthing/syncthing/internal/protoutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/s3"
)
type clock interface {
@@ -51,12 +51,12 @@ type inMemoryStore struct {
m *xsync.MapOf[protocol.DeviceID, *discosrv.DatabaseRecord]
dir string
flushInterval time.Duration
s3 *s3.Session
blobs blob.Store
objKey string
clock clock
}
func newInMemoryStore(dir string, flushInterval time.Duration, s3sess *s3.Session) *inMemoryStore {
func newInMemoryStore(dir string, flushInterval time.Duration, blobs blob.Store) *inMemoryStore {
hn, err := os.Hostname()
if err != nil {
hn = rand.String(8)
@@ -65,25 +65,25 @@ func newInMemoryStore(dir string, flushInterval time.Duration, s3sess *s3.Sessio
m: xsync.NewMapOf[protocol.DeviceID, *discosrv.DatabaseRecord](),
dir: dir,
flushInterval: flushInterval,
s3: s3sess,
blobs: blobs,
objKey: hn + ".db",
clock: defaultClock{},
}
nr, err := s.read()
if os.IsNotExist(err) && s3sess != nil {
// Try to read from AWS
latestKey, cerr := s3sess.LatestKey()
if os.IsNotExist(err) && blobs != nil {
// Try to read from blob storage
latestKey, cerr := blobs.LatestKey(context.Background())
if cerr != nil {
log.Println("Error reading database from S3:", err)
log.Println("Error finding database from blob storage:", cerr)
return s
}
fd, cerr := os.Create(path.Join(s.dir, "records.db"))
if cerr != nil {
log.Println("Error creating database file:", err)
log.Println("Error creating database file:", cerr)
return s
}
if cerr := s3sess.Download(fd, latestKey); cerr != nil {
log.Printf("Error reading database from S3: %v", err)
if cerr := blobs.Download(context.Background(), latestKey, fd); cerr != nil {
log.Printf("Error downloading database from blob storage: %v", cerr)
}
_ = fd.Close()
nr, err = s.read()
@@ -310,16 +310,16 @@ func (s *inMemoryStore) write() (err error) {
return err
}
// Upload to S3
if s.s3 != nil {
// Upload to blob storage
if s.blobs != nil {
fd, err = os.Open(dbf)
if err != nil {
log.Printf("Error uploading database to S3: %v", err)
log.Printf("Error uploading database to blob storage: %v", err)
return nil
}
defer fd.Close()
if err := s.s3.Upload(fd, s.objKey); err != nil {
log.Printf("Error uploading database to S3: %v", err)
if err := s.blobs.Upload(context.Background(), s.objKey, fd); err != nil {
log.Printf("Error uploading database to blob storage: %v", err)
}
log.Println("Finished uploading database")
}

View File

@@ -21,11 +21,13 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/thejerf/suture/v4"
"github.com/syncthing/syncthing/internal/blob"
"github.com/syncthing/syncthing/internal/blob/azureblob"
"github.com/syncthing/syncthing/internal/blob/s3"
_ "github.com/syncthing/syncthing/lib/automaxprocs"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/s3"
"github.com/syncthing/syncthing/lib/tlsutil"
)
@@ -58,12 +60,13 @@ const (
var debug = false
type CLI struct {
Cert string `group:"Listen" help:"Certificate file" default:"./cert.pem" env:"DISCOVERY_CERT_FILE"`
Key string `group:"Listen" help:"Key file" default:"./key.pem" env:"DISCOVERY_KEY_FILE"`
HTTP bool `group:"Listen" help:"Listen on HTTP (behind an HTTPS proxy)" env:"DISCOVERY_HTTP"`
Compression bool `group:"Listen" help:"Enable GZIP compression of responses" env:"DISCOVERY_COMPRESSION"`
Listen string `group:"Listen" help:"Listen address" default:":8443" env:"DISCOVERY_LISTEN"`
MetricsListen string `group:"Listen" help:"Metrics listen address" env:"DISCOVERY_METRICS_LISTEN"`
Cert string `group:"Listen" help:"Certificate file" default:"./cert.pem" env:"DISCOVERY_CERT_FILE"`
Key string `group:"Listen" help:"Key file" default:"./key.pem" env:"DISCOVERY_KEY_FILE"`
HTTP bool `group:"Listen" help:"Listen on HTTP (behind an HTTPS proxy)" env:"DISCOVERY_HTTP"`
Compression bool `group:"Listen" help:"Enable GZIP compression of responses" env:"DISCOVERY_COMPRESSION"`
Listen string `group:"Listen" help:"Listen address" default:":8443" env:"DISCOVERY_LISTEN"`
MetricsListen string `group:"Listen" help:"Metrics listen address" env:"DISCOVERY_METRICS_LISTEN"`
DesiredNotFoundRate float64 `group:"Listen" help:"Desired maximum rate of not-found replies (/s)" default:"1000"`
DBDir string `group:"Database" help:"Database directory" default:"." env:"DISCOVERY_DB_DIR"`
DBFlushInterval time.Duration `group:"Database" help:"Interval between database flushes" default:"5m" env:"DISCOVERY_DB_FLUSH_INTERVAL"`
@@ -74,6 +77,10 @@ type CLI struct {
DBS3AccessKeyID string `name:"db-s3-access-key-id" group:"Database (S3 backup)" hidden:"true" help:"S3 access key ID for database" env:"DISCOVERY_DB_S3_ACCESS_KEY_ID"`
DBS3SecretKey string `name:"db-s3-secret-key" group:"Database (S3 backup)" hidden:"true" help:"S3 secret key for database" env:"DISCOVERY_DB_S3_SECRET_KEY"`
DBAzureBlobAccount string `name:"db-azure-blob-account" env:"DISCOVERY_DB_AZUREBLOB_ACCOUNT"`
DBAzureBlobKey string `name:"db-azure-blob-key" env:"DISCOVERY_DB_AZUREBLOB_KEY"`
DBAzureBlobContainer string `name:"db-azure-blob-container" env:"DISCOVERY_DB_AZUREBLOB_CONTAINER"`
AMQPAddress string `group:"AMQP replication" hidden:"true" help:"Address to AMQP broker" env:"DISCOVERY_AMQP_ADDRESS"`
Debug bool `short:"d" help:"Print debug output" env:"DISCOVERY_DEBUG"`
@@ -100,7 +107,7 @@ func main() {
cert, err = tls.LoadX509KeyPair(cli.Cert, cli.Key)
if os.IsNotExist(err) {
log.Println("Failed to load keypair. Generating one, this might take a while...")
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365)
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365, false)
if err != nil {
log.Fatalln("Failed to generate X509 key pair:", err)
}
@@ -117,18 +124,20 @@ func main() {
Timeout: 2 * time.Minute,
})
// If configured, use S3 for database backups.
var s3c *s3.Session
// If configured, use blob storage for database backups.
var blobs blob.Store
var err error
if cli.DBS3Endpoint != "" {
var err error
s3c, err = s3.NewSession(cli.DBS3Endpoint, cli.DBS3Region, cli.DBS3Bucket, cli.DBS3AccessKeyID, cli.DBS3SecretKey)
if err != nil {
log.Fatalf("Failed to create S3 session: %v", err)
}
blobs, err = s3.NewSession(cli.DBS3Endpoint, cli.DBS3Region, cli.DBS3Bucket, cli.DBS3AccessKeyID, cli.DBS3SecretKey)
} else if cli.DBAzureBlobAccount != "" {
blobs, err = azureblob.NewBlobStore(cli.DBAzureBlobAccount, cli.DBAzureBlobKey, cli.DBAzureBlobContainer)
}
if err != nil {
log.Fatalf("Failed to create blob store: %v", err)
}
// Start the database.
db := newInMemoryStore(cli.DBDir, cli.DBFlushInterval, s3c)
db := newInMemoryStore(cli.DBDir, cli.DBFlushInterval, blobs)
main.Add(db)
// If we have an AMQP broker for replication, start that
@@ -141,7 +150,7 @@ func main() {
}
// Start the main API server.
qs := newAPISrv(cli.Listen, cert, db, repl, cli.HTTP, cli.Compression)
qs := newAPISrv(cli.Listen, cert, db, repl, cli.HTTP, cli.Compression, cli.DesiredNotFoundRate)
main.Add(qs)
// If we have a metrics port configured, start a metrics handler.

View File

@@ -184,7 +184,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token strin
continue
}
// requestedPeer is the server, id is the client
ses := newSession(requestedPeer, id, sessionLimiter, globalLimiter)
ses := newSession(requestedPeer, id, sessionLimitBps, globalLimiter)
go ses.Serve()

View File

@@ -51,7 +51,6 @@ var (
globalLimitBps int
overLimit atomic.Bool
descriptorLimit int64
sessionLimiter *rate.Limiter
globalLimiter *rate.Limiter
networkBufferSize int
@@ -158,7 +157,7 @@ func main() {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Println("Failed to load keypair. Generating one, this might take a while...")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365)
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365, false)
if err != nil {
log.Fatalln("Failed to generate X509 key pair:", err)
}
@@ -228,9 +227,6 @@ func main() {
}
}
if sessionLimitBps > 0 {
sessionLimiter = rate.NewLimiter(rate.Limit(sessionLimitBps), 2*sessionLimitBps)
}
if globalLimitBps > 0 {
globalLimiter = rate.NewLimiter(rate.Limit(globalLimitBps), 2*globalLimitBps)
}

View File

@@ -27,7 +27,7 @@ var (
bytesProxied atomic.Int64
)
func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit, globalRateLimit *rate.Limiter) *session {
func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionLimitBps int, globalRateLimit *rate.Limiter) *session {
serverkey := make([]byte, 32)
_, err := rand.Read(serverkey)
if err != nil {
@@ -40,12 +40,17 @@ func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit,
return nil
}
var sessionRateLimit *rate.Limiter
if sessionLimitBps > 0 {
sessionRateLimit = rate.NewLimiter(rate.Limit(sessionLimitBps), 2*sessionLimitBps)
}
ses := &session{
serverkey: serverkey,
serverid: serverid,
clientkey: clientkey,
clientid: clientid,
rateLimit: makeRateLimitFunc(sessionRateLimit, globalRateLimit),
limiter: sessionRateLimit,
connsChan: make(chan net.Conn),
conns: make([]net.Conn, 0, 2),
}
@@ -109,6 +114,7 @@ type session struct {
clientid syncthingprotocol.DeviceID
rateLimit func(bytes int)
limiter *rate.Limiter
connsChan chan net.Conn
conns []net.Conn

View File

@@ -8,11 +8,14 @@ package main
import (
"fmt"
"log/slog"
"os"
"runtime"
"runtime/pprof"
"syscall"
"time"
"github.com/syncthing/syncthing/internal/slogutil"
)
func startBlockProfiler() {
@@ -20,10 +23,10 @@ func startBlockProfiler() {
if profiler == nil {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
slog.Debug("Starting block profiling")
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
slog.Error("Block profiler failed", slogutil.Error(err))
panic("Block profiler failed")
}()
}

View File

@@ -41,5 +41,4 @@ func (p *profileCommand) Run(ctx Context) error {
type debugCommand struct {
File fileCommand `cmd:"" help:"Show information about a file (or directory/symlink)"`
Profile profileCommand `cmd:"" help:"Save a profile to help figuring out what Syncthing does"`
Index indexCommand `cmd:"" help:"Show information about the index (database)"`
}

View File

@@ -1,32 +0,0 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cli
import (
"github.com/alecthomas/kong"
)
type indexCommand struct {
Dump struct{} `cmd:"" help:"Print the entire db"`
DumpSize struct{} `cmd:"" help:"Print the db size of different categories of information"`
Check struct{} `cmd:"" help:"Check the database for inconsistencies"`
Account struct{} `cmd:"" help:"Print key and value size statistics per key type"`
}
func (*indexCommand) Run(kongCtx *kong.Context) error {
switch kongCtx.Selected().Name {
case "dump":
return indexDump()
case "dump-size":
return indexDumpSize()
case "check":
return indexCheck()
case "account":
return indexAccount()
}
return nil
}

View File

@@ -1,62 +0,0 @@
// Copyright (C) 2020 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cli
import (
"fmt"
"os"
"text/tabwriter"
)
// indexAccount prints key and data size statistics per class
func indexAccount() error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
var ksizes [256]int
var dsizes [256]int
var counts [256]int
var max [256]int
for it.Next() {
key := it.Key()
t := key[0]
ds := len(it.Value())
ks := len(key)
s := ks + ds
counts[t]++
ksizes[t] += ks
dsizes[t] += ds
if s > max[t] {
max[t] = s
}
}
tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', tabwriter.AlignRight)
toti, totds, totks := 0, 0, 0
for t := range ksizes {
if ksizes[t] > 0 {
// yes metric kilobytes 🤘
fmt.Fprintf(tw, "0x%02x:\t%d items,\t%d KB keys +\t%d KB data,\t%d B +\t%d B avg,\t%d B max\t\n", t, counts[t], ksizes[t]/1000, dsizes[t]/1000, ksizes[t]/counts[t], dsizes[t]/counts[t], max[t])
toti += counts[t]
totds += dsizes[t]
totks += ksizes[t]
}
}
fmt.Fprintf(tw, "Total\t%d items,\t%d KB keys +\t%d KB data.\t\n", toti, totks/1000, totds/1000)
tw.Flush()
return nil
}

View File

@@ -1,162 +0,0 @@
// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cli
import (
"encoding/binary"
"fmt"
"time"
"google.golang.org/protobuf/proto"
"github.com/syncthing/syncthing/internal/gen/bep"
"github.com/syncthing/syncthing/internal/gen/dbproto"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/protocol"
)
func indexDump() error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
for it.Next() {
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
folder := binary.BigEndian.Uint32(key[1:])
device := binary.BigEndian.Uint32(key[1+4:])
name := nulString(key[1+4+4:])
fmt.Printf("[device] F:%d D:%d N:%q", folder, device, name)
var f bep.FileInfo
err := proto.Unmarshal(it.Value(), &f)
if err != nil {
return err
}
fmt.Printf(" V:%v\n", &f)
case db.KeyTypeGlobal:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
var flv dbproto.VersionList
proto.Unmarshal(it.Value(), &flv)
fmt.Printf("[global] F:%d N:%q V:%s\n", folder, name, &flv)
case db.KeyTypeBlock:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[1+4 : 1+4+32]
name := nulString(key[1+4+32:])
fmt.Printf("[block] F:%d H:%x N:%q I:%d\n", folder, hash, name, binary.BigEndian.Uint32(it.Value()))
case db.KeyTypeDeviceStatistic:
fmt.Printf("[dstat] K:%x V:%x\n", key, it.Value())
case db.KeyTypeFolderStatistic:
fmt.Printf("[fstat] K:%x V:%x\n", key, it.Value())
case db.KeyTypeVirtualMtime:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
val := it.Value()
var realTime, virtualTime time.Time
realTime.UnmarshalBinary(val[:len(val)/2])
virtualTime.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, realTime, virtualTime)
case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(key[1:])
fmt.Printf("[folderidx] K:%d V:%q\n", key, it.Value())
case db.KeyTypeDeviceIdx:
key := binary.BigEndian.Uint32(key[1:])
val := it.Value()
device := "<nil>"
if len(val) > 0 {
dev, err := protocol.DeviceIDFromBytes(val)
if err != nil {
device = fmt.Sprintf("<invalid %d bytes>", len(val))
} else {
device = dev.String()
}
}
fmt.Printf("[deviceidx] K:%d V:%s\n", key, device)
case db.KeyTypeIndexID:
device := binary.BigEndian.Uint32(key[1:])
folder := binary.BigEndian.Uint32(key[5:])
fmt.Printf("[indexid] D:%d F:%d I:%x\n", device, folder, it.Value())
case db.KeyTypeFolderMeta:
folder := binary.BigEndian.Uint32(key[1:])
fmt.Printf("[foldermeta] F:%d", folder)
var cs dbproto.CountsSet
if err := proto.Unmarshal(it.Value(), &cs); err != nil {
fmt.Printf(" (invalid)\n")
} else {
fmt.Printf(" V:%v\n", &cs)
}
case db.KeyTypeMiscData:
fmt.Printf("[miscdata] K:%q V:%q\n", key[1:], it.Value())
case db.KeyTypeSequence:
folder := binary.BigEndian.Uint32(key[1:])
seq := binary.BigEndian.Uint64(key[5:])
fmt.Printf("[sequence] F:%d S:%d V:%q\n", folder, seq, it.Value())
case db.KeyTypeNeed:
folder := binary.BigEndian.Uint32(key[1:])
file := string(key[5:])
fmt.Printf("[need] F:%d V:%q\n", folder, file)
case db.KeyTypeBlockList:
fmt.Printf("[blocklist] H:%x\n", key[1:])
case db.KeyTypeBlockListMap:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[5:37]
fileName := string(key[37:])
fmt.Printf("[blocklistmap] F:%d H:%x N:%s\n", folder, hash, fileName)
case db.KeyTypeVersion:
fmt.Printf("[version] H:%x", key[1:])
var v bep.Vector
err := proto.Unmarshal(it.Value(), &v)
if err != nil {
fmt.Printf(" (invalid)\n")
} else {
fmt.Printf(" V:%v\n", &v)
}
case db.KeyTypePendingFolder:
device := binary.BigEndian.Uint32(key[1:])
folder := string(key[5:])
var of dbproto.ObservedFolder
proto.Unmarshal(it.Value(), &of)
fmt.Printf("[pendingFolder] D:%d F:%s V:%v\n", device, folder, &of)
case db.KeyTypePendingDevice:
device := "<invalid>"
dev, err := protocol.DeviceIDFromBytes(key[1:])
if err == nil {
device = dev.String()
}
var od dbproto.ObservedDevice
proto.Unmarshal(it.Value(), &od)
fmt.Printf("[pendingDevice] D:%v V:%v\n", device, &od)
default:
fmt.Printf("[??? %d]\n %x\n %x\n", key[0], key, it.Value())
}
}
return nil
}

View File

@@ -1,88 +0,0 @@
// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cli
import (
"encoding/binary"
"fmt"
"sort"
"github.com/syncthing/syncthing/lib/db"
)
func indexDumpSize() error {
type sizedElement struct {
key string
size int
}
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
var elems []sizedElement
for it.Next() {
var ele sizedElement
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
folder := binary.BigEndian.Uint32(key[1:])
device := binary.BigEndian.Uint32(key[1+4:])
name := nulString(key[1+4+4:])
ele.key = fmt.Sprintf("DEVICE:%d:%d:%s", folder, device, name)
case db.KeyTypeGlobal:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
ele.key = fmt.Sprintf("GLOBAL:%d:%s", folder, name)
case db.KeyTypeBlock:
folder := binary.BigEndian.Uint32(key[1:])
hash := key[1+4 : 1+4+32]
name := nulString(key[1+4+32:])
ele.key = fmt.Sprintf("BLOCK:%d:%x:%s", folder, hash, name)
case db.KeyTypeDeviceStatistic:
ele.key = fmt.Sprintf("DEVICESTATS:%s", key[1:])
case db.KeyTypeFolderStatistic:
ele.key = fmt.Sprintf("FOLDERSTATS:%s", key[1:])
case db.KeyTypeVirtualMtime:
ele.key = fmt.Sprintf("MTIME:%s", key[1:])
case db.KeyTypeFolderIdx:
id := binary.BigEndian.Uint32(key[1:])
ele.key = fmt.Sprintf("FOLDERIDX:%d", id)
case db.KeyTypeDeviceIdx:
id := binary.BigEndian.Uint32(key[1:])
ele.key = fmt.Sprintf("DEVICEIDX:%d", id)
default:
ele.key = fmt.Sprintf("UNKNOWN:%x", key)
}
ele.size = len(it.Value())
elems = append(elems, ele)
}
sort.Slice(elems, func(i, j int) bool {
return elems[i].size > elems[j].size
})
for _, ele := range elems {
fmt.Println(ele.key, ele.size)
}
return nil
}

View File

@@ -1,434 +0,0 @@
// Copyright (C) 2018 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cli
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"sort"
"google.golang.org/protobuf/proto"
"github.com/syncthing/syncthing/internal/gen/bep"
"github.com/syncthing/syncthing/internal/gen/dbproto"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/protocol"
)
type fileInfoKey struct {
folder uint32
device uint32
name string
}
type globalKey struct {
folder uint32
name string
}
type sequenceKey struct {
folder uint32
sequence uint64
}
func indexCheck() (err error) {
ldb, err := getDB()
if err != nil {
return err
}
folders := make(map[uint32]string)
devices := make(map[uint32]string)
deviceToIDs := make(map[string]uint32)
fileInfos := make(map[fileInfoKey]*bep.FileInfo)
globals := make(map[globalKey]*dbproto.VersionList)
sequences := make(map[sequenceKey]string)
needs := make(map[globalKey]struct{})
blocklists := make(map[string]struct{})
versions := make(map[string]*bep.Vector)
usedBlocklists := make(map[string]struct{})
usedVersions := make(map[string]struct{})
var localDeviceKey uint32
success := true
defer func() {
if err == nil {
if success {
fmt.Println("Index check completed successfully.")
} else {
err = errors.New("Inconsistencies found in the index")
}
}
}()
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
return err
}
for it.Next() {
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
folder := binary.BigEndian.Uint32(key[1:])
device := binary.BigEndian.Uint32(key[1+4:])
name := nulString(key[1+4+4:])
var f bep.FileInfo
err := proto.Unmarshal(it.Value(), &f)
if err != nil {
fmt.Println("Unable to unmarshal FileInfo:", err)
success = false
continue
}
fileInfos[fileInfoKey{folder, device, name}] = &f
case db.KeyTypeGlobal:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
var flv dbproto.VersionList
if err := proto.Unmarshal(it.Value(), &flv); err != nil {
fmt.Println("Unable to unmarshal VersionList:", err)
success = false
continue
}
globals[globalKey{folder, name}] = &flv
case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(it.Key()[1:])
folders[key] = string(it.Value())
case db.KeyTypeDeviceIdx:
key := binary.BigEndian.Uint32(it.Key()[1:])
devices[key] = string(it.Value())
deviceToIDs[string(it.Value())] = key
if bytes.Equal(it.Value(), protocol.LocalDeviceID[:]) {
localDeviceKey = key
}
case db.KeyTypeSequence:
folder := binary.BigEndian.Uint32(key[1:])
seq := binary.BigEndian.Uint64(key[5:])
val := it.Value()
sequences[sequenceKey{folder, seq}] = string(val[9:])
case db.KeyTypeNeed:
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
needs[globalKey{folder, name}] = struct{}{}
case db.KeyTypeBlockList:
hash := string(key[1:])
blocklists[hash] = struct{}{}
case db.KeyTypeVersion:
hash := string(key[1:])
var v bep.Vector
if err := proto.Unmarshal(it.Value(), &v); err != nil {
fmt.Println("Unable to unmarshal Vector:", err)
success = false
continue
}
versions[hash] = &v
}
}
if localDeviceKey == 0 {
fmt.Println("Missing key for local device in device index (bailing out)")
success = false
return
}
var missingSeq []sequenceKey
for fk, fi := range fileInfos {
if fk.name != fi.Name {
fmt.Printf("Mismatching FileInfo name, %q (key) != %q (actual)\n", fk.name, fi.Name)
success = false
}
folder := folders[fk.folder]
if folder == "" {
fmt.Printf("Unknown folder ID %d for FileInfo %q\n", fk.folder, fk.name)
success = false
continue
}
if devices[fk.device] == "" {
fmt.Printf("Unknown device ID %d for FileInfo %q, folder %q\n", fk.folder, fk.name, folder)
success = false
}
if fk.device == localDeviceKey {
sk := sequenceKey{fk.folder, uint64(fi.Sequence)}
name, ok := sequences[sk]
if !ok {
fmt.Printf("Sequence entry missing for FileInfo %q, folder %q, seq %d\n", fi.Name, folder, fi.Sequence)
missingSeq = append(missingSeq, sk)
success = false
continue
}
if name != fi.Name {
fmt.Printf("Sequence entry refers to wrong name, %q (seq) != %q (FileInfo), folder %q, seq %d\n", name, fi.Name, folder, fi.Sequence)
success = false
}
}
if len(fi.Blocks) == 0 && len(fi.BlocksHash) != 0 {
key := string(fi.BlocksHash)
if _, ok := blocklists[key]; !ok {
fmt.Printf("Missing block list for file %q, block list hash %x\n", fi.Name, fi.BlocksHash)
success = false
} else {
usedBlocklists[key] = struct{}{}
}
}
if fi.VersionHash != nil {
key := string(fi.VersionHash)
if _, ok := versions[key]; !ok {
fmt.Printf("Missing version vector for file %q, version hash %x\n", fi.Name, fi.VersionHash)
success = false
} else {
usedVersions[key] = struct{}{}
}
}
_, ok := globals[globalKey{fk.folder, fk.name}]
if !ok {
fmt.Printf("Missing global for file %q\n", fi.Name)
success = false
continue
}
}
// Aggregate the ranges of missing sequence entries, print them
sort.Slice(missingSeq, func(a, b int) bool {
if missingSeq[a].folder != missingSeq[b].folder {
return missingSeq[a].folder < missingSeq[b].folder
}
return missingSeq[a].sequence < missingSeq[b].sequence
})
var folder uint32
var startSeq, prevSeq uint64
for _, sk := range missingSeq {
if folder != sk.folder || sk.sequence != prevSeq+1 {
if folder != 0 {
fmt.Printf("Folder %d missing %d sequence entries: #%d - #%d\n", folder, prevSeq-startSeq+1, startSeq, prevSeq)
}
startSeq = sk.sequence
folder = sk.folder
}
prevSeq = sk.sequence
}
if folder != 0 {
fmt.Printf("Folder %d missing %d sequence entries: #%d - #%d\n", folder, prevSeq-startSeq+1, startSeq, prevSeq)
}
for gk, vl := range globals {
folder := folders[gk.folder]
if folder == "" {
fmt.Printf("Unknown folder ID %d for VersionList %q\n", gk.folder, gk.name)
success = false
}
checkGlobal := func(i int, device []byte, version protocol.Vector, invalid, deleted bool) {
dev, ok := deviceToIDs[string(device)]
if !ok {
fmt.Printf("VersionList %q, folder %q refers to unknown device %q\n", gk.name, folder, device)
success = false
}
fi, ok := fileInfos[fileInfoKey{gk.folder, dev, gk.name}]
if !ok {
fmt.Printf("VersionList %q, folder %q, entry %d refers to unknown FileInfo\n", gk.name, folder, i)
success = false
}
fiv := fi.Version
if fi.VersionHash != nil {
fiv = versions[string(fi.VersionHash)]
}
if !protocol.VectorFromWire(fiv).Equal(version) {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo version mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, version, fi.Version)
success = false
}
ffi := protocol.FileInfoFromDB(fi)
if ffi.IsInvalid() != invalid {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo invalid mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, invalid, ffi.IsInvalid())
success = false
}
if ffi.IsDeleted() != deleted {
fmt.Printf("VersionList %q, folder %q, entry %d, FileInfo deleted mismatch, %v (VersionList) != %v (FileInfo)\n", gk.name, folder, i, deleted, ffi.IsDeleted())
success = false
}
}
for i, fv := range vl.Versions {
ver := protocol.VectorFromWire(fv.Version)
for _, device := range fv.Devices {
checkGlobal(i, device, ver, false, fv.Deleted)
}
for _, device := range fv.InvalidDevices {
checkGlobal(i, device, ver, true, fv.Deleted)
}
}
// If we need this file we should have a need entry for it. False
// positives from needsLocally for deleted files, where we might
// legitimately lack an entry if we never had it, and ignored files.
if needsLocally(vl) {
_, ok := needs[gk]
if !ok {
fv, _ := vlGetGlobal(vl)
devB, _ := fvFirstDevice(fv)
dev := deviceToIDs[string(devB)]
fi := protocol.FileInfoFromDB(fileInfos[fileInfoKey{gk.folder, dev, gk.name}])
if !fi.IsDeleted() && !fi.IsIgnored() {
fmt.Printf("Missing need entry for needed file %q, folder %q\n", gk.name, folder)
}
}
}
}
seenSeq := make(map[fileInfoKey]uint64)
for sk, name := range sequences {
folder := folders[sk.folder]
if folder == "" {
fmt.Printf("Unknown folder ID %d for sequence entry %d, %q\n", sk.folder, sk.sequence, name)
success = false
continue
}
if prev, ok := seenSeq[fileInfoKey{folder: sk.folder, name: name}]; ok {
fmt.Printf("Duplicate sequence entry for %q, folder %q, seq %d (prev %d)\n", name, folder, sk.sequence, prev)
success = false
}
seenSeq[fileInfoKey{folder: sk.folder, name: name}] = sk.sequence
fi, ok := fileInfos[fileInfoKey{sk.folder, localDeviceKey, name}]
if !ok {
fmt.Printf("Missing FileInfo for sequence entry %d, folder %q, %q\n", sk.sequence, folder, name)
success = false
continue
}
if fi.Sequence != int64(sk.sequence) {
fmt.Printf("Sequence mismatch for %q, folder %q, %d (key) != %d (FileInfo)\n", name, folder, sk.sequence, fi.Sequence)
success = false
}
}
for nk := range needs {
folder := folders[nk.folder]
if folder == "" {
fmt.Printf("Unknown folder ID %d for need entry %q\n", nk.folder, nk.name)
success = false
continue
}
vl, ok := globals[nk]
if !ok {
fmt.Printf("Missing global for need entry %q, folder %q\n", nk.name, folder)
success = false
continue
}
if !needsLocally(vl) {
fmt.Printf("Need entry for file we don't need, %q, folder %q\n", nk.name, folder)
success = false
}
}
if d := len(blocklists) - len(usedBlocklists); d > 0 {
fmt.Printf("%d block list entries out of %d needs GC\n", d, len(blocklists))
}
if d := len(versions) - len(usedVersions); d > 0 {
fmt.Printf("%d version entries out of %d needs GC\n", d, len(versions))
}
return nil
}
func needsLocally(vl *dbproto.VersionList) bool {
gfv, gok := vlGetGlobal(vl)
if !gok { // That's weird, but we hardly need something non-existent
return false
}
fv, ok := vlGet(vl, protocol.LocalDeviceID[:])
return db.Need(gfv, ok, protocol.VectorFromWire(fv.Version))
}
// Get returns a FileVersion that contains the given device and whether it has
// been found at all.
func vlGet(vl *dbproto.VersionList, device []byte) (*dbproto.FileVersion, bool) {
_, i, _, ok := vlFindDevice(vl, device)
if !ok {
return &dbproto.FileVersion{}, false
}
return vl.Versions[i], true
}
// GetGlobal returns the current global FileVersion. The returned FileVersion
// may be invalid, if all FileVersions are invalid. Returns false only if
// VersionList is empty.
func vlGetGlobal(vl *dbproto.VersionList) (*dbproto.FileVersion, bool) {
i := vlFindGlobal(vl)
if i == -1 {
return nil, false
}
return vl.Versions[i], true
}
// findGlobal returns the first version that isn't invalid, or if all versions are
// invalid just the first version (i.e. 0) or -1, if there's no versions at all.
func vlFindGlobal(vl *dbproto.VersionList) int {
for i := range vl.Versions {
if !fvIsInvalid(vl.Versions[i]) {
return i
}
}
if len(vl.Versions) == 0 {
return -1
}
return 0
}
// findDevice returns whether the device is in InvalidVersions or Versions and
// in InvalidDevices or Devices (true for invalid), the positions in the version
// and device slices and whether it has been found at all.
func vlFindDevice(vl *dbproto.VersionList, device []byte) (bool, int, int, bool) {
for i, v := range vl.Versions {
if j := deviceIndex(v.Devices, device); j != -1 {
return false, i, j, true
}
if j := deviceIndex(v.InvalidDevices, device); j != -1 {
return true, i, j, true
}
}
return false, -1, -1, false
}
func deviceIndex(devices [][]byte, device []byte) int {
for i, dev := range devices {
if bytes.Equal(device, dev) {
return i
}
}
return -1
}
func fvFirstDevice(fv *dbproto.FileVersion) ([]byte, bool) {
if len(fv.Devices) != 0 {
return fv.Devices[0], true
}
if len(fv.InvalidDevices) != 0 {
return fv.InvalidDevices[0], true
}
return nil, false
}
func fvIsInvalid(fv *dbproto.FileVersion) bool {
return fv == nil || len(fv.Devices) == 0
}

View File

@@ -14,15 +14,12 @@ import (
"github.com/alecthomas/kong"
"github.com/kballard/go-shellquote"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
)
type CLI struct {
cmdutil.CommonOptions
DataDir string `name:"data" placeholder:"PATH" env:"STDATADIR" help:"Set data directory (database and logs)"`
GUIAddress string `name:"gui-address"`
GUIAPIKey string `name:"gui-apikey"`
GUIAddress string `name:"gui-address" env:"STGUIADDRESS"`
GUIAPIKey string `name:"gui-apikey" env:"STGUIAPIKEY"`
Show showCommand `cmd:"" help:"Show command group"`
Debug debugCommand `cmd:"" help:"Debug command group"`
@@ -37,11 +34,6 @@ type Context struct {
}
func (cli CLI) AfterApply(kongCtx *kong.Context) error {
err := cmdutil.SetConfigDataLocationsFromFlags(cli.HomeDir, cli.ConfDir, cli.DataDir)
if err != nil {
return fmt.Errorf("command line options: %w", err)
}
clientFactory := &apiClientFactory{
cfg: config.GUIConfiguration{
RawAddress: cli.GUIAddress,

View File

@@ -17,8 +17,6 @@ import (
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/locations"
)
func responseToBArray(response *http.Response) ([]byte, error) {
@@ -133,19 +131,6 @@ func prettyPrintResponse(response *http.Response) error {
return prettyPrintJSON(data)
}
func getDB() (backend.Backend, error) {
return backend.OpenLevelDBRO(locations.Get(locations.Database))
}
func nulString(bs []byte) string {
for i := range bs {
if bs[i] == 0 {
return string(bs[:i])
}
}
return string(bs)
}
func normalizePath(path string) string {
return filepath.ToSlash(filepath.Clean(path))
}

View File

@@ -1,16 +0,0 @@
// Copyright (C) 2021 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cmdutil
// CommonOptions are reused among several subcommands
type CommonOptions struct {
buildCommonOptions
ConfDir string `name:"config" placeholder:"PATH" env:"STCONFDIR" help:"Set configuration directory (config and keys)"`
HomeDir string `name:"home" placeholder:"PATH" env:"STHOMEDIR" help:"Set configuration and data directory"`
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
SkipPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup"`
}

View File

@@ -1,35 +0,0 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cmdutil
import (
"errors"
"github.com/syncthing/syncthing/lib/locations"
)
func SetConfigDataLocationsFromFlags(homeDir, confDir, dataDir string) error {
homeSet := homeDir != ""
confSet := confDir != ""
dataSet := dataDir != ""
switch {
case dataSet != confSet:
return errors.New("either both or none of --config and --data must be given, use --home to set both at once")
case homeSet && dataSet:
return errors.New("--home must not be used together with --config and --data")
case homeSet:
confDir = homeDir
dataDir = homeDir
fallthrough
case dataSet:
if err := locations.SetBaseDir(locations.ConfigBaseDir, confDir); err != nil {
return err
}
return locations.SetBaseDir(locations.DataBaseDir, dataDir)
}
return nil
}

View File

@@ -11,12 +11,15 @@ import (
"context"
"crypto/sha256"
"fmt"
"log/slog"
"net/http"
"os"
"path/filepath"
"sort"
"slices"
"strings"
"time"
"github.com/syncthing/syncthing/internal/slogutil"
)
const (
@@ -33,11 +36,13 @@ const (
func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
files, err := filepath.Glob(filepath.Join(dir, "panic-*.log"))
if err != nil {
l.Warnln("Failed to list panic logs:", err)
slog.ErrorContext(ctx, "Failed to list panic logs", slogutil.Error(err))
return
}
sort.Sort(sort.Reverse(sort.StringSlice(files)))
slices.SortFunc(files, func(a, b string) int {
return strings.Compare(b, a)
})
for _, file := range files {
if strings.Contains(file, ".reported.") {
// We've already sent this file. It'll be cleaned out at some
@@ -46,7 +51,7 @@ func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
}
if err := uploadPanicLog(ctx, urlBase, file); err != nil {
l.Warnln("Reporting crash:", err)
slog.ErrorContext(ctx, "Reporting crash", slogutil.Error(err))
} else {
// Rename the log so we don't have to try to report it again. This
// succeeds, or it does not. There is no point complaining about it.
@@ -69,7 +74,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
data = filterLogLines(data)
hash := fmt.Sprintf("%x", sha256.Sum256(data))
l.Infof("Reporting crash found in %s (report ID %s) ...\n", filepath.Base(file), hash[:8])
slog.InfoContext(ctx, "Reporting crash", slogutil.FilePath(filepath.Base(file)), slog.String("id", hash[:8]))
url := fmt.Sprintf("%s/%s", urlBase, hash)
headReq, err := http.NewRequest(http.MethodHead, url, nil)

View File

@@ -6,8 +6,6 @@
package main
import (
"github.com/syncthing/syncthing/lib/logger"
)
import "github.com/syncthing/syncthing/internal/slogutil"
var l = logger.DefaultLogger.NewFacility("main", "Main package")
func init() { slogutil.RegisterPackage("Main package") }

View File

@@ -238,7 +238,7 @@ func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo,
}
// Verify the hash against the plaintext block info
if !scanner.Validate(dec, plainBlock.Hash, 0) {
if !scanner.Validate(dec, plainBlock.Hash) {
// The block decrypted correctly but fails the hash check. This
// is odd and unexpected, but it it's still a valid block from
// the source. The file might have changed while we pulled it?

View File

@@ -11,42 +11,25 @@ import (
"bufio"
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"os"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/syncthing"
)
type CLI struct {
cmdutil.CommonOptions
GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
NoPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup" env:"STNOPORTPROBING"`
}
func (c *CLI) Run(l logger.Logger) error {
if c.HideConsole {
osutil.HideConsole()
}
if c.HomeDir != "" {
if c.ConfDir != "" {
return errors.New("--home must not be used together with --config")
}
c.ConfDir = c.HomeDir
}
if c.ConfDir == "" {
c.ConfDir = locations.GetBaseDir(locations.ConfigBaseDir)
}
func (c *CLI) Run() error {
// Support reading the password from a pipe or similar
if c.GUIPassword == "-" {
reader := bufio.NewReader(os.Stdin)
@@ -57,13 +40,13 @@ func (c *CLI) Run(l logger.Logger) error {
c.GUIPassword = string(password)
}
if err := Generate(l, c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder, c.SkipPortProbing); err != nil {
if err := Generate(locations.GetBaseDir(locations.ConfigBaseDir), c.GUIUser, c.GUIPassword, c.NoPortProbing); err != nil {
return fmt.Errorf("failed to generate config and keys: %w", err)
}
return nil
}
func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFolder, skipPortProbing bool) error {
func Generate(confDir, guiUser, guiPassword string, skipPortProbing bool) error {
dir, err := fs.ExpandTilde(confDir)
if err != nil {
return err
@@ -78,20 +61,21 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFo
certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
slog.Warn("Key exists; will not overwrite")
} else {
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
if err != nil {
return fmt.Errorf("create certificate: %w", err)
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
slog.Info("Calculated device ID", slog.String("device", myID.String()))
cfgFile := locations.Get(locations.ConfigFile)
cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger)
if fs.IsNotExist(err) {
if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder, skipPortProbing); err != nil {
if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, skipPortProbing); err != nil {
return fmt.Errorf("create config: %w", err)
}
} else if err != nil {
@@ -104,7 +88,7 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFo
var updateErr error
waiter, err := cfg.Modify(func(cfg *config.Configuration) {
updateErr = updateGUIAuthentication(l, &cfg.GUI, guiUser, guiPassword)
updateErr = updateGUIAuthentication(&cfg.GUI, guiUser, guiPassword)
})
if err != nil {
return fmt.Errorf("modify config: %w", err)
@@ -120,17 +104,17 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFo
return nil
}
func updateGUIAuthentication(l logger.Logger, guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
func updateGUIAuthentication(guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
if guiUser != "" && guiCfg.User != guiUser {
guiCfg.User = guiUser
l.Infoln("Updated GUI authentication user name:", guiUser)
slog.Info("Updated GUI authentication user", "name", guiUser)
}
if guiPassword != "" && guiCfg.Password != guiPassword {
if err := guiCfg.SetPassword(guiPassword); err != nil {
return fmt.Errorf("failed to set GUI authentication password: %w", err)
}
l.Infoln("Updated GUI authentication password.")
slog.Info("Updated GUI authentication password")
}
return nil
}

View File

@@ -8,18 +8,21 @@ package main
import (
"fmt"
"log/slog"
"os"
"runtime"
"runtime/pprof"
"syscall"
"time"
"github.com/syncthing/syncthing/internal/slogutil"
)
func startHeapProfiler() {
l.Debugln("Starting heap profiling")
slog.Debug("Starting heap profiling")
go func() {
err := saveHeapProfiles(1) // Only returns on error
l.Warnln("Heap profiler failed:", err)
slog.Error("Heap profiler failed", slogutil.Error(err))
panic("Heap profiler failed")
}()
}

View File

@@ -7,8 +7,8 @@
//go:build !windows
// +build !windows
package cmdutil
package main
type buildCommonOptions struct {
type buildSpecificOptions struct {
HideConsole bool `hidden:""`
}

View File

@@ -4,8 +4,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package cmdutil
package main
type buildCommonOptions struct {
HideConsole bool `name:"no-console" help:"Hide console window"`
type buildSpecificOptions struct {
HideConsole bool `name:"no-console" help:"Hide console window" env:"STHIDECONSOLE"`
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -11,26 +11,28 @@ import (
"context"
"fmt"
"io"
"log/slog"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/svcutil"
"github.com/syncthing/syncthing/lib/sync"
)
var (
stdoutFirstLines []string // The first 10 lines of stdout
stdoutLastLines []string // The last 50 lines of stdout
stdoutMut = sync.NewMutex()
stdoutMut sync.Mutex
)
const (
@@ -43,9 +45,7 @@ const (
panicUploadNoticeWait = 10 * time.Second
)
func monitorMain(options serveOptions) {
l.SetPrefix("[monitor] ")
func (c *serveCmd) monitorMain() {
var dst io.Writer = os.Stdout
logFile := locations.Get(locations.LogFile)
@@ -58,13 +58,13 @@ func monitorMain(options serveOptions) {
open := func(name string) (io.WriteCloser, error) {
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime)
}
if options.LogMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(options.LogMaxSize), options.LogMaxFiles)
if c.LogMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(c.LogMaxSize), c.LogMaxFiles)
} else {
fileDst, err = open(logFile)
}
if err != nil {
l.Warnln("Failed to setup logging to file, proceeding with logging to stdout only:", err)
slog.Error("Failed to set up logging to file, proceeding with logging to stdout only", slogutil.Error(err))
} else {
if build.IsWindows {
// Translate line breaks to Windows standard
@@ -78,14 +78,14 @@ func monitorMain(options serveOptions) {
// Log to both stdout and file.
dst = io.MultiWriter(dst, fileDst)
l.Infof(`Log output saved to file "%s"`, logFile)
slog.Info("Saved log output", slogutil.FilePath(logFile))
}
}
args := os.Args
binary, err := getBinary(args[0])
if err != nil {
l.Warnln("Error starting the main Syncthing process:", err)
slog.Error("Failed to start the main Syncthing process", slogutil.Error(err))
panic("Error starting the main Syncthing process")
}
var restarts [restartCounts]time.Time
@@ -102,7 +102,7 @@ func monitorMain(options serveOptions) {
maybeReportPanics()
if t := time.Since(restarts[0]); t < restartLoopThreshold {
l.Warnf("%d restarts in %v; not retrying further", restartCounts, t)
slog.Error("Too many restarts; not retrying further", slog.Int("count", restartCounts), slog.Any("interval", t))
os.Exit(svcutil.ExitError.AsInt())
}
@@ -122,10 +122,10 @@ func monitorMain(options serveOptions) {
panic(err)
}
l.Debugln("Starting syncthing")
slog.Debug("Starting syncthing")
err = cmd.Start()
if err != nil {
l.Warnln("Error starting the main Syncthing process:", err)
slog.Error("Failed to start the main Syncthing process", slogutil.Error(err))
panic("Error starting the main Syncthing process")
}
@@ -134,7 +134,7 @@ func monitorMain(options serveOptions) {
stdoutLastLines = make([]string, 0, 50)
stdoutMut.Unlock()
wg := sync.NewWaitGroup()
var wg sync.WaitGroup
wg.Add(1)
go func() {
@@ -158,13 +158,13 @@ func monitorMain(options serveOptions) {
stopped := false
select {
case s := <-stopSign:
l.Infof("Signal %d received; exiting", s)
slog.Info("Received signal; exiting", "signal", s)
cmd.Process.Signal(sigTerm)
err = <-exit
stopped = true
case s := <-restartSign:
l.Infof("Signal %d received; restarting", s)
slog.Info("Received signal; restarting", "signal", s)
cmd.Process.Signal(sigHup)
err = <-exit
@@ -178,25 +178,25 @@ func monitorMain(options serveOptions) {
if exiterr, ok := err.(*exec.ExitError); ok {
exitCode := exiterr.ExitCode()
if stopped || options.NoRestart {
if stopped || c.NoRestart {
os.Exit(exitCode)
}
if exitCode == svcutil.ExitUpgrade.AsInt() {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
slog.Info("Restarting monitor...")
if err = restartMonitor(binary, args); err != nil {
l.Warnln("Restart:", err)
slog.Error("Failed to restart monitor", slogutil.Error(err))
}
os.Exit(exitCode)
}
}
if options.NoRestart {
if c.NoRestart {
os.Exit(svcutil.ExitError.AsInt())
}
l.Infoln("Syncthing exited:", err)
slog.Info("Syncthing exited", slogutil.Error(err))
time.Sleep(restartPause)
if first {
@@ -238,47 +238,29 @@ func copyStderr(stderr io.Reader, dst io.Writer) {
return
}
if panicFd == nil {
dst.Write([]byte(line))
dst.Write([]byte(line))
if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
panicFd, err = os.Create(locations.GetTimestamped(locations.PanicLog))
if err != nil {
l.Warnln("Create panic log:", err)
continue
}
l.Warnf("Panic detected, writing to \"%s\"", panicFd.Name())
if strings.Contains(line, "leveldb") && strings.Contains(line, "corrupt") {
l.Warnln(`
*********************************************************************************
* Crash due to corrupt database. *
* *
* This crash usually occurs due to one of the following reasons: *
* - Syncthing being stopped abruptly (killed/loss of power) *
* - Bad hardware (memory/disk issues) *
* - Software that affects disk writes (SSD caching software and similar) *
* *
* Please see the following URL for instructions on how to recover: *
* https://docs.syncthing.net/users/faq.html#my-syncthing-database-is-corrupt *
*********************************************************************************
`)
} else {
l.Warnln("Please check for existing issues with similar panic message at https://github.com/syncthing/syncthing/issues/")
l.Warnln("If no issue with similar panic message exists, please create a new issue with the panic log attached")
}
stdoutMut.Lock()
for _, line := range stdoutFirstLines {
panicFd.WriteString(line)
}
panicFd.WriteString("...\n")
for _, line := range stdoutLastLines {
panicFd.WriteString(line)
}
stdoutMut.Unlock()
if panicFd == nil && (strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:")) {
panicFd, err = os.Create(locations.GetTimestamped(locations.PanicLog))
if err != nil {
slog.Error("Failed to create panic log", slogutil.Error(err))
continue
}
slog.Error("Panic detected, writing to file", slogutil.FilePath(panicFd.Name()))
slog.Info("Please check for existing issues with similar panic message at https://github.com/syncthing/syncthing/issues/")
slog.Info("If no issue with similar panic message exists, please create a new issue with the panic log attached")
stdoutMut.Lock()
for _, line := range stdoutFirstLines {
panicFd.WriteString(line)
}
panicFd.WriteString("...\n")
for _, line := range stdoutLastLines {
panicFd.WriteString(line)
}
stdoutMut.Unlock()
panicFd.WriteString("Panic at " + time.Now().Format(time.RFC3339) + "\n")
}
@@ -448,7 +430,6 @@ func newAutoclosedFile(name string, closeDelay, maxOpenTime time.Duration) (*aut
name: name,
closeDelay: closeDelay,
maxOpenTime: maxOpenTime,
mut: sync.NewMutex(),
closed: make(chan struct{}),
closeTimer: time.NewTimer(time.Minute),
}
@@ -556,7 +537,7 @@ func maybeReportPanics() {
// Try to get a config to see if/where panics should be reported.
cfg, err := loadOrDefaultConfig()
if err != nil {
l.Warnln("Couldn't load config; not reporting crash")
slog.Error("Couldn't load config; not reporting crash")
return
}
@@ -576,7 +557,7 @@ func maybeReportPanics() {
case <-ctx.Done():
return
case <-time.After(panicUploadNoticeWait):
l.Warnln("Uploading crash reports is taking a while, please wait...")
slog.Warn("Uploading crash reports is taking a while, please wait")
}
}()

View File

@@ -16,7 +16,9 @@ import (
"syscall"
"time"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
"golang.org/x/exp/constraints"
)
func startPerfStats() {
@@ -29,37 +31,68 @@ func savePerfStats(file string) {
panic(err)
}
var prevUsage int64
var prevTime int64
var rusage syscall.Rusage
var memstats runtime.MemStats
var prevTime time.Time
var curRus, prevRus syscall.Rusage
var curMem, prevMem runtime.MemStats
var prevIn, prevOut int64
t0 := time.Now()
syscall.Getrusage(syscall.RUSAGE_SELF, &prevRus)
runtime.ReadMemStats(&prevMem)
fmt.Fprintf(fd, "TIME_S\tCPU_S\tHEAP_KIB\tRSS_KIB\tNETIN_KBPS\tNETOUT_KBPS\tDBSIZE_KIB\n")
for t := range time.NewTicker(250 * time.Millisecond).C {
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil {
continue
}
curTime := time.Now().UnixNano()
timeDiff := curTime - prevTime
curUsage := rusage.Utime.Nano() + rusage.Stime.Nano()
usageDiff := curUsage - prevUsage
cpuUsagePercent := 100 * float64(usageDiff) / float64(timeDiff)
prevTime = curTime
prevUsage = curUsage
syscall.Getrusage(syscall.RUSAGE_SELF, &curRus)
runtime.ReadMemStats(&curMem)
in, out := protocol.TotalInOut()
var inRate, outRate float64
if timeDiff > 0 {
inRate = float64(in-prevIn) / (float64(timeDiff) / 1e9) // bytes per second
outRate = float64(out-prevOut) / (float64(timeDiff) / 1e9) // bytes per second
}
timeDiff := t.Sub(prevTime)
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,
rate(prevIn, in, timeDiff, 1e3),
rate(prevOut, out, timeDiff, 1e3),
dirsize(locations.Get(locations.Database))/1024,
)
prevTime = t
prevRus = curRus
prevMem = curMem
prevIn, prevOut = in, out
runtime.ReadMemStats(&memstats)
startms := int(t.Sub(t0).Seconds() * 1000)
fmt.Fprintf(fd, "%d\t%f\t%d\t%d\t%.0f\t%.0f\n", startms, cpuUsagePercent, memstats.Alloc, memstats.Sys-memstats.HeapReleased, inRate, outRate)
}
}
func cpusec(r *syscall.Rusage) float64 {
return float64(r.Utime.Nano()+r.Stime.Nano()) / float64(time.Second)
}
type number interface {
constraints.Float | constraints.Integer
}
func rate[T number](prev, cur T, d time.Duration, div float64) float64 {
diff := cur - prev
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

@@ -32,3 +32,10 @@
darwin: "20"
linux: "3.2"
windows: "10.0"
- runtime: go1.25
requirements:
# macOS 12 (Monterey) per https://tip.golang.org/doc/go1.25#darwin
darwin: "21"
linux: "3.2"
windows: "10.0"

View File

@@ -2,7 +2,7 @@
Name=Start Syncthing
GenericName=File synchronization
Comment=Starts the main syncthing process in the background.
Exec=/usr/bin/syncthing serve --no-browser --logfile=default
Exec=syncthing serve --no-browser --logfile=default
Icon=syncthing
Terminal=false
Type=Application

View File

@@ -2,7 +2,7 @@
Name=Syncthing Web UI
GenericName=File synchronization UI
Comment=Opens Syncthing's Web UI in the default browser (Syncthing must already be started).
Exec=/usr/bin/syncthing --browser-only
Exec=syncthing --browser-only
Icon=syncthing
Terminal=false
Type=Application

View File

@@ -7,7 +7,7 @@ StartLimitBurst=4
[Service]
User=%i
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4

View File

@@ -18,4 +18,4 @@ env STNORESTART=yes
respawn
# the syncthing command Upstart is to execute when it is started up
exec $SYNCTHING_EXE -no-browser
exec $SYNCTHING_EXE --no-browser

79
go.mod
View File

@@ -1,55 +1,63 @@
module github.com/syncthing/syncthing
go 1.22.0
go 1.23.0
require (
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f
github.com/alecthomas/kong v1.6.0
github.com/aws/aws-sdk-go v1.55.5
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1
github.com/alecthomas/kong v1.11.0
github.com/aws/aws-sdk-go v1.55.7
github.com/calmh/incontainer v1.0.0
github.com/calmh/xdr v1.2.0
github.com/ccding/go-stun v0.1.5
github.com/chmduquesne/rollinghash v4.0.0+incompatible
github.com/coreos/go-semver v0.3.1
github.com/d4l3k/messagediff v1.2.1
github.com/getsentry/raven-go v0.2.0
github.com/go-ldap/ldap/v3 v3.4.10
github.com/go-ldap/ldap/v3 v3.4.11
github.com/gobwas/glob v0.2.3
github.com/greatroar/blobloom v0.8.0
github.com/gofrs/flock v0.12.1
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/jackpal/gateway v1.0.16
github.com/jackpal/go-nat-pmp v1.0.2
github.com/jmoiron/sqlx v1.4.0
github.com/julienschmidt/httprouter v1.3.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/maruel/panicparse/v2 v2.4.0
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1
github.com/maruel/panicparse/v2 v2.5.0
github.com/mattn/go-sqlite3 v1.14.28
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2
github.com/maxmind/geoipupdate/v6 v6.1.0
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
github.com/oschwald/geoip2-golang v1.11.0
github.com/pierrec/lz4/v4 v4.1.22
github.com/prometheus/client_golang v1.20.5
github.com/puzpuzpuz/xsync/v3 v3.4.0
github.com/quic-go/quic-go v0.48.2
github.com/prometheus/client_golang v1.22.0
github.com/puzpuzpuz/xsync/v3 v3.5.1
github.com/quic-go/quic-go v0.52.0
github.com/rabbitmq/amqp091-go v1.10.0
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/shirou/gopsutil/v4 v4.24.12
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9
github.com/shirou/gopsutil/v4 v4.25.4
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
github.com/thejerf/suture/v4 v4.0.6
github.com/urfave/cli v1.22.16
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
github.com/willabides/kongplete v0.4.0
github.com/wlynxg/anet v0.0.5
go.uber.org/automaxprocs v1.6.0
golang.org/x/crypto v0.31.0
golang.org/x/net v0.33.0
golang.org/x/sys v0.28.0
golang.org/x/text v0.21.0
golang.org/x/time v0.8.0
golang.org/x/tools v0.28.0
google.golang.org/protobuf v1.36.1
golang.org/x/crypto v0.38.0
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/net v0.40.0
golang.org/x/sys v0.33.0
golang.org/x/text v0.25.0
golang.org/x/time v0.11.0
golang.org/x/tools v0.33.0
google.golang.org/protobuf v1.36.6
modernc.org/sqlite v1.37.0
sigs.k8s.io/yaml v1.4.0
)
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -57,31 +65,33 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.60.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
@@ -89,12 +99,17 @@ require (
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
go.uber.org/mock v0.5.2 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sync v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.62.1 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.9.1 // indirect
)
// https://github.com/gobwas/glob/pull/55
replace github.com/gobwas/glob v0.2.3 => github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b
// https://github.com/mattn/go-sqlite3/pull/1338
replace github.com/mattn/go-sqlite3 v1.14.28 => github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8

242
go.sum
View File

@@ -1,22 +1,38 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f h1:GmH5lT+moM7PbAJFBq57nH9WJ+wRnBXr/tyaYWbSAx8=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 h1:LR0kAX9ykz8G4YgLCaRDVJ3+n43R8MneB5dTy2konZo=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v1.6.0 h1:mwOzbdMR7uv2vul9J0FU3GYxE7ls/iX1ieMg5WIM6gE=
github.com/alecthomas/kong v1.6.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/kong v1.11.0 h1:y++1gI7jf8O7G7l4LZo5ASFhrhJvzc+WgF/arranEmM=
github.com/alecthomas/kong v1.11.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b h1:Fjm4GuJ+TGMgqfGHN42IQArJb77CfD/mAwLbDUoJe6g=
github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b/go.mod h1:91K7jfEsgJSyfSrX+gmrRfZMtntx6JsHolWubGXDopg=
github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8 h1:oNVrBJGXkD334ToEmxJz8G6LhzD1/sMA4twMHsMLzQo=
github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/calmh/incontainer v1.0.0 h1:g2cTUtZuFGmMGX8GoykPkN1Judj2uw8/3/aEtq4Z/rg=
github.com/calmh/incontainer v1.0.0/go.mod h1:eOhqnw15c9X+4RNBe0W3HlUZFfX16O0EDsCOInTndHY=
github.com/calmh/xdr v1.2.0 h1:GaGSNH4ZDw9kNdYqle6+RcAENiaQ8/611Ok+jQbBEeU=
@@ -29,11 +45,11 @@ github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chmduquesne/rollinghash v4.0.0+incompatible h1:hnREQO+DXjqIw3rUTzWN7/+Dpw+N5Um8zpKV0JOEgbo=
github.com/chmduquesne/rollinghash v4.0.0+incompatible/go.mod h1:Uc2I36RRfTAf7Dge82bi3RU0OQUmXT9iweIcPqvr8A0=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
@@ -41,8 +57,10 @@ github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkE
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
@@ -51,20 +69,24 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU=
github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -81,24 +103,20 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA=
github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/greatroar/blobloom v0.8.0 h1:I9RlEkfqK9/6f1v9mFmDYegDQ/x0mISCpiNpAm23Pt4=
github.com/greatroar/blobloom v0.8.0/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv8OvMHJxHKs=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -127,30 +145,39 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/maruel/panicparse/v2 v2.4.0 h1:yQKMIbQ0DKfinzVkTkcUzQyQ60UCiNnYfR7PWwTs2VI=
github.com/maruel/panicparse/v2 v2.4.0/go.mod h1:nOY2OKe8csO3F3SA5+hsxot05JLgukrF54B9x88fVp4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 h1:NicmruxkeqHjDv03SfSxqmaLuisddudfP3h5wdXFbhM=
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1/go.mod h1:eyp4DdUJAKkr9tvxR3jWhw2mDK7CWABMG5r9uyaKC7I=
github.com/maruel/panicparse/v2 v2.5.0 h1:yCtuS0FWjfd0RTYMXGpDvWcb0kINm8xJGu18/xMUh00=
github.com/maruel/panicparse/v2 v2.5.0/go.mod h1:DA2fDiBk63bKfBf4CVZP9gb4fuvzdPbLDsSI873hweQ=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU=
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ=
github.com/maxmind/geoipupdate/v6 v6.1.0 h1:sdtTHzzQNJlXF5+fd/EoPTucRHyMonYt/Cok8xzzfqA=
github.com/maxmind/geoipupdate/v6 v6.1.0/go.mod h1:cZYCDzfMzTY4v6dKRdV7KTB6SStxtn3yFkiJ1btTGGc=
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75 h1:cUVxyR+UfmdEAZGJ8IiKld1O0dbGotEnkMolG5hfMSY=
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75/go.mod h1:pBbZyGwC5i16IBkjVKoy/sznA8jPD/K9iedwe1ESE6w=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
@@ -161,20 +188,22 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -186,32 +215,34 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab h1:ZjX6I48eZSFetPb41dHudEyVr5v953N15TsNZXlkcWY=
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab/go.mod h1:/PfPXh0EntGc3QAAyUaviy4S9tzy4Zp0e2ilq4voC6E=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw=
github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -222,13 +253,12 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2 h1:F4snRP//nIuTTW9LYEzVH4HVwDG9T3M4t8y/2nqMbiY=
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 h1:yhxdTGmFkAM2TFA65c3NgGwpnIkUM8oVqPX2e9S7IVg=
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y=
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8=
@@ -244,65 +274,42 @@ github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gN
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
github.com/willabides/kongplete v0.4.0 h1:eivXxkp5ud5+4+NVN9e4goxC5mSh3n1RHov+gsblM2g=
github.com/willabides/kongplete v0.4.0/go.mod h1:0P0jtWD9aTsqPSUAl4de35DLghrr57XcayPyvqSi2X8=
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -322,47 +329,26 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -376,8 +362,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -393,5 +379,29 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -2,7 +2,7 @@
"A device with that ID is already added.": "أضيف هذا الجهاز بالفعل.",
"A negative number of days doesn't make sense.": "لا يمكن استخدام قيمة سالبة لعدد الأيام.",
"A new major version may not be compatible with previous versions.": "الإصدار الجديد قد لا يتوافق مع الإصدارات السابقة.",
"API Key": "مفتاح API",
"API Key": "مفتاح واجهة برمجة التطبيقات \"API\"",
"About": "حول",
"Action": "إجراء",
"Actions": "الإجراءات",
@@ -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?": "هل تريد الانتقال الى التصميم الجديد لتقرير الاستخدام المجهول ؟",
@@ -52,6 +53,7 @@
"Body:": "جسم:",
"Bugs": "أخطاء برمجية",
"Cancel": "إلغاء",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "لا يمكن تفعيله عندما يكون نوع المجلد هو \"{{foldertype}}\".",
"Changelog": "سجل التغيير",
"Clean out after": "نظف بعد",
"Cleaning Versions": "إصدارات نظيفة",
@@ -154,7 +156,7 @@
"Failed Items": "العناصر الفاشلة",
"Failed to load file versions.": "لم يُتَوَصَّل لنسخة الملف.",
"Failed to load ignore patterns.": "فشل التَّوَصُّل إلى مُرَشِّحات التجاهل.",
"Failed to setup, retrying": "فشل الإعداد، تجري المحاولة مرة أخرى",
"Failed to set up, retrying": "فشل الإعداد، تجري المحاولة مرة أخرى",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "يُتوقع فشل الاتصال بخوادم IPv6، إذا لم يكن IPv6 متاحا.",
"File Pull Order": "ترتيب استيراد الملفات",
"File Versioning": "إصدارات الملف",
@@ -368,7 +370,7 @@
"Show diff with previous version": "أظهر الفرق مقارنةً بالنسخة السابقة",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "يُعرَض بدلا من المُعرِّف ضمن العناقيد. سيُروَّج للأجهزة الأخرى على أنه اسم أساسي محتمل.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "يُعرَض بدلا من المُعرِّف ضمن العناقيد. إذا تُرك فارغا، سيُحدَّث إلى الاسم المختار من قِبَل الجهاز.",
"Shutdown": "إغلاق",
"Shut Down": "إغلاق",
"Shutdown Complete": "أُغلِق",
"Simple": "بسيط",
"Simple File Versioning": "التقسيم البسيط لإصدارات الملفات",

View File

@@ -152,7 +152,7 @@
"Show ID": "Паказаць ID",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
"Shutdown": "Выключыць",
"Shut Down": "Выключыць",
"Shutdown Complete": "Выключэньне завершанае",
"Simple File Versioning": "Простае захоўваньне вэрсій",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",

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?": "Форматът на данните за анонимно отчитане на употреба е променен. Желаете ли да използвате него вместо стария?",
@@ -52,6 +53,7 @@
"Body:": "Съдържание:",
"Bugs": "Дефекти",
"Cancel": "Отказ",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Не мож да бъде включено, ако вида на папката е „{{foldertype}}“.",
"Changelog": "Дневник на промените",
"Clean out after": "Почистване след",
"Cleaning Versions": "Почистване на версии",
@@ -154,7 +156,7 @@
"Failed Items": "Елементи с грешка",
"Failed to load file versions.": "Грешка при зареждане на версии.",
"Failed to load ignore patterns.": "Грешка при зареждане на шаблони за пренебрегване.",
"Failed to setup, retrying": "Грешка при настройване, извършва се повторен опит",
"Failed to set up, retrying": "Грешка при настройване, извършва се повторен опит",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Неуспешна връзка към сървъри по IPv6 може да се очаква ако няма свързаност по IPv6.",
"File Pull Order": "Ред на изтегляне",
"File Versioning": "Версии на файловете",
@@ -225,6 +227,7 @@
"Learn more": "Научете повече",
"Learn more at {%url%}": "Научете повече на {{url}}",
"Limit": "Ограничение",
"Limit Bandwidth in LAN": "Огранич. на скоростта в местната мрежа",
"Listener Failures": "Грешки при очакване на връзка",
"Listener Status": "Очакване на връзка",
"Listeners": "Очакване на връзка",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Показване на разликите с предходната версия",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "В списъка на устройствата се показва вместо идентификатор. Ще бъде предложено на другите устройства като име по подразбиране.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "В списъка на устройствата се показва вместо идентификатор. Ако бъде оставено празно ще бъде променено на името, което носи устройството.",
"Shutdown": "Изключване",
"Shut Down": "Изключване",
"Shutdown Complete": "Спирането завършено",
"Simple": "Обикновени",
"Simple File Versioning": "Обикновени версии",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Xarxes permeses",
"Alphabetic": "Alfabètic",
"Altered by ignoring deletes.": "S'ha alterat ignorant les supressions.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre activat quan el tipus de carpeta és \"{{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.": "Una ordre externa gestiona la versió. Ha d'eliminar el fitxer de la carpeta compartida. Si el camí a l'aplicació conté espais, s'ha de citar.",
"Anonymous Usage Reporting": "Informe anònim d'ús",
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format de l'informe d'ús anònim ha canviat. Voleu canviar a aquest nou format?",
@@ -52,6 +53,7 @@
"Body:": "Cos de text:",
"Bugs": "Errors (Bugs)",
"Cancel": "Cancel·la",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "No es pot habilitar quan el tipus de carpeta és \"{{foldertype}}\".",
"Changelog": "Historial de canvis",
"Clean out after": "Netejar després",
"Cleaning Versions": "Netejant versions",
@@ -154,7 +156,7 @@
"Failed Items": "Elements fallats",
"Failed to load file versions.": "No s'han pogut carregar les versions dels fitxers.",
"Failed to load ignore patterns.": "No s'han pogut carregar els patrons ignorats.",
"Failed to setup, retrying": "No s'ha pogut configurar, s'està tornant a provar",
"Failed to set up, retrying": "No s'ha pogut configurar, s'està tornant a provar",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "S'espera que no es pugui connectar als servidors IPv6 si no hi ha connectivitat IPv6.",
"File Pull Order": "Ordre d'agafar fitxers",
"File Versioning": "Versionat de Fitxers",
@@ -368,7 +370,7 @@
"Show diff with previous version": "Mostra la diferència amb la versió anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en comptes del ID del Node en l'estat del cluster. Serà advertit als altres dispositius com un nom opcional per defecte.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrat en comptes del ID del Node en l'estat del cluster. S'actualitzarà al nom del dispositiu si es deixa buit.",
"Shutdown": "Apaga",
"Shut Down": "Apaga",
"Shutdown Complete": "Apagat complet",
"Simple": "Simple",
"Simple File Versioning": "Versionat de Fitxers Senzill",

View File

@@ -150,7 +150,7 @@
"Failed Items": "Objectes fallits",
"Failed to load file versions.": "No s'han pogut carregar les versions dels fitxers.",
"Failed to load ignore patterns.": "No s'han pogut carregar els patrons ignorats.",
"Failed to setup, retrying": "Errada en la configuració, reintentant",
"Failed to set up, retrying": "Errada en la configuració, reintentant",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "És possible que es produïsca una fallada al connectar als servidors IPv6 si no hi ha connectivitat IPv6.",
"File Pull Order": "Ordre de fitxers del pull",
"File Versioning": "Versionat de fitxer",
@@ -353,7 +353,7 @@
"Show diff with previous version": "Mostrar les diferències amb la versió prèvia",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'anunciarà als altres dispositius com el nom opcional per defecte.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'actualitzarà al nom que el dispositiu anuncia si es deixa buit.",
"Shutdown": "Apagar",
"Shut Down": "Apagar",
"Shutdown Complete": "Apagar completament",
"Simple": "Senzill",
"Simple File Versioning": "Versionat de fitxers senzill",

View File

@@ -154,7 +154,7 @@
"Failed Items": "Nezdařené položky",
"Failed to load file versions.": "Nepodařilo se nahrát verze souboru.",
"Failed to load ignore patterns.": "Načtení vzorů ignorovaného se nezdařilo.",
"Failed to setup, retrying": "Nastavování se nezdařilo, zkouší se znovu",
"Failed to set up, retrying": "Nastavování se nezdařilo, zkouší se znovu",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Je v pořádku, když se připojení k IPv6 serverům nezdaří, pokud není k dispozici IPv6 konektivita.",
"File Pull Order": "Pořadí stahování souborů",
"File Versioning": "Správa verzí souborů",
@@ -360,7 +360,7 @@
"Show diff with previous version": "Ukázat rozdíl oproti předchozí verzi",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Bude odesíláno ostatním zařízením jako výchozí název zařízení.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Pokud nebude vyplněno, bude nastaveno na název, který zařízení odesílá.",
"Shutdown": "Vypnout",
"Shut Down": "Vypnout",
"Shutdown Complete": "Vypnutí dokončeno",
"Simple": "Jednoduché",
"Simple File Versioning": "Jednoduchá správa verzí souborů",

View File

@@ -154,7 +154,7 @@
"Failed Items": "Mislykkede filer",
"Failed to load file versions.": "Fil versioner kunne ikke indlæses.",
"Failed to load ignore patterns.": "Ignorerings-mønstre kunne ikke indlæses.",
"Failed to setup, retrying": "Opsætning mislykkedes; prøver igen",
"Failed to set up, retrying": "Opsætning mislykkedes; prøver igen",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Fejl i forbindelse med opkobling til IPv6-servere skal forventes, hvis der ikke er IPv6-forbindelse.",
"File Pull Order": "Hentningsrækkefølge for filer",
"File Versioning": "Filversionering",
@@ -368,7 +368,7 @@
"Show diff with previous version": "Vis forskelle fra tidligere version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive sendt til andre enheder som valgfrit standardnavn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive opdateret til det navn, som enheden sender, hvis det ikke er udfyldt.",
"Shutdown": "Luk ned",
"Shut Down": "Luk ned",
"Shutdown Complete": "Nedlukning fuldført",
"Simple": "Enkel",
"Simple File Versioning": "Simpel filversionering",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Erlaubte Netzwerke",
"Alphabetic": "Alphabetisch",
"Altered by ignoring deletes.": "Weicht ab, weil Löschungen ignoriert werden.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Immer eingeschaltet, wenn der Ordnertyp „{{foldertype}}“ ist.",
"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.": "Die Versionierung erfolgt über einen externen Befehl. Er muss die Datei aus dem geteilten Ordner entfernen. Wenn der Pfad zur Anwendung Leerzeichen enthält, sollte er in Anführungszeichen gesetzt werden.",
"Anonymous Usage Reporting": "Anonymer Nutzungsbericht",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Das Format des anonymen Nutzungsberichts hat sich geändert. Möchten Sie auf das neue Format umsteigen?",
@@ -52,6 +53,7 @@
"Body:": "Nachrichtentext:",
"Bugs": "Fehler",
"Cancel": "Abbrechen",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kann nicht aktiviert werden, wenn der Ordnertyp „{{foldertype}}“ ist.",
"Changelog": "Änderungsprotokoll",
"Clean out after": "Löschen nach",
"Cleaning Versions": "Versionen bereinigen",
@@ -154,7 +156,7 @@
"Failed Items": "Fehlgeschlagene Elemente",
"Failed to load file versions.": "Fehler beim Laden der Dateiversionen.",
"Failed to load ignore patterns.": "Fehler beim Laden der Ignoriermuster.",
"Failed to setup, retrying": "Fehler beim Einrichten, erneuter Versuch",
"Failed to set up, retrying": "Fehler beim Einrichten, erneuter Versuch",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Ein Verbindungsfehler zu IPv6-Servern ist zu erwarten, wenn es keine IPv6-Konnektivität gibt.",
"File Pull Order": "Dateiübertragungsreihenfolge",
"File Versioning": "Dateiversionierung",
@@ -225,6 +227,7 @@
"Learn more": "Mehr erfahren",
"Learn more at {%url%}": "Erfahren Sie mehr unter {{url}}",
"Limit": "Limit",
"Limit Bandwidth in LAN": "Bandbreite im LAN begrenzen",
"Listener Failures": "Fehler bei Listener",
"Listener Status": "Status der Listener",
"Listeners": "Zuhörer",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Unterschied zur vorherigen Version anzeigen",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wird anstelle der Gerätekennung im Verbundstatus angezeigt. Wird anderen Geräten als optionaler Standardname bekannt gegeben.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wird anstelle der Gerätekennung im Verbundstatus angezeigt. Wird auf den Namen aktualisiert, den das Gerät anzeigt, wenn er leer bleibt.",
"Shutdown": "Herunterfahren",
"Shut Down": "Herunterfahren",
"Shutdown Complete": "Vollständig heruntergefahren",
"Simple": "Einfach",
"Simple File Versioning": "Einfache Dateiversionierung",

View File

@@ -154,7 +154,7 @@
"Failed Items": "Αρχεία που απέτυχαν",
"Failed to load file versions.": "Η φόρτωση των εκδόσεων αρχείων απέτυχε.",
"Failed to load ignore patterns.": "Αποτυχία φόρτωσης μοτίβων παράβλεψης.",
"Failed to setup, retrying": "Αποτυχία ενεργοποίησης, γίνεται νέα προσπάθεια",
"Failed to set up, retrying": "Αποτυχία ενεργοποίησης, γίνεται νέα προσπάθεια",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Είναι φυσιολογική η αποτυχία σύνδεσης σε εξυπηρετητές IPv6 όταν δεν υπάρχει συνδεσιμότητα IPv6.",
"File Pull Order": "Σειρά με την οποία θα κατεβαίνουν τα αρχεία",
"File Versioning": "Τήρηση εκδόσεων αρχείων",
@@ -368,7 +368,7 @@
"Show diff with previous version": "Εμφάνιση διαφορών με προηγούμενη έκδοση",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Θα φαίνεται αντί για την ταυτότητα της συσκευής στην προβολή της κατάστασης ολόκληρης της συστάδας. Θα γνωστοποιείται σαν το προαιρετικό όνομα της συσκευής.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Θα φαίνεται αντί για την ταυτότητα της συσκευής στην προβολή της κατάστασης ολόκληρης της συστάδας. Θα ενημερώνεται αυτόματα αν αλλάξει το όνομα της συσκευής.",
"Shutdown": "Απενεργοποίηση",
"Shut Down": "Απενεργοποίηση",
"Shutdown Complete": "Πλήρης απενεργοποίηση",
"Simple": "Απλό",
"Simple File Versioning": "Απλή τήρηση εκδόσεων",

View File

@@ -150,7 +150,7 @@
"Failed Items": "Failed Items",
"Failed to load file versions.": "Failed to load file versions.",
"Failed to load ignore patterns.": "Failed to load ignore patterns.",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failed to set up, retrying": "Failed to set up, retrying",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "File Pull Order",
"File Versioning": "File Versioning",
@@ -353,7 +353,7 @@
"Show diff with previous version": "Show diff with previous version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
"Shutdown": "Shutdown",
"Shut Down": "Shut Down",
"Shutdown Complete": "Shutdown Complete",
"Simple": "Simple",
"Simple File Versioning": "Simple File Versioning",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Allowed Networks",
"Alphabetic": "Alphabetic",
"Altered by ignoring deletes.": "Altered by ignoring deletes.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Always turned on when the folder type is \"{{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.": "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 Reporting",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
@@ -52,6 +53,7 @@
"Body:": "Body:",
"Bugs": "Bugs",
"Cancel": "Cancel",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Cannot be enabled when the folder type is \"{{foldertype}}\".",
"Changelog": "Changelog",
"Clean out after": "Clean out after",
"Cleaning Versions": "Cleaning Versions",
@@ -154,7 +156,7 @@
"Failed Items": "Failed Items",
"Failed to load file versions.": "Failed to load file versions.",
"Failed to load ignore patterns.": "Failed to load ignore patterns.",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failed to set up, retrying": "Failed to set up, retrying",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "File Pull Order",
"File Versioning": "File Versioning",
@@ -225,6 +227,7 @@
"Learn more": "Learn more",
"Learn more at {%url%}": "Learn more at {{url}}",
"Limit": "Limit",
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
"Listener Failures": "Listener Failures",
"Listener Status": "Listener Status",
"Listeners": "Listeners",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Show diff with previous version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
"Shutdown": "Shutdown",
"Shut Down": "Shut Down",
"Shutdown Complete": "Shutdown Complete",
"Simple": "Simple",
"Simple File Versioning": "Simple File Versioning",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Allowed Networks",
"Alphabetic": "Alphabetic",
"Altered by ignoring deletes.": "Altered by ignoring deletes.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Always turned on when the folder type is \"{{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.": "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 Reporting",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
@@ -52,6 +53,7 @@
"Body:": "Body:",
"Bugs": "Bugs",
"Cancel": "Cancel",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Cannot be enabled when the folder type is \"{{foldertype}}\".",
"Changelog": "Changelog",
"Clean out after": "Clean out after",
"Cleaning Versions": "Cleaning Versions",
@@ -80,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",
@@ -154,7 +157,7 @@
"Failed Items": "Failed Items",
"Failed to load file versions.": "Failed to load file versions.",
"Failed to load ignore patterns.": "Failed to load ignore patterns.",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failed to set up, retrying": "Failed to set up, retrying",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "File Pull Order",
"File Versioning": "File Versioning",
@@ -208,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 user name or password.",
"Info": "Info",
"Internally used paths:": "Internally used paths:",
"Introduced By": "Introduced By",
"Introducer": "Introducer",
@@ -225,6 +229,7 @@
"Learn more": "Learn more",
"Learn more at {%url%}": "Learn more at {{url}}",
"Limit": "Limit",
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
"Listener Failures": "Listener Failures",
"Listener Status": "Listener Status",
"Listeners": "Listeners",
@@ -368,7 +373,7 @@
"Show diff with previous version": "Show diff with previous version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
"Shutdown": "Shutdown",
"Shut Down": "Shut Down",
"Shutdown Complete": "Shutdown Complete",
"Simple": "Simple",
"Simple File Versioning": "Simple File Versioning",

View File

@@ -106,7 +106,7 @@
"Error": "Eraro",
"External File Versioning": "Ekstera Versionado de Dosiero",
"Failed Items": "Malsukcesaj Eroj",
"Failed to setup, retrying": "Malsukcesis agordi, provante denove",
"Failed to set up, retrying": "Malsukcesis agordi, provante denove",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Malsukceso por konekti al IPv6 serviloj atendante se ekzistas neniu IPv6 konektebleco.",
"File Pull Order": "Ordo por Tiri Dosieron",
"File Versioning": "Versionado de Dosieroj",
@@ -258,7 +258,7 @@
"Show diff with previous version": "Montri diferenco kun antaŭa versio",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Montrita anstataŭ ID de Aparato en la statuso de la grupo. Estos anoncita al aliaj aparatoj kiel laŭvola defaŭlta nomo.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Montri anstataŭ ID de Aparato en la statuso de la grupo. Estos ĝisdatigita al la nomo de la aparato sciigante se ĝi estas lasita malplena.",
"Shutdown": "Sistemfermo",
"Shut Down": "Sistemfermo",
"Shutdown Complete": "Sistemfermo Tuta",
"Simple File Versioning": "Simpla Versionado de Dosieroj",
"Single level wildcard (matches within a directory only)": "Ununivela ĵokero (egalas nur ene de dosierujo)",

View File

@@ -11,7 +11,7 @@
"Add Device": "Agregar el dispositivo",
"Add Folder": "Agregar Carpeta",
"Add Remote Device": "Añadir un dispositivo remoto",
"Add devices from the introducer to our device list, for mutually shared folders.": "Añadir dispositivos desde el introductor a nuestra lista de dispositivos, para las carpetas compartidas mutuamente.",
"Add devices from the introducer to our device list, for mutually shared folders.": "Añadir dispositivos del presentador a nuestra lista de dispositivos para las carpetas compartidas mutuamente.",
"Add filter entry": "Añadir una entrada al filtro",
"Add ignore patterns": "Agregar patrones a ignorar",
"Add new folder?": "¿Agregar una carpeta nueva?",
@@ -29,7 +29,7 @@
"Altered by ignoring deletes.": "Alterado ignorando eliminaciones.",
"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. ¿Desearía usar el nuevo formato?",
"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?",
"Applied to LAN": "Aplicado a la LAN",
"Apply": "Solicitar",
"Are you sure you want to override all remote changes?": "¿Está seguro(a) de que desea sobreescribir todos los cambios remotos?",
@@ -131,7 +131,7 @@
"Edit Device": "Editar Dispositivo",
"Edit Device Defaults": "Editar Valores Predeterminados del Dispositivo",
"Edit Folder": "Editar Carpeta",
"Edit Folder Defaults": "Editar Valores Predeterminados de la Carpeta",
"Edit Folder Defaults": "Editar Valores Predeterminados de las Carpeta",
"Editing {%path%}.": "Editando {{path}}.",
"Enable Crash Reporting": "Activar Informes de Fallos",
"Enable NAT traversal": "Permitir NAT transversal",
@@ -154,7 +154,7 @@
"Failed Items": "Elementos fallidos",
"Failed to load file versions.": "Error al cargar las versiones de los archivos.",
"Failed to load ignore patterns.": "No se pudieron cargar los patrones de ignorar.",
"Failed to setup, retrying": "Fallo en la configuración, reintentando",
"Failed to set up, retrying": "Fallo en la configuración, reintentando",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Se espera un fallo al conectar a los servidores IPv6 si no hay conectividad IPv6.",
"File Pull Order": "Orden de Obtención de los Archivos",
"File Versioning": "Versionado de ficheros",
@@ -269,7 +269,7 @@
"No upgrades": "Sin actualizaciones",
"Not shared": "No Compartido(a)",
"Notice": "Aviso",
"Number of Connections": "Número de las conexiones",
"Number of Connections": "Número de conexiones",
"OK": "De acuerdo",
"Off": "Desactivado",
"Oldest First": "El más antiguo primero",
@@ -368,7 +368,7 @@
"Show diff with previous version": "Mostrar la diferencia con la versión anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Se muestra en lugar del ID del dispositivo en el estado del grupo (cluster). Se notificará a los otros dispositivos como nombre opcional por defecto.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Se muestra en lugar del ID del dispositivo en el estado del grupo (cluster). Se actualizará al nombre que el dispositivo anuncia si se deja vacío.",
"Shutdown": "Apagar",
"Shut Down": "Apagar",
"Shutdown Complete": "Apagar completamente",
"Simple": "Sencillo",
"Simple File Versioning": "Versionado simple de fichero",
@@ -532,7 +532,7 @@
"deleted": "eliminado",
"deny": "denegar",
"directories": "directorios",
"file": "expediente",
"file": "fichero",
"files": "archivos",
"folder": "carpeta",
"full documentation": "Documentación completa",

View File

@@ -1,17 +1,26 @@
{
"A device with that ID is already added.": "Sellise seadme ID'ga seade on juba lisatud.",
"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.",
"API Key": "API Võti",
"API Key": "API võti",
"About": "Rakenduse teave",
"Action": "Tegevus",
"Actions": "Tegevused",
"Add": "Lisa",
"Add Device": "Lisa seade",
"Add Folder": "Lisa kaust",
"Add new folder?": "Lisa uus kaust?",
"Add Remote Device": "Lisa kaugseade",
"Add new folder?": "Kas lisad uue kausta?",
"Address": "Aadress",
"Addresses": "Aadressid",
"All Data": "Kõik andmed",
"All Time": "Kõik ajad",
"Allowed Networks": "Lubatud võrgud",
"Alphabetic": "Tähestikuline",
"Apply": "Rakenda",
"Automatic upgrades": "Automaatsed uuendused",
"Be careful!": "Ettevaatust!",
"Cancel": "Loobu",
"Changelog": "Muudatuste nimekiri",
"Close": "Sulge",
"Configured": "Seadistatud",
"Connection Error": "Ühenduse viga",
@@ -41,7 +50,7 @@
"Folder Label": "Kausta Silt",
"Folder Type": "Kausta Tüüp",
"Folders": "Kaustad",
"GUI": "GUI",
"GUI": "Kasutajaliides",
"GUI Authentication Password": "GUI Autentimise Salasõna",
"GUI Authentication User": "GUI Autentimise Kasutajatunnus",
"GUI Theme": "GUI Teema",
@@ -69,7 +78,7 @@
"New Folder": "Uus Kaust",
"Newest First": "Uusimad Ennem",
"No": "Ei",
"OK": "OK",
"OK": "Sobib",
"Oldest First": "Vanimad Ennem",
"Options": "Valikud",
"Outgoing Rate Limit (KiB/s)": "Väljuva Kiiruse Piirang (KiB/s)",
@@ -110,7 +119,7 @@
"The device ID cannot be blank.": "Seadme ID ei tohi olla tühi.",
"The folder ID cannot be blank.": "Kausta ID ei tohi olla tühi.",
"The folder ID must be unique.": "Kausta ID peab olema unikaalne.",
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi!",
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi.",
"The following items could not be synchronized.": "Järgnevaid üksusi ei õnnestunud sünkroniseerida.",
"The maximum age must be a number and cannot be blank.": "Maksimaalne vanus peab olema arv ning ei tohi olla tühi.",
"Unknown": "Teadmata",

View File

@@ -130,7 +130,7 @@
"External File Versioning": "Fitxategi bertsioen kanpoko kudeaketa",
"Failed Items": "Huts egin duten fitxategiak",
"Failed to load ignore patterns.": "Huts egin du baztertze ereduak kargatzean.",
"Failed to setup, retrying": "Konfigurazioan huts egitea, berriro saiatuz",
"Failed to set up, retrying": "Konfigurazioan huts egitea, berriro saiatuz",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "IPv6 zerbitzariei buruzko konexioak huts eginen du, IPv6 konektibitaterik ez bada",
"File Pull Order": "Fitxategiak berreskuratzeko ordena",
"File Versioning": "Fitxategiak zaintzeko metodoa",
@@ -309,7 +309,7 @@
"Show diff with previous version": "Erakutsi aurreko bertsioarekiko aldeak",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Tresnaren ID-aren ordez erakutsia, taldearen egoeran. Beste tresneri erakutsia izanen da, izen erabilgarri bat bezala",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Tresnaren ID-aren ordez erakutsia, taldearen egoeran. Hutsa utzia balin bada, urrun den tresnak proposatu izenarekin aktualizatua izanen da",
"Shutdown": "Geldi",
"Shut Down": "Geldi",
"Shutdown Complete": "Gelditua!",
"Simple File Versioning": "Bertsioen segitze sinplifikatua",
"Single level wildcard (matches within a directory only)": "Hein bakar bateko jokerra (karpetaren barnean bakarrik dagokiona)",

View File

@@ -122,7 +122,7 @@
"External": "Ulkoinen",
"External File Versioning": "Ulkoinen tiedostoversionti",
"Failed Items": "Epäonnistuneet kohteet",
"Failed to setup, retrying": "Käyttöönotto epäonnistui, Yritetään uudelleen",
"Failed to set up, retrying": "Käyttöönotto epäonnistui, Yritetään uudelleen",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Yhteys IPv6-palvelimiin todennäköisesti epäonnistuu, koska IPv6-yhteyksiä ei ole.",
"File Pull Order": "Tiedostojen noutojärjestys",
"File Versioning": "Tiedostoversiointi",
@@ -288,7 +288,7 @@
"Show diff with previous version": "Näytä muutokset edelliseen versioon",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Näytetään ryhmän tiedoissa laitteen ID:n sijaan. Ilmoitetaan muille laitteille vaihtoehtoisena oletusnimenä.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Näytetään ryhmän tiedoissa laitteen ID:n sijaan. Tyhjä nimi päivitetään laitteen ilmoittamaksi nimeksi.",
"Shutdown": "Sammuta",
"Shut Down": "Sammuta",
"Shutdown Complete": "Sammutus valmis",
"Simple File Versioning": "Yksinkertainen tiedostoversiointi",
"Single level wildcard (matches within a directory only)": "Yksitasoinen jokerimerkki (vaikuttaa vain kyseisen kansion sisällä)",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Mga Pinapayagang Network",
"Alphabetic": "Alpabetiko",
"Altered by ignoring deletes.": "Binago sa pamamagitan ng hindi pagpansin sa mga pagtanggal.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Palaging nakabukas kung ang uri ng folder ay nakatakda bilang \"{{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.": "Pinapamahala ng external na command ang file versioning. Kailangan nitong tanggalin ang file mula sa binabahaging folder. Kung may mga space ang path sa application, kailangan itong i-quote.",
"Anonymous Usage Reporting": "Anonymous na Pag-uulat ng Paggamit",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Nagbago ang pormat ng anonymous na ulat ng paggamit. Gusto mo bang lumipat sa bagong pormat?",
@@ -52,6 +53,7 @@
"Body:": "Body:",
"Bugs": "Mga Bug",
"Cancel": "Kanselahin",
"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",
@@ -154,7 +156,7 @@
"Failed Items": "Mga Nabigong Item",
"Failed to load file versions.": "Nabigong i-load ang mga bersyon ng file.",
"Failed to load ignore patterns.": "Nabigong i-load ang mga ignore pattern.",
"Failed to setup, retrying": "Nabigong i-set up, sinusubukan muli",
"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",
@@ -311,7 +313,7 @@
"Receive Encrypted": "Makatanggap Naka-Encrypt",
"Receive Only": "Makatanggap Lamang",
"Received data is already encrypted": "Naka-encrypt na ang natanggap na data",
"Recent Changes": "Mga Kamakilang Pagbabago",
"Recent Changes": "Mga Kamakailang Pagbabago",
"Reduced by ignore patterns": "Binabawasan ng mga ignore pattern",
"Relay LAN": "Relay na LAN",
"Relay WAN": "Relay na WAN",
@@ -368,7 +370,7 @@
"Show diff with previous version": "Ipakita ang diff sa nakaraang bersyon",
"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.",
"Shutdown": "I-shutdown",
"Shut Down": "I-shutdown",
"Shutdown Complete": "Tapos na ang Shutdown",
"Simple": "Simple",
"Simple File Versioning": "Simpleng File Versioning",
@@ -403,7 +405,7 @@
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Ang Syncthing ay Libre at Open Source na Software na nakalisensya sa MPL v2.0.",
"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Ang Syncthing ay isang continuous na file synchronization na program. Sini-synchronize nito ang mga file sa pagitan ng dalawa o higit pang mga computer sa totoong oras, ligtas na protektado mula sa prying na mata. Ang iyong data ay iyong data at nararapat kang pumili kung saan sila ilalagay, kung binabahagi ito sa third party, at kung paano ito pinapadala sa Internet.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Nakikinig ang Syncthing sa mga sumusunod na network address para sa mga tangka sa koneksyon mula sa ibang device:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Hindi nakikinig ang Syncthing sa mga tangka sa koneksyon mula sa ibang mga device sa anumang address. Ang mga palabas na koneksyon lamang ay maaring gumana.",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Hindi nakikinig ang Syncthing sa mga tangka sa koneksyon mula sa ibang mga device sa anumang address. Ang mga palabas na koneksyon lamang ay maaaring gumana.",
"Syncthing is restarting.": "Nagre-restart ang Syncthing.",
"Syncthing is saving changes.": "Nagse-save ng mga pagbabago ang Syncthing.",
"Syncthing is upgrading.": "Naga-upgrade ang Syncthing.",
@@ -417,17 +419,17 @@
"The Syncthing Authors": "Ang Mga Awtor ng Syncthing",
"The Syncthing admin interface is configured to allow remote access without a password.": "Naka-configure ang Syncthing admin interface na payagan ang remote access nang walang password.",
"The aggregated statistics are publicly available at the URL below.": "Available nang publiko ang pinagsama-samang istatistika sa URL sa ibaba.",
"The cleanup interval cannot be blank.": "Hindi maaring walang laman ang pagitan ng paglinis.",
"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 maaring walang laman ang Device ID.",
"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 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 maaring walang laman ang folder ID.",
"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 maaring walang laman ang path ng folder.",
"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 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.",
@@ -436,14 +438,14 @@
"The following unexpected items were found.": "Nahanap ang mga sumusunod na hindi inaasahang item.",
"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 maaring walang laman.",
"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 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 maaring walang laman.",
"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 maaring walang laman.",
"The path cannot be blank.": "Hindi maaring walang laman ang path.",
"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 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)",
"The remote device has not accepted sharing this folder.": "Hindi tinanggap ng remote device ang pagbahagi ng folder na ito.",

View File

@@ -160,7 +160,7 @@
"Show QR": "Afficher l'image QR",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Sera diffusé aux autres appareils comme nom convivial optionnel par défaut.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Si laissé vide, il sera renseigné par le nom convivial proposé par l'appareil distant.",
"Shutdown": "Arrêter",
"Shut Down": "Arrêter",
"Shutdown Complete": "Arrêté !",
"Simple File Versioning": "Suivi simplifié des versions",
"Single level wildcard (matches within a directory only)": "Joker à un seul niveau (correspond uniquement à lintérieur du répertoire)",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Réseaux autorisés",
"Alphabetic": "Alphabétique",
"Altered by ignoring deletes.": "Protégé par \"Ignore Delete\".",
"Always turned on when the folder type is \"{%foldertype%}\".": "Toujours activé pour le type de partage \"{{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.": "Une commande externe gère les versions de fichiers. Il lui incombe de supprimer les fichiers du répertoire partagé. Si le chemin contient des espaces, il doit être spécifié entre guillemets.",
"Anonymous Usage Reporting": "Rapport anonyme de statistiques d'utilisation",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Le format du rapport anonyme d'utilisation a changé. Voulez-vous passer au nouveau format ?",
@@ -52,6 +53,7 @@
"Body:": "Corps du message :",
"Bugs": "Bogues",
"Cancel": "Annuler",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Ne peut être activé pour le type de partage \"{{foldertype}}\".",
"Changelog": "Historique des versions",
"Clean out after": "Conserver pendant",
"Cleaning Versions": "Purge des versions",
@@ -154,7 +156,7 @@
"Failed Items": "Éléments en échec",
"Failed to load file versions.": "Échec de chargement des versions de fichiers.",
"Failed to load ignore patterns.": "Échec du chargement des masques d'exclusions.",
"Failed to setup, retrying": "Échec, nouvel essai",
"Failed to set up, retrying": "Échec, nouvel essai",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "La connexion aux serveurs en IPv6 va échouer s'il n'y a pas de connectivité IPv6.",
"File Pull Order": "Ordre de récupération des fichiers",
"File Versioning": "Préservation des fichiers",
@@ -225,6 +227,7 @@
"Learn more": "En savoir plus",
"Learn more at {%url%}": "Si vous souhaitez en savoir plus, c'est ici (en anglais) : {{url}}",
"Limit": "Limite",
"Limit Bandwidth in LAN": "Limiter la bande passante locale (LAN)",
"Listener Failures": "Échecs de l'écouteur",
"Listener Status": "État de l'écouteur",
"Listeners": "Écoute",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Afficher les différences avec la version précédente",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Sera diffusé aux autres appareils comme nom convivial optionnel par défaut.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Nom convivial local affiché à la place de l'ID de l'appareil dans la plupart des écrans. Si laissé vide, c'est le nom convivial local de l'appareil distant qui sera utilisé. (Modifiable ultérieurement).",
"Shutdown": "Arrêter",
"Shut Down": "Arrêter",
"Shutdown Complete": "Arrêt complet",
"Simple": "Suivi simplifié",
"Simple File Versioning": "Suivi simplifié des versions",

View File

@@ -146,7 +146,7 @@
"Error": "Flater",
"External File Versioning": "Ekstern ferzjebehear foar triemen",
"Failed Items": "Mislearre items",
"Failed to setup, retrying": "Ynskeakeljen mislearre, wurd no opnij besocht",
"Failed to set up, retrying": "Ynskeakeljen mislearre, wurd no opnij besocht",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Mislearjen fan it ferbinen mei IPv6-tsjinners wurd ferwachte as der gjin stipe foar IPv6-ferbinings is.",
"File Pull Order": "Triemlûkfolchoarder",
"File Versioning": "Triemferzjebehear",
@@ -312,7 +312,7 @@
"Show diff with previous version": "Ferskil (diff) mei de foarige ferzje sjen litte",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wurd ynstee fan apparaat-ID sjen litten by de bondeltastân. Wurd nei oare apparaten advertearre as in mooglike standertnamme.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wurd yn de bondeltastân sjen litten ynstee fan apparaat-ID. Wannear't leech litten wurd, wurd it fernijt nei de namme die it apparaat útstjoert.",
"Shutdown": "Ofslute",
"Shut Down": "Ofslute",
"Shutdown Complete": "Ofsluten klear",
"Simple File Versioning": "Ienfâldich triemferzjebehear",
"Single level wildcard (matches within a directory only)": "Inkel-nivo jokerteken (wildcard) (fergeliket allinnich binnen in map)",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Líonraí Ceadaithe",
"Alphabetic": "Aibítreach",
"Altered by ignoring deletes.": "Athraithe trí neamhaird a dhéanamh ar scriosadh.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Cuirtear ar siúl i gcónaí é nuair is é \"{{foldertype}}\" an cineál fillteáin.",
"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.": "Láimhseálann ordú seachtrach an leagan. Caithfidh sé an comhad a bhaint den fhillteán comhroinnte. Má tá spásanna sa chosán chuig an bhfeidhmchlár, ba chóir é a lua.",
"Anonymous Usage Reporting": "Tuairisciú Úsáide Gan Ainm",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Tá athrú tagtha ar fhormáid na tuarascála úsáide gan ainm. Ar mhaith leat bogadh go dtí an fhormáid nua?",
@@ -52,6 +53,7 @@
"Body:": "Comhlacht:",
"Bugs": "Fabhtanna",
"Cancel": "Cuir ar ceal",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Ní féidir é a chumasú nuair is é \"{{foldertype}}\" an cineál fillteáin.",
"Changelog": "ChangelogName",
"Clean out after": "Glan amach tar éis",
"Cleaning Versions": "Leaganacha Glantacháin",
@@ -154,7 +156,7 @@
"Failed Items": "Míreanna Teipthe",
"Failed to load file versions.": "Theip ar luchtú leaganacha comhaid.",
"Failed to load ignore patterns.": "Theip ar phatrúin neamhairde a luchtú.",
"Failed to setup, retrying": "Theip ar thus, ag triail arís",
"Failed to set up, retrying": "Theip ar thus, ag triail arís",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Táthar ag súil le mainneachtain ceangal le freastalaithe IPv6 mura bhfuil nascacht IPv6 ann.",
"File Pull Order": "Ordú Tarraingthe Comhad",
"File Versioning": "Leagan Comhaid",
@@ -225,6 +227,7 @@
"Learn more": "Faigh tuilleadh eolais",
"Learn more at {%url%}": "Tuilleadh eolais ag {{url}}",
"Limit": "Teorainn",
"Limit Bandwidth in LAN": "Teorainn a chur ar an bandaleithead i LAN",
"Listener Failures": "Teipeanna an Éisteora",
"Listener Status": "Stádas an éisteora",
"Listeners": "Éisteoirí",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Taispeáin diff leis an leagan roimhe seo",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Taispeántar é in ionad ID gléis i stádas na braisle. Fógrófar é do ghléasanna eile mar ainm réamhshocraithe roghnach.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Taispeántar é in ionad ID gléis i stádas na braisle. Déanfar é a nuashonrú go dtí an t-ainm a fhógraíonn an gléas má fhágtar folamh é.",
"Shutdown": "Múchadh",
"Shut Down": "Múchadh",
"Shutdown Complete": "Múchadh Críochnaithe",
"Simple": "Simplí",
"Simple File Versioning": "Leagan Simplí Comhad",

View File

@@ -6,6 +6,7 @@
"About": "Sobre",
"Action": "Acción",
"Actions": "Accións",
"Active filter rules": "Regras de filtrado activas",
"Add": "Engadir",
"Add Device": "Engadir dispositivo",
"Add Folder": "Engadir cartafol",
@@ -25,6 +26,7 @@
"Allow Anonymous Usage Reporting?": "Permitir o informe de uso anónimo?",
"Allowed Networks": "Redes permitidas",
"Alphabetic": "Alfabética",
"Altered by ignoring deletes.": "Cambiado por ignorar o borrado.",
"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?",
@@ -37,21 +39,26 @@
"Are you sure you want to restore {%count%} files?": "Está seguro de que desexa restaurar {{count}} ficheiros?",
"Are you sure you want to revert all local changes?": "Está seguro de que quere reverter todos os cambios locais?",
"Are you sure you want to upgrade?": "Está seguro de que desexa actualizar?",
"Authentication Required": "Autenticación Necesaria",
"Authors": "Autores",
"Auto Accept": "Aceptar automaticamente",
"Automatic Crash Reporting": "Informe Automático de Erros",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Agora a actualización automática permite escoller entre versións estables e versións candidatas.",
"Automatic upgrades": "Actualizacións automáticas",
"Automatic upgrades are always enabled for candidate releases.": "As actualizacións automáticas sempre están activadas para versións candidatas.",
"Automatically create or share folders that this device advertises at the default path.": "Crear ou compartir automaticamente os cartafoles na ruta predeterminada que este dispositivo anuncia.",
"Available debug logging facilities:": "Ferramentas de depuración dispoñibles:",
"Be careful!": "Teña coidado!",
"Body:": "Corpo:",
"Bugs": "Erros",
"Cancel": "Cancelar",
"Changelog": "Rexistro de cambios",
"Clean out after": "Limpar despois",
"Cleaning Versions": "Limpando Versións",
"Cleanup Interval": "Intervalo de Limpeza",
"Click to see full identification string and QR code.": "Faga clic para ver a cadea de identificación completa e o código QR.",
"Close": "Pechar",
"Command": "Orde",
"Comment, when used at the start of a line": "Comentar, cando se usa ao inicio dunha liña",
"Compression": "Compresión",
"Configuration Directory": "Directorio de Configuración",
@@ -69,13 +76,17 @@
"Copied!": "Copiado!",
"Copy": "Copiar",
"Copy failed! Try to select and copy manually.": "Fallou a copia! Probe a seleccionar e copiar manualmente.",
"Currently Shared With Devices": "Compartido actualmente cos dispositivos",
"Custom Range": "Rango personalizado",
"Danger!": "Perigo!",
"Database Location": "Localización da Base de Datos",
"Debugging Facilities": "Ferramentas de depuración",
"Default": "Predeterminado",
"Default Configuration": "Configuración Predeterminada",
"Default Device": "Dispositivo Predeterminado",
"Default Folder": "Cartafol Predeterminado",
"Default Ignore Patterns": "Patróns de Ignorado Predeterminados",
"Defaults": "Predeterminados",
"Delete": "Eliminar",
"Delete Unexpected Items": "Eliminar os Ítems Inesperados",
"Deleted {%file%}": "Eliminado {{file}}",
@@ -89,10 +100,16 @@
"Device Identification": "Identificación do dispositivo",
"Device Name": "Nome do dispositivo",
"Device Status": "Estado do dispositivo",
"Device is untrusted, enter encryption password": "Sen confianza no dispositivo, escribir contrasinal para cifrar",
"Device rate limits": "Límites do dispositivo",
"Device that last modified the item": "Dispositivo que modificou o elemento por última vez",
"Devices": "Dispositivos",
"Disable Crash Reporting": "Desactivar o Informe de Erros",
"Disabled": "Deshabilitado",
"Disabled periodic scanning and disabled watching for changes": "Desactivaronse o escaneo periódico e o control de cambios",
"Disabled periodic scanning and enabled watching for changes": "Desactivouse o escaneo periódico e activouse o control de cambios",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Desactivouse o escaneo periódico e fallou establecer a vixilancia de cambios, reintento cada minuto:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Desactiva a comparación e sincronización dos permisos dos ficheiros. Útil en sistemas que non teñen ou usan permisos personalizados (ex. FAT, exFAT, Synology, Android).",
"Discard": "Descartar",
"Disconnected": "Desconectado",
"Disconnected (Inactive)": "Desconectado (Inactivo)",
@@ -102,7 +119,9 @@
"Discovery Failures": "Erros de Descubrimento",
"Discovery Status": "Estado do Descubrimento",
"Dismiss": "Descartar",
"Do not add it to the ignore list, so this notification may recur.": "Non engadilo á lista de ignorados, para que esta notificación poida repetirse.",
"Do not restore": "Non restaurar",
"Do not restore all": "Non restablecer todo",
"Do you want to enable watching for changes for all your folders?": "Quere habilitar o control de cambios para todos os seus cartafois?",
"Documentation": "Documentación",
"Download Rate": "Velocidade de Descarga",
@@ -110,11 +129,17 @@
"Downloading": "Descargando",
"Edit": "Editar",
"Edit Device": "Editar o Dispositivo",
"Edit Device Defaults": "Editar predeterminados do dispositivo",
"Edit Folder": "Editar o Cartafol",
"Edit Folder Defaults": "Editar predeterminados dos cartafoles",
"Editing {%path%}.": "Editando {{path}}.",
"Enable Crash Reporting": "Activar informar dos fallos",
"Enable NAT traversal": "Habilitar o NAT traversal",
"Enable Relaying": "Habilitar Relevos",
"Enabled": "Habilitado",
"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.",
"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.",
@@ -125,8 +150,14 @@
"Extended Attributes Filter": "Filtro de Atributos Estendidos",
"External": "Externo",
"External File Versioning": "Versionado de Fichiro Externo",
"Failed Items": "Elmentos fallados",
"Failed to load file versions.": "Fallou a carga das versións dos ficheiros.",
"Failed to load ignore patterns.": "Fallou a carga de patróns ignorados.",
"Failed to set up, retrying": "Fallou a configuración, reintentando",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "É de agardar o fallo ao conectar con servidores IPv6 se non hai conexión por IPv6.",
"File Pull Order": "Orde de Obtención de Arquivos",
"File Versioning": "Versionado de Ficheiros",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Os ficheiros móvense ao directorio .stversions cando se substitúen ou eleminan con Syncthing.",
"Filter by date": "FIltrar por data",
"Filter by name": "Filtrar por nome",
"Folder": "Cartafol",
@@ -292,7 +323,7 @@
"Show diff with previous version": "Mostrar a diferencia coa versión anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrado en lugar do ID de Dispositivo no estado do clúster. Anunciarase a outros dispositivos como nome por defecto opcional.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrado en lugar do ID de Dispositivo no estado do clúster. Actualizarase ao nome que anuncia o dispositivo de se deixar baleiro.",
"Shutdown": "Apagar",
"Shut Down": "Apagar",
"Shutdown Complete": "Apagado Completado",
"Simple": "Simple",
"Simple File Versioning": "Versionado de Ficheiros Sinxelo",

View File

@@ -1,114 +1,558 @@
{
"A device with that ID is already added.": "כבר נוסף התקן עם המזהה הזה.",
"A negative number of days doesn't make sense.": "מספר שלילי של ימים אינו הגיוני.",
"A new major version may not be compatible with previous versions.": "ייתכן שגרסה עיקרית חדשה לא תהיה תואמת לגרסאות קודמות.",
"API Key": "מפתח API",
"About": "על אודות",
"About": "אודות",
"Action": "פעולה",
"Actions": "פעולות",
"Add": "הוספה",
"Add Device": "הוספת התקן",
"Add Folder": "הוספת תיקיה",
"Add Remote Device": "הוספת התקן מרוחק",
"Add new folder?": "להוסיף תיקיה חדשה?",
"Active filter rules": "כללי מסנן פעילים",
"Add": "הוסף",
"Add Device": "הוסף התקן",
"Add Folder": "הוסף תיקייה",
"Add Remote Device": "הוסף התקן מרוחק",
"Add devices from the introducer to our device list, for mutually shared folders.": "הוסף התקנים מהמציג לרשימת ההתקנים שלנו, בשביל תיקיות משותפות הדדית.",
"Add filter entry": "הוסף ערך מסנן",
"Add ignore patterns": "הוסף דפוסי התעלמות",
"Add new folder?": "להוסיף תיקייה חדשה?",
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "בנוסף, פרק הזמן לסריקה מלאה מחדש יגדל (פי 60, כלומר ברירת מחדל חדשה של שעה). אתה יכול גם להגדיר אותו ידנית עבור כל תיקייה מאוחר יותר לאחר שבחרת 'לא'.",
"Address": "כתובת",
"Addresses": "כתובות",
"Advanced": "מתקדם",
"Advanced Configuration": "הגדרת תצורה מתקדמת",
"Advanced Configuration": "תצורה מתקדמת",
"All Data": "כל הנתונים",
"Allow Anonymous Usage Reporting?": "לאפשר דיווח שימוש בעילום שם?",
"All Time": "כל הזמנים",
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "כל התיקיות המשותפות עם התקן זה חייבות להיות מוגנת באמצעות סיסמה, כך שכל הנתונים שנשלחו אינם קריאים ללא הסיסמה שניתנה.",
"Allow Anonymous Usage Reporting?": "לאפשר דיווח שימוש אנונימי?",
"Allowed Networks": "רשתות מורשות",
"Alphabetic": "אלפאבתי",
"Anonymous Usage Reporting": "דיווח שימוש בעילום שם",
"Are you sure you want to restore {%count%} files?": "האם אכן ברצונך לשחזר {{count}} קבצים?",
"Are you sure you want to upgrade?": "האם אכן ברצונך לשדרג?",
"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?": "פורמט דוח שימוש אנונימי השתנה. האם ברצונך לעבור לפורמט החדש?",
"Applied to LAN": "הוחל על LAN",
"Apply": "החל",
"Are you sure you want to override all remote changes?": "האם אתה בטוח שברצונך לדרוס את כל השינויים המרוחקים?",
"Are you sure you want to permanently delete all these files?": "האם אתה בטוח שברצונך למחוק לצמיתות את כל הקבצים האלה?",
"Are you sure you want to remove device {%name%}?": "האם אתה בטוח שברצונך להסיר את ההתקן {{name}}?",
"Are you sure you want to remove folder {%label%}?": "האם אתה בטוח שברצונך להסיר את התיקייה {{label}}?",
"Are you sure you want to restore {%count%} files?": "האם אתה בטוח שברצונך לשחזר {{count}} קבצים?",
"Are you sure you want to revert all local changes?": "האם אתה בטוח שברצונך לבטל את כל השינויים המקומיים?",
"Are you sure you want to upgrade?": "האם אתה בטוח שברצונך לשדרג?",
"Authentication Required": "נדרש אימות",
"Authors": "מחברים",
"Auto Accept": "הסכמה אוטומטית",
"Automatic upgrades": "שדרוג אוטומטי",
"Automatic Crash Reporting": "דיווח קריסה אוטומטי",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "שדרוג אוטומטי עכשיו מציע את הבחירה בין שחרורים יציבים ומועמדים לשחרור.",
"Automatic upgrades": "שדרוגים אוטומטיים",
"Automatic upgrades are always enabled for candidate releases.": "שדרוגים אוטומטיים תמיד מופעלים עבור מועמדים לשחרור.",
"Automatically create or share folders that this device advertises at the default path.": "צור או שתף באופן אוטומטי תיקיות שההתקן הזה מפרסם בנתיב ברירת המחדל.",
"Available debug logging facilities:": "מתקני רישום דיבג זמינים:",
"Be careful!": "זהירות!",
"Bugs": "תקלות",
"Changelog": "רשימת שינויים",
"Close": "סגירה",
"Body:": "גוף:",
"Bugs": "באגים",
"Cancel": "ביטול",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "לא ניתן לאפשור כאשר סוג התיקייה הוא \"{{foldertype}}\".",
"Changelog": "יומן שינויים",
"Clean out after": "נקה לאחר",
"Cleaning Versions": "מנקה גרסאות",
"Cleanup Interval": "פרק זמן לניקוי",
"Click to see full identification string and QR code.": "לחץ כדי לראות מחרוזת זיהוי מלאה וקוד QR.",
"Close": "סגור",
"Command": "פקודה",
"Comment, when used at the start of a line": "הערה, כאשר משתמשים בה בתחילת שורה",
"Compression": "דחיסה",
"Connection Error": קלת חיבור",
"Configuration Directory": יקיית תצורה",
"Configuration File": "קובץ תצורה",
"Configured": "מוגדר",
"Connected (Unused)": "מחובר (לא בשימוש)",
"Connection Error": "שגיאת חיבור",
"Connection Management": "ניהול חיבורים",
"Connection Type": "סוג חיבור",
"Connections": "חיבורים",
"Connections via relays might be rate limited by the relay": "חיבורים דרך ממסרים עשויים להיות מוגבלים בקצב על ידי הממסר",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "מעקב רציף אחר שינויים זמין כעת בתוך Syncthing. זה יגלה שינויים בדיסק ויוציא סריקה רק על הנתיבים שהשתנו. היתרונות הן ששינויים מופצים מהר יותר ושנדרשות פחות סריקות מלאות.",
"Copied from elsewhere": "הועתק ממקום אחר",
"Copied from original": "הועתק מהמקור",
"Copied!": "הועתק!",
"Copy": "העתק",
"Copy failed! Try to select and copy manually.": "העתקה נכשלה! נסה לבחור ולהעתיק ידנית.",
"Currently Shared With Devices": "כרגע משותף עם התקנים",
"Custom Range": "טווח מותאם אישית",
"Danger!": "סכנה!",
"Database Location": "מיקום מסד נתונים",
"Debugging Facilities": "מתקני דיבוג",
"Default": "ברירת מחדל",
"Default Configuration": "תצורת ברירת מחדל",
"Default Device": "התקן ברירת מחדל",
"Default Folder": "תיקייה ברירת מחדל",
"Default Ignore Patterns": "דפוסי התעלמות ברירת מחדל",
"Defaults": "ברירות מחדל",
"Delete": "מחק",
"Delete Unexpected Items": "מחק פריטים בלתי צפויים",
"Deleted {%file%}": "{{file}} נמחק",
"Deselect All": "בטל את הבחירה בהכל",
"Deselect devices to stop sharing this folder with.": "בטל בחירת התקנים כדי להפסיק שיתוף תיקייה זו.",
"Deselect folders to stop sharing with this device.": "בטל בחירת תיקיות להפסקת השיתוף עם התקן זה.",
"Device": "התקן",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "התקן \"{{name}}\" ({{device}} ב־{{address}}) רוצה להתחבר. להוסיף התקן חדש?",
"Device Certificate": "תעודת התקן",
"Device ID": "מזהה התקן",
"Device Identification": "מזהה התקן",
"Device Identification": "זיהוי התקן",
"Device Name": "שם התקן",
"Device Status": "מצב התקן",
"Device is untrusted, enter encryption password": "ההתקן אינו מהימן, הזן סיסמת הצפנה",
"Device rate limits": "מגבלות קצב התקן",
"Device that last modified the item": "ההתקן ששינה את הפריט בפעם האחרונה",
"Devices": "התקנים",
"Disable Crash Reporting": "השבת דיווח קריסה",
"Disabled": "מושבת",
"Disabled periodic scanning and disabled watching for changes": "סריקה תקופתית הושבתה ומעקב אחר שינויים הושבת",
"Disabled periodic scanning and enabled watching for changes": "סריקה תקופתית הושבתה ומעקב אחר שינויים הופעל",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "סריקה תקופתית הושבתה והגדרת מעקב אחר שינויים נכשלה, מנסה שוב כל דקה:",
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "משבית השוואה וסנכרון של הרשאות קובץ. שימושי במערכות עם הרשאות שאינן קיימות או מותאמות אישית (למשל Android, Synology, exFAT, FAT).",
"Discard": "השלך",
"Disconnected": "מנותק",
"Disconnected (Inactive)": "מנותק (לא פעיל)",
"Disconnected (Unused)": "מנותק (לא בשימוש)",
"Discovered": "התגלה",
"Discovery": "גילוי",
"Discovery Failures": "כשלי גילוי",
"Discovery Status": "מצב גילוי",
"Dismiss": "דחה",
"Do not add it to the ignore list, so this notification may recur.": "אל תוסיף אותו לרשימת ההתעלמות, כך שהתראה זו עשויה לחזור על עצמה.",
"Do not restore": "אל תשחזר",
"Do not restore all": "אל תשחזר הכל",
"Do you want to enable watching for changes for all your folders?": "האם ברצונך להפעיל מעקב אחר שינויים עבור כל התיקיות שלך?",
"Documentation": "תיעוד",
"Download Rate": "קצב הורדה",
"Edit": "עריכה",
"Edit Device": "עריכת התקן",
"Edit Folder": "עריכה תיקיה",
"Downloaded": ורד",
"Downloading": "מוריד",
"Edit": "ערוך",
"Edit Device": "ערוך התקן",
"Edit Device Defaults": "ערוך ברירות מחדל של התקן",
"Edit Folder": "ערוך תיקייה",
"Edit Folder Defaults": "ערוך ברירות מחדל של תיקייה",
"Editing {%path%}.": "עורך {{path}}.",
"Enable Crash Reporting": "הפעל דיווח קריסה",
"Enable NAT traversal": "הפעל חציית NAT",
"Enable Relaying": "הפעל ממסור",
"Enabled": "מופעל",
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "מאפשר שליחת תכונות מורחבות להתקנים אחרים, ומחיל תכונות מורחבות נכנסות. עשוי לדרוש הרצה עם הרשאות גבוהות.",
"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.": "מאפשר שליחת תכונות מורחבות להתקנים אחרים, אבל לא מחיל תכונות מורחבות נכנסות. זה יכול להשפיע משמעותית על הביצועים. תמיד מופעל כאשר \"סנכרון תכונות מורחבות\" מופעל.",
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "מאפשר שליחת מידע על בעלות להתקנים אחרים, ומחיל מידע על בעלות נכנס. בדרך כלל דורש הרצה עם הרשאות גבוהות.",
"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.": "מאפשר שליחת מידע על בעלות להתקנים אחרים, אבל לא מחיל מידע על בעלות נכנס. זה יכול להשפיע משמעותית על הביצועים. תמיד מופעל כאשר \"סנכרון בעלות\" מופעל.",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "הזן מספר לא שלילי (למשל, \"2.35\") ובחר יחידה. אחוזים הם כחלק מגודל הדיסק הכולל.",
"Enter a non-privileged port number (1024 - 65535).": "הזן מספר יציאה לא מיוחס (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "הזן כתובות מופרדות בפסיק (\"tcp://ip:port\", \"tcp://host:port\") או \"dynamic\" כדי לבצע גילוי אוטומטי של הכתובת.",
"Enter ignore patterns, one per line.": "הזן דפוסי התעלמות, אחד בכל שורה.",
"Enter up to three octal digits.": "הזן עד שלושה ספרות אוקטליות.",
"Error": "שגיאה",
"Folder": "תיקיה",
"Folder ID": "מזהה תיקיה",
"Folder Label": "כותרת תיקיה",
"Folder Path": "נתיב תיקיה",
"Folder Type": "סוג תיקיה",
"Extended Attributes": "תכונות מורחבות",
"Extended Attributes Filter": "מסנן תכונות מורחבות",
"External": "חיצוני",
"External File Versioning": "ניהול גרסאות קבצים חיצוני",
"Failed Items": "פריטים שנכשלו",
"Failed to load file versions.": "טעינת גרסאות קבצים נכשלה.",
"Failed to load ignore patterns.": "טעינת דפוסי התעלמות נכשלה.",
"Failed to set up, retrying": "ההגדרה נכשלה, מנסה שוב",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "צפוי כשל בהתחברות לשרתי IPv6 אם אין קישוריות IPv6.",
"File Pull Order": "סדר משיכת קבצים",
"File Versioning": "ניהול גרסאות קבצים",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "הקבצים מועברים לתיקיית stversions. כאשר הם מוחלפים או נמחקים על ידי Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "הקבצים מועברים לגרסאות עם חותמת תאריך בתיקיית stversions. כאשר הם מוחלפים או נמחקים על ידי 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.": "הקבצים מוגנים מפני שינויים שנעשו בהתקנים אחרים, אבל שינויים שנעשו בהתקן זה יישלחו לשאר האשכול.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "הקבצים מסונכרנים מהאשכול, אבל כל שינוי שנעשה מקומית לא יישלח להתקנים אחרים.",
"Filesystem Watcher Errors": "שגיאות משגיח מערכת קבצים",
"Filter by date": "סנן לפי תאריך",
"Filter by name": "סנן לפי שם",
"Folder": "תיקייה",
"Folder ID": "מזהה תיקייה",
"Folder Label": "תווית תיקייה",
"Folder Path": "נתיב תיקייה",
"Folder Status": "מצב תיקייה",
"Folder Type": "סוג תיקייה",
"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": "תיקיות",
"GUI": "ממשק משתמש",
"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": "ממשק משתמש גרפי",
"GUI / API HTTPS Certificate": "תעודת HTTPS עבור ממשק גרפי / תכנותי",
"GUI Authentication Password": "סיסמת אימות ממשק גרפי",
"GUI Authentication User": "משתמש אימות ממשק גרפי",
"GUI Authentication: Set User and Password": "אימות ממשק גרפי: הגדר משתמש וסיסמה",
"GUI Listen Address": "כתובת האזנה של ממשק גרפי",
"GUI Override Directory": "תיקיית מעקף ממשק גרפי",
"GUI Theme": "ערכת נושא של ממשק גרפי",
"General": "כללי",
"Generate": "צור",
"Global Discovery": "גילוי גלובלי",
"Global Discovery Servers": "שרתי גילוי גלובלי",
"Global State": "מצב גלובלי",
"Help": "עזרה",
"Hint: only deny-rules detected while the default is deny. Consider adding \"permit any\" as last rule.": "רמז: רק כללי שלילה מזוהים כאשר ברירת המחדל היא לשלול. שקול להוסיף \"התר כל\" ככלל אחרון.",
"Home page": "דף הבית",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "עם זאת, ההגדרות הנוכחיות שלך מצביעות על כך שאתה אולי לא רוצה את זה מופעל. השבתנו דיווח קריסה אוטומטי עבורך.",
"Identification": "זיהוי",
"If untrusted, enter encryption password": "אם לא מהימן, הזן סיסמת הצפנה",
"If you want to prevent other users on this computer from accessing Syncthing and through it your files, consider setting up authentication.": "אם אתה רוצה למנוע ממשתמשים אחרים במחשב זה לגשת אל Syncthing ודרך כך לקבצים שלך, שקול להגדיר אימות.",
"Ignore": "התעלמות",
"Ignore Permissions": "התעלמות מהרשאות",
"Keep Versions": "שמירת גרסאות",
"Ignore Patterns": "דפוסי התעלמות",
"Ignore Permissions": "התעלם מהרשאות",
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "ניתן להוסיף דפוסי התעלמות רק לאחר יצירת התיקייה. אם מסומן, שדה קלט להזנת דפוסי התעלמות יוצג לאחר השמירה.",
"Ignored Devices": "התקנים בהתעלמות",
"Ignored Folders": "תיקיות בהתעלמות",
"Ignored at": "בהתעלמות אצל",
"Included Software": "תוכנות כלולות",
"Incoming Rate Limit (KiB/s)": "מגבלת קצב נכנס (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "תצורה שגויה עלולה לגרום נזק לתכולת התיקייה שלך ולהפוך את Syncthing לבלתי ניתן להפעלה.",
"Incorrect user name or password.": "שם משתמש או סיסמה שגויים.",
"Internally used paths:": "נתיבים בשימוש פנימי:",
"Introduced By": "הוצג על ידי",
"Introducer": "מציג",
"Introduction": "מבוא",
"Inversion of the given condition (i.e. do not exclude)": "היפוך של התנאי הנתון (כלומר אל תחריג)",
"Keep Versions": "שמור גרסאות",
"LDAP": "LDAP",
"Learn more": "למידע נוסף",
"Loading...": "כעת בטעינה...",
"Largest First": "הגדול ביותר תחילה",
"Last 30 Days": "30 הימים האחרונים",
"Last 7 Days": "7 הימים האחרונים",
"Last Month": "החודש האחרון",
"Last Scan": "הסריקה האחרונה",
"Last seen": "נראה לאחרונה",
"Latest Change": "השינוי העדכני ביותר",
"Learn more": "למד עוד",
"Learn more at {%url%}": "למד עוד באתר {{url}}",
"Limit": "מגבלה",
"Limit Bandwidth in LAN": "הגבלת רוחב פס ברשת תקשורת מקומית (LAN)",
"Listener Failures": "כשלי מאזין",
"Listener Status": "מצב מאזין",
"Listeners": "מאזינים",
"Loading data...": "טוען נתונים...",
"Loading...": "טוען...",
"Local Additions": "הוספות מקומיות",
"Local Discovery": "גילוי מקומי",
"Local State": "מצב מקומי",
"Local State (Total)": "מצב מקומי (סה\"כ)",
"Locally Changed Items": "פריטים שהשתנו מקומית",
"Log": "יומן",
"Move to top of queue": "העברה לראש הרשימה",
"Log File": "קובץ יומן",
"Log In": "היכנס",
"Log Out": "צא",
"Log in to see paths information.": "היכנס כדי לראות מידע על נתיבים.",
"Log in to see version information.": "היכנס כדי לראות מידע על הגרסה.",
"Log tailing paused. Scroll to the bottom to continue.": "מעקב יומן הושהה. גלול לתחתית כדי להמשיך.",
"Login failed, see Syncthing logs for details.": "הכניסה נכשלה, ראה יומני Syncthing לפרטים.",
"Logs": "יומנים",
"Major Upgrade": "שדרוג עיקרי",
"Mass actions": "פעולות המוניות",
"Maximum Age": "גיל מרבי",
"Maximum single entry size": "גודל ערך יחיד מרבי",
"Maximum total size": "גודל כולל מרבי",
"Metadata Only": "מטא-נתונים בלבד",
"Minimum Free Disk Space": "שטח דיסק פנוי מזערי",
"Mod. Device": "שנה התקן",
"Mod. Time": "זמן שינוי",
"More than a month ago": "לפני יותר מחודש",
"More than a week ago": "לפני יותר משבוע",
"More than a year ago": "לפני יותר משנה",
"Move to top of queue": "העבר לראש התור",
"Multi level wildcard (matches multiple directory levels)": "תו כללי רב רמות (תואם רמות תיקייה מרובות)",
"Never": "לעולם לא",
"New Device": "התקן חדש",
"New Folder": "תיקיה חדשה",
"New Folder": "תיקייה חדשה",
"Newest First": "החדש ביותר תחילה",
"No": "לא",
"No File Versioning": "אין ניהול גרסאות קבצים",
"No files will be deleted as a result of this operation.": "לא יימחקו קבצים כתוצאה מפעולה זו.",
"No rules set": "לא נקבעו כללים",
"No upgrades": "אין שדרוגים",
"Not shared": "לא בשיתוף",
"Notice": "הודעה",
"Number of Connections": "מספר חיבורים",
"OK": "אישור",
"Off": "כבוי",
"Oldest First": "הישן ביותר תחילה",
"Optional descriptive label for the folder. Can be different on each device.": "תווית תיאורית אופציונלית עבור התיקייה. יכולה להיות שונה בכל התקן.",
"Options": "אפשרויות",
"Out of Sync": "לא מסונכרן",
"Out of Sync Items": "פריטים לא מסונכרנים",
"Outgoing Rate Limit (KiB/s)": "מגבלת קצב יוצא (KiB/s)",
"Override": "דריסה",
"Override Changes": "דרוס שינויים",
"Ownership": "בעלות",
"Password": "סיסמה",
"Path": "נתיב",
"Pause": "השהיה",
"Pause All": "להשהות הכול",
"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 where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "הנתיב שבו יש לאחסן גרסאות (השאר ריק עבור תיקיית stversion. ברירת המחדל בתיקייה המשותפת).",
"Paths": "נתיבים",
"Pause": "השהה",
"Pause All": "השהה הכל",
"Paused": "מושהה",
"Paused (Unused)": "מושהה (לא בשימוש)",
"Pending changes": "שינויים ממתינים",
"Periodic scanning at given interval and disabled watching for changes": "סריקה תקופתית בפרק זמן שניתן ומעקב אחר שינויים הושבת",
"Periodic scanning at given interval and enabled watching for changes": "סריקה תקופתית בפרק זמן שניתן ומעקב אחר שינויים הופעל",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "סריקה תקופתית בפרק זמן שניתן והגדרת מעקב אחר שינויים נכשלה, מנסה שוב כל דקה:",
"Permanently add it to the ignore list, suppressing further notifications.": "הוסף אותו לצמיתות לרשימת ההתעלמות, תוך העלמת התראות נוספות.",
"Please consult the release notes before performing a major upgrade.": "נא לבדוק את הערות השחרור לפני ביצוע שדרוג עיקרי.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "נא להגדיר משתמש וסיסמה לאימות ממשק גרפי בשיח ההגדרות.",
"Please wait": "נא להמתין",
"Prefix indicating that the file can be deleted if preventing directory removal": "קידומת המציינת כי הקובץ ניתן למחיקה אם מונעים הסרת תיקייה",
"Prefix indicating that the pattern should be matched without case sensitivity": "קידומת המציינת כי יש להתאים את הדפוס ללא רגישות לרישיות",
"Preparing to Sync": "מתכונן לסנכרון",
"Preview": "תצוגה מקדימה",
"Preview Usage Report": "תצוגה מקדימה של דוח שימוש",
"QR code": "קוד QR",
"QUIC LAN": "QUIC LAN",
"QUIC WAN": "QUIC WAN",
"Quick guide to supported patterns": "מדריך מהיר לדפוסים נתמכים",
"Random": "אקראי",
"Receive Encrypted": "קבלה מוצפנת",
"Receive Only": "קבלה בלבד",
"Received data is already encrypted": "הנתונים שהתקבלו כבר מוצפנים",
"Recent Changes": "שינויים אחרונים",
"Reduced by ignore patterns": "הופחת על ידי דפוסי התעלמות",
"Relay LAN": "ממסר LAN",
"Relay WAN": "ממסר WAN",
"Release Notes": "הערות שחרור",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "מועמדים לשחרור מכילים את התכונות והתיקונים העדכניים ביותר. הם דומים לשחרורים הדו־שבועיים המסורתיים של Syncthing.",
"Remote Devices": "התקנים מרוחקים",
"Remove": "הסרה",
"Remote GUI": "ממשק גרפי מרוחק",
"Remove": "הסר",
"Remove Device": "הסר התקן",
"Remove Folder": "הסר תיקייה",
"Required identifier for the folder. Must be the same on all cluster devices.": "נדרש מזהה עבור התיקייה. חייב להיות אותו הדבר בכל התקני האשכול.",
"Rescan": "סריקה מחדש",
"Rescan All": "לסרוק הכול",
"Save": "שמירה",
"Scanning": "כעת בסריקה",
"Send & Receive": "שליחה וקבלה",
"Rescan All": "סרוק הכל מחדש",
"Rescans": "סריקות מחדש",
"Restart": "הפעלה מחדש",
"Restart Needed": "נדרשת הפעלה מחדש",
"Restarting": "מפעיל מחדש",
"Restore": "שחזר",
"Restore Versions": "שחזר גרסאות",
"Resume": "המשך",
"Resume All": "המשך הכל",
"Reused": "בשימוש חוזר",
"Revert": "בטל",
"Revert Local Changes": "בטל שינויים מקומיים",
"Save": "שמור",
"Saving changes": "שומר שינויים",
"Scan Time Remaining": "זמן הסריקה שנותר",
"Scanning": "סורק",
"See external versioning help for supported templated command line parameters.": "ראה עזרה בנושא ניהול גרסאות חיצוני עבור פרמטרים תבניתיים הנתמכים בשורת הפקודה.",
"Select All": "בחר הכל",
"Select a version": "בחר גרסה",
"Select additional devices to share this folder with.": "בחר התקנים נוספים לשיתוף תיקייה זו.",
"Select additional folders to share with this device.": "בחר תיקיות נוספות לשיתוף עם התקן זה.",
"Select latest version": "בחר את הגרסה העדכנית ביותר",
"Select oldest version": "בחר את הגרסה הישנה ביותר",
"Send & Receive": "שליחה & קבלה",
"Send Extended Attributes": "שלח תכונות מורחבות",
"Send Only": "שליחה בלבד",
"Share": יתוף",
"Share Folder": "שיתוף תיקיה",
"Share this folder?": "לשתף תיקיה זו?",
"Send Ownership": לח בעלות",
"Set Ignores on Added Folder": "הגדר התעלמויות על התיקייה שנוספה",
"Settings": "הגדרות",
"Share": "שתף",
"Share Folder": "שתף תיקייה",
"Share by Email": "שתף באמצעות דוא\"ל",
"Share by SMS": "שתף באמצעות מסרון",
"Share this folder?": "לשתף תיקייה זו?",
"Shared Folders": "תיקיות משותפות",
"Shared With": "משותף עם",
"Show ID": "הצגת מזהה",
"Sharing": "שיתוף",
"Show ID": "הצג מזהה",
"Show QR": "הצג QR",
"Shutdown": "כיבוי",
"Show detailed discovery status": "הצג מצב גילוי מפורט",
"Show detailed listener status": "הצג מצב מאזין מפורט",
"Show diff with previous version": "הצג הבדל עם הגרסה הקודמת",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "מוצג במקום מזהה ההתקן במצב האשכול. יפורסם להתקנים אחרים כשם ברירת מחדל אופציונלי.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "מוצג במקום מזהה ההתקן במצב האשכול. יעודכן לשם שההתקן מפרסם אם נותר ריק.",
"Shut Down": "כיבוי",
"Shutdown Complete": "הכיבוי הושלם",
"Simple": "פשוט",
"Simple File Versioning": "ניהול גרסאות קבצים פשוט",
"Single level wildcard (matches within a directory only)": "תו כללי ברמה אחת (תואם בתוך תיקייה בלבד)",
"Size": "גודל",
"Smallest First": "הקטן ביותר תחילה",
"Some discovery methods could not be established for finding other devices or announcing this device:": "לא היה ניתן להקים כמה שיטות גילוי למציאת התקנים אחרים או הכרזת התקן זה:",
"Some items could not be restored:": "לא היה ניתן לשחזר כמה פריטים:",
"Some listening addresses could not be enabled to accept connections:": "לא היה ניתן להפעיל כמה כתובות האזנה לקבלת חיבורים:",
"Source Code": "קוד מקור",
"Stable releases and release candidates": "שחרורים יציבים ומועמדים לשחרור",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "שחרורים יציבים מתעכבים בערך בשבועיים. במהלך הזמן הזה הם עוברים בדיקות בתור מועמדים לשחרור.",
"Stable releases only": "שחרורים יציבים בלבד",
"Staggered": "מדורג",
"Staggered File Versioning": "ניהול גרסאות קבצים מדורג",
"Start Browser": "התחל דפדפן",
"Statistics": "סטטיסטיקה",
"Stay logged in": "הישאר מחובר",
"Stopped": "נעצר",
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "מאחסן ומסנכרן נתונים מוצפנים בלבד. תיקיות בכל ההתקנים המחוברים צריכות להיות מוגדרות עם אותה הסיסמה או להיות גם מסוג \"{{receiveEncrypted}}\".",
"Subject:": "נושא:",
"Support": "תמיכה",
"Syncing": "כעת בסנכרון",
"Support Bundle": "חבילת תמיכה",
"Sync Extended Attributes": "סנכרון תכונות מורחבות",
"Sync Ownership": "סנכרון בעלות",
"Sync Protocol Listen Addresses": "כתובות האזנה של פרוטוקול הסנכרון",
"Sync Status": "מצב סנכרון",
"Syncing": "מסנכרן",
"Syncthing device ID for \"{%devicename%}\"": "מזהה התקן Syncthing עבור \"{{devicename}}\"",
"Syncthing has been shut down.": "Syncthing כבה.",
"Syncthing includes the following software or portions thereof:": "Syncthing כולל את התוכנות הבאות או חלקים מהן:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing היא תוכנה חופשית וקוד פתוח המורשית כ־MPL v2.0.",
"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Syncthing היא תוכנת סנכרון רציף של קבצים. היא מסנכרנת קבצים בין שני מחשבים או יותר בזמן אמת, מוגנים בבטחה מפני עיניים חטטניות. הנתונים שלך הם הנתונים שלך בלבד ומגיע לך לבחור היכן הם מאוחסנים, אם הם משותפים עם צד שלישי כלשהו, ואיך הם משודרים על גבי האינטרנט.",
"Syncthing is listening on the following network addresses for connection attempts from other devices:": "Syncthing מאזין בכתובות הרשת הבאות לניסיונות חיבור מהתקנים אחרים:",
"Syncthing is not listening for connection attempts from other devices on any address. Only outgoing connections from this device may work.": "Syncthing אינו מאזין לניסיונות חיבור מהתקנים אחרים בכתובת כלשהי. רק חיבורים יוצאים מהתקן זה עשויים לעבוד.",
"Syncthing is restarting.": "Syncthing מופעל מחדש.",
"Syncthing is saving changes.": "Syncthing שומר שינויים.",
"Syncthing is upgrading.": "Syncthing משתדרג.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing עכשיו תומך בדיווח קריסות באופן אוטומטי למפתחים. תכונה זו מופעלת כברירת מחדל.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "נראה כי Syncthing נפל, או שיש בעיה עם חיבור האינטרנט שלך. מנסה שוב…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "נראה כי Syncthing חווה בעיה בעיבוד הבקשה שלך. נא לרענן את הדף או להפעיל מחדש את Syncthing אם הבעיה נמשכת.",
"TCP LAN": "TCP LAN",
"TCP WAN": "TCP WAN",
"Take me back": "קח אותי בחזרה",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "הכתובת של הממשק הגרפי נעקפת על ידי אפשרויות הפעלה. שינויים כאן לא ייכנסו לתוקף כל עוד המעקף נמצא במקום.",
"The Syncthing Authors": "מחברי Syncthing",
"The Syncthing admin interface is configured to allow remote access without a password.": "ממשק המנהל של Syncthing מוגדר לאפשר גישה מרוחקת ללא סיסמה.",
"The aggregated statistics are publicly available at the URL below.": "הסטטיסטיקות המצטברות זמינות לציבור בכתובת ה־URL למטה.",
"The cleanup interval cannot be blank.": "פרק זמן לניקוי אינו יכול להיות ריק.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "התצורה נשמרה אבל לא הופעלה. יש לאתחל את Syncthing כדי להפעיל את התצורה החדשה.",
"The device ID cannot be blank.": "מזהה ההתקן אינו יכול להיות ריק.",
"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).": "ניתן למצוא את מזהה ההתקן אותו יש להזין כאן בדו־השיח \"פעולות > הצג מזהה\" בהתקנים האחרים. רווחים ומקפים הם אופציונליים (מוזנחים).",
"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.": "דוח השימוש המוצפן נשלח מדי יום. הוא משמש למעקב אחר פלטפורמות שכיחות, גדלי תיקיות, וגרסאות יישום. אם מערך הנתונים המדווח ישתנה, תתבקש עם דו-שיח זה שוב.",
"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.": "מזהה ההתקן שהוזן לא נראה חוקי. הוא צריך להיות מחרוזת באורך 52 או 56 תווים המורכבת מאותיות ומספרים, כאשר רווחים ומקפים הם אופציונליים.",
"The folder ID cannot be blank.": "מזהה התיקייה לא יכול להיות ריק.",
"The folder ID must be unique.": "מזהה התיקייה חייב להיות ייחודי.",
"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.": "תוכן התיקייה בהתקנים אחרים יידרס כדי להפוך לזהה עם התקן זה. קבצים שלא נוכחים כאן יימחקו בהתקנים אחרים.",
"The folder content on this device will be overwritten to become identical with other devices. Files newly added here will be deleted.": "תוכן התיקייה בהתקן זה יידרס כדי להפוך לזהה עם התקנים אחרים. קבצים חדשים שנוספו כאן יימחקו.",
"The folder path cannot be blank.": "נתיב התיקייה אינו יכול להיות ריק.",
"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.": "נעשה שימוש בפרקי הזמן הבאים: במשך השעה הראשונה נשמרת גרסה כל 30 שניות, במשך היום הראשון נשמרת גרסה כל שעה, במשך 30 הימים הראשונים נשמרת גרסה כל יום, עד הגיל המרבי נשמרת גרסה כל שבוע.",
"The following items could not be synchronized.": "לא היה ניתן לסנכרן את הפריטים הבאים.",
"The following items were changed locally.": "הפריטים הבאים שונו מקומית.",
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "נעשה שימוש בשיטות הבאות כדי לגלות התקנים אחרים ברשת ולהכריז על התקן זה כדי שימצא על ידי אחרים:",
"The following text will automatically be inserted into a new message.": "הטקסט הבא יוכנס באופן אוטומטי לתוך הודעה חדשה.",
"The following unexpected items were found.": "הפריטים הבלתי צפויים הבאים נמצאו.",
"The interval must be a positive number of seconds.": "פרק הזמן חייב להיות מספר חיובי של שניות.",
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "פרק הזמן, בשניות, להרצת ניקוי בתיקיית הגרסאות. אפס כדי להשבית ניקוי תקופתי.",
"The maximum age must be a number and cannot be blank.": "הגיל המרבי חייב להיות מספר ואינו יכול להיות ריק.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "הזמן המרבי לשמירת גרסה (בימים, הגדר ל־0 כדי להשאיר גרסאות לנצח).",
"The number of connections must be a non-negative number.": "מספר החיבורים חייב להיות מספר לא שלילי.",
"The number of days must be a number and cannot be blank.": "מספר הימים חייב להיות מספר ואינו יכול להיות ריק.",
"The number of days to keep files in the trash can. Zero means forever.": "מספר הימים לשמירת קבצים בפח האשפה. אפס פירושו לנצח.",
"The number of old versions to keep, per file.": "המספר של גרסאות ישנות שיש לשמור, לכל קובץ.",
"The number of versions must be a number and cannot be blank.": "מספר הגרסאות חייב להיות מספר ואינו יכול להיות ריק.",
"The path cannot be blank.": "הנתיב אינו יכול להיות ריק.",
"The rate limit is applied to the accumulated traffic of all connections to this device.": "מגבלת הקצב מוחלת על התעבורה המצטברת של כל החיבורים להתקן זה.",
"The rate limit must be a non-negative number (0: no limit)": "מגבלת הקצב חייבת להיות מספר לא שלילי (0: ללא הגבלה)",
"The remote device has not accepted sharing this folder.": "ההתקן המרוחק לא קיבל את שיתוף תיקייה זו.",
"The remote device has paused this folder.": "ההתקן המרוחק השהה את התיקייה הזו.",
"The rescan interval must be a non-negative number of seconds.": "פרק הזמן לסריקה מחדש חייב להיות מספר לא שלילי של שניות.",
"There are no devices to share this folder with.": "אין התקנים לשיתוף תיקייה זו.",
"There are no file versions to restore.": "אין גרסאות קובץ לשחזור.",
"There are no folders to share with this device.": "אין תיקיות לשיתוף עם התקן זה.",
"They are retried automatically and will be synced when the error is resolved.": "הם מנוסים מחדש באופן אוטומטי ויסונכרנו כאשר השגיאה תיפתר.",
"This Device": "התקן זה",
"This Month": "החודש הזה",
"This can easily give hackers access to read and change any files on your 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.": "התקן זה לא יכול לגלות באופן אוטומטי התקנים אחרים ולהכריז על כתובת משלו כדי שימצא על ידי אחרים. רק התקנים עם כתובות מוגדרות סטטית יכולים להתחבר.",
"This is a major version upgrade.": "זהו שדרוג גרסה עיקרית.",
"This setting controls the free space required on the home (i.e., index database) disk.": "הגדרה זו שולטת במקום הפנוי הנדרש בדיסק הבית (כלומר, אינדקס של מסד נתונים).",
"Time": "זמן",
"Time the item was last modified": "זמן השינוי האחרון של הפריט",
"To connect with the Syncthing device named \"{%devicename%}\", add a new remote device on your end with this ID:": "כדי להתחבר עם התקן Syncthing בשם \"{{devicename}}\", הוסף התקן מרוחק חדש בקצה שלך עם מזהה זה:",
"To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked.": "כדי להתיר כלל, סמן את תיבת הסימון. כדי לשלול כלל, השאר אותה לא מסומנת.",
"Today": "היום",
"Trash Can": "פח אשפה",
"Trash Can File Versioning": "ניהול גרסאות קבצים עם פח אשפה",
"Type": "סוג",
"UNIX Permissions": "הרשאות UNIX",
"Unavailable": "לא זמין",
"Unavailable/Disabled by administrator or maintainer": "לא זמין/מושבת על ידי מנהל או מתחזק",
"Undecided (will prompt)": "לא הוחלט (יתבקש)",
"Unexpected Items": "פריטים בלתי צפויים",
"Unexpected items have been found in this folder.": "פריטים בלתי צפויים נמצאו בתיקייה זו.",
"Unignore": "בטל התעלמות",
"Unknown": "לא ידוע",
"Unshared": "לא משותף",
"Unshared Devices": "התקנים לא משותפים",
"Unshared Folders": "תיקיות לא משותפות",
"Untrusted": "לא מהימן",
"Up to Date": "מעודכן",
"Updated {%file%}": "{{file}} עודכן",
"Upgrade": "שדרוג",
"Upgrade To {%version%}": "שדרוג לגרסה {{version}}",
"Upgrading": "כעת בשדרוג",
"Upgrade To {%version%}": "שדרג ל־{{version}}",
"Upgrading": "משדרג",
"Upload Rate": "קצב העלאה",
"Uptime": "זמן פעולה",
"Use HTTPS for GUI": "שימוש ב־HTTP לממשק המשתמש",
"Usage reporting is always enabled for candidate releases.": "דיווח שימוש תמיד מופעל עבור מועמדים לשחרור.",
"Use HTTPS for GUI": "השתמש ב־HTTPS עבור ממשק גרפי",
"Use notifications from the filesystem to detect changed items.": "השתמש בהתראות ממערכת הקבצים כדי לגלות פריטים שהשתנו.",
"User": "משתמש",
"User Home": "תיקיית הבית של המשתמש",
"Username/Password has not been set for the GUI authentication. Please consider setting it up.": "שם משתמש/סיסמה לא הוגדרו עבור אימות הממשק הגרפי. נא לשקול להגדיר אותם.",
"Using a QUIC connection over LAN": "משתמש בחיבור QUIC על גבי LAN",
"Using a QUIC connection over WAN": "משתמש בחיבור QUIC על גבי WAN",
"Using a direct TCP connection over LAN": "משתמש בחיבור TCP ישיר על גבי LAN",
"Using a direct TCP connection over WAN": "משתמש בחיבור TCP ישיר על גבי WAN",
"Version": "גרסה",
"Versions": "גרסאות",
"Versions Path": "נתיב גרסאות",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "גרסאות נמחקות באופן אוטומטי אם הן ישנות יותר מהגיל המרבי או חורגות ממספר הקבצים המותרים בפרק זמן.",
"Waiting to Clean": "ממתין לנקות",
"Waiting to Scan": "ממתין לסריקה",
"Waiting to Sync": "ממתין לסנכרון",
"Warning": "אזהרה",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "אזהרה, הנתיב הזה הוא תיקיית אב של תיקייה קיימת \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "אזהרה, הנתיב הזה הוא תיקיית אב של תיקייה קיימת \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "אזהרה, הנתיב הזה הוא תיקיית משנה של תיקייה קיימת \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "אזהרה, הנתיב הזה הוא תיקיית משנה של תיקייה קיימת \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "אזהרה: אם אתה משתמש במשגיח חיצוני כמו {{syncthingInotify}}, עליך לוודא שהוא מושבת.",
"Watch for Changes": "עקוב אחר שינויים",
"Watching for Changes": "מעקב אחר שינויים",
"Watching for changes discovers most changes without periodic scanning.": "מעקב אחר שינויים מגלה את רוב השינויים ללא סריקה תקופתית.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "בעת הוספת התקן חדש, זכור כי יש להוסיף את ההתקן הזה גם בצד השני.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "בעת הוספת תיקייה חדשה, זכור כי מזהה התיקייה משמש לקשירת תיקיות יחד בין התקנים. הם רגישים לרישיות וצריכים להתאים בדיוק בין כל ההתקנים.",
"When set to more than one on both devices, Syncthing will attempt to establish multiple concurrent connections. If the values differ, the highest will be used. Set to zero to let Syncthing decide.": "כאשר מוגדר ליותר מאחד בשני ההתקנים, Syncthing ינסה להקים חיבורים בו-זמניים מרובים. אם הערכים שונים, ייעשה שימוש בערך הגבוה ביותר. הגדר לאפס כדי לתת ל־Syncthing להחליט.",
"Yes": "כן",
"You must keep at least one version.": "חובה לשמור גרסה אחת לפחות.",
"Yesterday": "אתמול",
"You can also copy and paste the text into a new message manually.": "אתה יכול גם להעתיק ולהדביק את הטקסט לתוך הודעה חדשה באופן ידני.",
"You can also select one of these nearby devices:": "אתה יכול גם לבחור אחד מההתקנים הקרובים הבאים:",
"You can change your choice at any time in the Settings dialog.": "אתה יכול לשנות את הבחירה שלך בכל עת בדו־שיח ההגדרות.",
"You can read more about the two release channels at the link below.": "אתה יכול לקרוא עוד על שני ערוצי השחרור בקישור למטה.",
"You have no ignored devices.": "אין לך התקנים בהתעלמות.",
"You have no ignored folders.": "אין לך תיקיות בהתעלמות.",
"You have unsaved changes. Do you really want to discard them?": "יש לך שינויים שלא נשמרו. האם אתה באמת רוצה להשליך אותם?",
"You must keep at least one version.": "אתה חייב להשאיר לפחות גרסה אחת.",
"You should never add or change anything locally in a \"{%receiveEncrypted%}\" folder.": "לעולם אל תוסיף או תשנה כלום באופן מקומי בתיקיית \"{{receiveEncrypted}}\".",
"Your SMS app should open to let you choose the recipient and send it from your own number.": "יישום המסרונים שלך צריך להיפתח כדי לתת לך לבחור את הנמען ולשלוח את המסרון מהמספר שלך.",
"Your email app should open to let you choose the recipient and send it from your own address.": "יישום הדוא\"ל שלך צריך להיפתח כדי לתת לך לבחור את הנמען ולשלוח את ההודעה מהכתובת שלך.",
"days": "ימים",
"deleted": "נמחק",
"deny": "לשלול",
"directories": "תיקיות",
"file": "קובץ",
"files": "קבצים",
"folder": "תיקייה",
"full documentation": "תיעוד מלא",
"items": "פריטים"
"items": "פריטים",
"modified": "שונה",
"permit": "היתר",
"seconds": "שניות",
"theme": {
"name": {
"black": "שחור",
"dark": "כהה",
"default": "ברירת מחדל",
"light": "בהיר"
}
},
"unknown device": "התקן לא ידוע",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} רוצה לשתף את התיקייה \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} רוצה לשתף את התיקייה \"{{folderlabel}}\" ({{folder}}).",
"{%reintroducer%} might reintroduce this device.": "{{reintroducer}} עשוי להציג מחדש את ההתקן הזה."
}

View File

@@ -154,7 +154,7 @@
"Failed Items": "विफल वस्तुएं",
"Failed to load file versions.": "फाइल संस्करण लोड करने में विफल।",
"Failed to load ignore patterns.": "नजरअंदाज प्रतिमान लोड करने में विफल।",
"Failed to setup, retrying": "स्थापना करने में विफल, पुनः प्रयास किया जा रहा है",
"Failed to set up, retrying": "स्थापना करने में विफल, पुनः प्रयास किया जा रहा है",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "यदि IPv6 संयोजकता नहीं है तो IPv6 सर्वर से जुड़ने में विफलता अपेक्षित है।",
"File Pull Order": "फाइल खींचने का क्रम",
"File Versioning": "फाइल संस्करणीकरण",
@@ -368,7 +368,7 @@
"Show diff with previous version": "पिछले संस्करण के साथ अंतर दिखाएं",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "समूह स्थिति में उपकरण ID के बजाय दिखाया गया। वैकल्पिक तयशुदा नाम के रूप में अन्य उपकरणों पर विज्ञापित किया जाएगा।",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "समूह स्थिति में उपकरण ID के बजाय दिखाया गया। खाली छोड़े जाने पर उपकरण द्वारा विज्ञापित नाम में अद्यतित कर दिया जाएगा।",
"Shutdown": "शटडाउन",
"Shut Down": "शटडाउन",
"Shutdown Complete": "शटडाउन पूर्ण",
"Simple": "सरल",
"Simple File Versioning": "सरल फाइल संस्करण",

View File

@@ -146,7 +146,7 @@
"Failed Items": "Hibás elemek",
"Failed to load file versions.": "Nem sikerült betölteni a fájlverziókat.",
"Failed to load ignore patterns.": "Nem sikerült betölteni a mellőzési mintákat.",
"Failed to setup, retrying": "Telepítés nem sikerült, újrapróbálkozás",
"Failed to set up, retrying": "Telepítés nem sikerült, újrapróbálkozás",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Mivel nincs IPv6 kapcsolat, ezért várhatóan nem fog sikerülni IPv6-os szerverekhez csatlakozni.",
"File Pull Order": "Fájlküldési sorrend",
"File Versioning": "Fájlverzió-követés",
@@ -345,7 +345,7 @@
"Show diff with previous version": "Előző verzió eltérésének megjelenítése",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Az eszközazonosító helyett jelenik meg. A többi eszközön alapértelmezett névként használható.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Az eszközazonosító helyett jelenik meg. Üresen hagyva az eszköz saját neve lesz alkalmazva.",
"Shutdown": "Leállítás",
"Shut Down": "Leállítás",
"Shutdown Complete": "Leállítás kész",
"Simple": "Egyszerű",
"Simple File Versioning": "Egyszerű fájlverzió-követés",

View File

@@ -146,7 +146,7 @@
"Failed Items": "Berkas yang gagal",
"Failed to load file versions.": "Gagal memuat versi berkas.",
"Failed to load ignore patterns.": "Gagal memuat pola pengabaian.",
"Failed to setup, retrying": "Gagal menyiapkan, mengulang",
"Failed to set up, retrying": "Gagal menyiapkan, mengulang",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Gagal untuk menyambung ke server IPv6 itu disangka apabila tidak ada konektivitas IPv6.",
"File Pull Order": "Urutan Penarikan Berkas",
"File Versioning": "Pemversian Berkas",
@@ -322,7 +322,7 @@
"Show diff with previous version": "Tampilkan perbedaan dengan versi sebelumnya",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Ditampilkan sebagai ganti ID Perangkat dalam status gugus. Akan diumumkan ke perangkat lain sebagai nama bawaan opsional.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Ditampilkan sebagai ganti ID Perangkat dalam status gugus. Akan diubah menjadi nama yang perangkat umumkan jika tidak diisi.",
"Shutdown": "Matikan",
"Shut Down": "Matikan",
"Shutdown Complete": "Pematian Selesai",
"Simple File Versioning": "Pemversian Berkas Sederhana",
"Single level wildcard (matches within a directory only)": "Wildcard tingkat tunggal (cocok hanya dalam satu direktori saja)",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Reti Consentite",
"Alphabetic": "Alfabetico",
"Altered by ignoring deletes.": "Modificato ignorando le eliminazioni.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre attivato quando il tipo di cartella è \"{{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.": "Il controllo versione è gestito da un comando esterno. Quest'ultimo deve rimuovere il file dalla cartella condivisa. Se il percorso dell'applicazione contiene spazi, deve essere indicato tra virgolette.",
"Anonymous Usage Reporting": "Statistiche Anonime di Utilizzo",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Il formato delle statistiche anonime di utilizzo è cambiato. Vuoi passare al nuovo formato?",
@@ -52,6 +53,7 @@
"Body:": "Corpo:",
"Bugs": "Bug",
"Cancel": "Annulla",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Non può essere abilitato se il tipo di cartella è \"{{foldertype}}\".",
"Changelog": "Registro modifiche",
"Clean out after": "Svuota dopo",
"Cleaning Versions": "Pulizia Versioni",
@@ -154,7 +156,7 @@
"Failed Items": "Elementi Errati",
"Failed to load file versions.": "Impossibile caricare le versioni dei file.",
"Failed to load ignore patterns.": "Impossibile caricare gli schemi di esclusione.",
"Failed to setup, retrying": "Configurazione fallita, riprovo",
"Failed to set up, retrying": "Configurazione fallita, riprovo",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "La connessione a server IPv6 fallisce se non c'è connettività IPv6.",
"File Pull Order": "Ordine Prelievo File",
"File Versioning": "Controllo Versione File",
@@ -368,7 +370,7 @@
"Show diff with previous version": "Mostra le differenze con la versione precedente",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Negli altri dispositivi verrà presentato come nome predefinito opzionale.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Se viene lasciato vuoto, verrà utilizzato il nome proposto dal dispositivo.",
"Shutdown": "Arresta",
"Shut Down": "Arresta",
"Shutdown Complete": "Arresto Eseguito",
"Simple": "Semplice",
"Simple File Versioning": "Controllo Versione Semplice",

View File

@@ -311,7 +311,7 @@
"Show diff with previous version": "前バージョンとの差分を表示",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "ステータス画面でデバイスIDの代わりに表示されます。他のデバイスに対してもデフォルトの名前として通知されます。",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "ステータス画面でデバイスIDの代わりに表示されます。空欄にすると相手側デバイスが通知してきた名前で更新されます。",
"Shutdown": "シャットダウン",
"Shut Down": "シャットダウン",
"Shutdown Complete": "シャットダウン完了",
"Simple File Versioning": "単純バージョン管理",
"Single level wildcard (matches within a directory only)": "ワイルドカード (単一のディレクトリ内だけでマッチします)",

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?": "익명 사용 보고의 형식이 변경되었습니다. 새 형식으로 설정을 변경하시겠습니까?",
@@ -52,6 +53,7 @@
"Body:": "내용:",
"Bugs": "버그",
"Cancel": "취소",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "{{foldertype}} 폴더 유형일 때는 활성화할 수 없습니다.",
"Changelog": "변경 기록",
"Clean out after": "보관 기간",
"Cleaning Versions": "버전 정리",
@@ -154,7 +156,7 @@
"Failed Items": "실패 항목",
"Failed to load file versions.": "파일 버전을 불러오기에 실패했습니다.",
"Failed to load ignore patterns.": "무시 양식을 불러오기에 실패했습니다.",
"Failed to setup, retrying": "설정 적용 실패; 재시도 중",
"Failed to set up, retrying": "설정 적용 실패; 재시도 중",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "IPv6에 연결되어 있지 않을 때는 IPv6 서버에 접속하지 못하는 것이 정상입니다.",
"File Pull Order": "파일 수신 순서",
"File Versioning": "파일 버전 관리",
@@ -225,6 +227,7 @@
"Learn more": "더 알아보기",
"Learn more at {%url%}": "자세한 내용은 {{url}}을 참조하십시오.",
"Limit": "제한",
"Limit Bandwidth in LAN": "근거리 통신망(LAN)에 속도 제한 적용",
"Listener Failures": "대기자 실패",
"Listener Status": "대기자 현황",
"Listeners": "대기자",
@@ -368,7 +371,7 @@
"Show diff with previous version": "이전 버전과의 diff 보기",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "기기 아이디를 대신해 기기 목록에서 나타납니다. 다른 기기에 선택적 기본값 이름으로 통보됩니다.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "기기 아이디를 대신해 기기 목록에서 나타납니다. 비워 둘 경우 다른 기기에서 통보받은 이름으로 갱신됩니다.",
"Shutdown": "종료",
"Shut Down": "종료",
"Shutdown Complete": "종료 완료",
"Simple": "간단",
"Simple File Versioning": "간단한 파일 버전 관리",

View File

@@ -6,11 +6,14 @@
"About": "Apie programą",
"Action": "Veiksmas",
"Actions": "Veiksmai",
"Active filter rules": "Aktyvios filtro taisyklės",
"Add": "Pridėti",
"Add Device": "Pridėti įrenginį",
"Add Folder": "Pridėti aplanką",
"Add Remote Device": "Pridėti nuotolinį įrenginį",
"Add devices from the introducer to our device list, for mutually shared folders.": "Pridėti įrenginius iš supažindintojo į mūsų įrenginių sąrašą, siekiant abipusiškai bendrinti aplankus.",
"Add filter entry": "Pridėti filtro įrašą",
"Add ignore patterns": "Pridėti ignoravimo šablonų",
"Add new folder?": "Pridėti naują aplanką?",
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Pilnas nuskaitymo iš naujo intervalas bus papildomai padidintas (60 kartų, t.y. nauja numatytoji 1 val. reikšmė). Taip pat vėliau, pasirinkę Ne, galite jį konfigūruoti rankiniu būdu kiekvienam atskiram aplankui.",
"Address": "Adresas",
@@ -45,6 +48,7 @@
"Automatically create or share folders that this device advertises at the default path.": "Automatiškai sukurti ar bendrinti aplankus, kuriuos šis įrenginys skelbia numatytajame kelyje.",
"Available debug logging facilities:": "Prieinamos derinimo registravimo priemonės:",
"Be careful!": "Būkite atsargūs!",
"Body:": "Turinys:",
"Bugs": "Klaidos",
"Cancel": "Atsisakyti",
"Changelog": "Keitinių žurnalas",
@@ -63,6 +67,7 @@
"Connection Management": "Ryšių valdymas",
"Connection Type": "Ryšio tipas",
"Connections": "Ryšiai",
"Connections via relays might be rate limited by the relay": "Ryšiai per tarpinius mazgus gali būti ribojami pagal užklausų skaičių per laiko vienetą",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Pastoviai stebėti pakeitimus dabar galima Syncthing viduje. Tai aptiks pakeitimus jūsų diske ir paleis nuskaitymą tik modifikuotuose keliuose. Pranašumas yra tas, kad pakeitimai sklis greičiau ir reikės mažiau pilnų nuskaitymų.",
"Copied from elsewhere": "Nukopijuota iš kitur",
"Copied from original": "Nukopijuota iš originalo",
@@ -139,7 +144,7 @@
"Failed Items": "Nepavykę siuntimai",
"Failed to load file versions.": "Nepavyko įkelti failo versijų.",
"Failed to load ignore patterns.": "Nepavyko įkelti nepaisymo šablonų.",
"Failed to setup, retrying": "Nepavyko nustatyti, bandoma iš naujo",
"Failed to set up, retrying": "Nepavyko nustatyti, bandoma iš naujo",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Nesėkmė prisijungti prie IPv6 serverių yra tikėtina, jei nėra IPv6 ryšio.",
"File Pull Order": "Failų siuntimo tvarka",
"File Versioning": "Versijų valdymas",
@@ -332,7 +337,7 @@
"Show diff with previous version": "Rodyti skirtumus su ankstesne versija",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Grupės būsenoje rodomas vietoje įrenginio vardo. Kiti įrenginiai matys kaip pasirinktinį vardą.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Grupės būsenoje rodomas vietoje įrenginio vardo. Bus atnaujintas į įrenginio vardą jei nieko neįrašysite.",
"Shutdown": "Išjungti",
"Shut Down": "Išjungti",
"Shutdown Complete": "Sėkmingai išjungta",
"Simple File Versioning": "Supaprastintas versijų valdymas",
"Single level wildcard (matches within a directory only)": "Vieno lygio pakaitos simbolis (atitinka tik vieną katalogo lygį)",

View File

@@ -154,7 +154,7 @@
"Failed Items": "Elementsynkronisering som har mislyktes",
"Failed to load file versions.": "Lasting av fil-versjoner feilet.",
"Failed to load ignore patterns.": "Lasting av ignorer mønstre feilet.",
"Failed to setup, retrying": "Klarte ikke å utføre oppsett, prøver igjen",
"Failed to set up, retrying": "Klarte ikke å utføre oppsett, prøver igjen",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Å ikke klare å koble til IPv6-tjenere er forventet hvis det ikke er noen IPv6-tilknytning.",
"File Pull Order": "Filenes henterekkefølge",
"File Versioning": "Versjonskontroll",
@@ -339,7 +339,7 @@
"Show diff with previous version": "Vis diff med forrige version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vis i stedet for enhets-ID i gruppestatus. Vil bli kringkastet til andre enheter som et valgfritt forvalgsnavn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i stedet for mappe-ID i gruppestatus. Vil bli oppdatert til navnet enheten kringkaster dersom tomt.",
"Shutdown": "Avslutt",
"Shut Down": "Avslutt",
"Shutdown Complete": "Avslutning fullført",
"Simple": "Enkel",
"Simple File Versioning": "Enkel versjonskontroll",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Toegestane netwerken",
"Alphabetic": "Alfabetisch",
"Altered by ignoring deletes.": "Veranderd door het negeren van verwijderingen.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Altijd aanzetten als het map-type \"{{foldertype}}\" is.",
"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.": "Een externe opdracht regelt het versiebeheer. Hij moet het bestand verwijderen uit de gedeelde map. Als het pad naar de toepassing spaties bevat, moet dit tussen aanhalingstekens geplaatst worden.",
"Anonymous Usage Reporting": "Anonieme gebruikersstatistieken",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Het formaat voor anonieme gebruikersrapporten is gewijzigd. Wil je naar het nieuwe formaat overschakelen?",
@@ -52,6 +53,7 @@
"Body:": "Inhoud:",
"Bugs": "Bugs",
"Cancel": "Annuleren",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kan niet aangezet worden als het map-type \"{{foldertype}}\" is.",
"Changelog": "Wijzigingenlogboek",
"Clean out after": "Opruimen na",
"Cleaning Versions": "Versies opruimen",
@@ -154,7 +156,7 @@
"Failed Items": "Mislukte items",
"Failed to load file versions.": "Laden van bestandsversies mislukt.",
"Failed to load ignore patterns.": "Laden van negeerpatronen mislukt.",
"Failed to setup, retrying": "Instellen mislukt, opnieuw proberen",
"Failed to set up, retrying": "Instellen mislukt, opnieuw proberen",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Als er geen IPv6-connectiviteit is worden problemen bij verbinden met IPv6-servers verwacht.",
"File Pull Order": "Volgorde voor binnenhalen van bestanden",
"File Versioning": "Versiebeheer",
@@ -225,8 +227,9 @@
"Learn more": "Lees meer",
"Learn more at {%url%}": "Meer informatie op {{url}}",
"Limit": "Begrenzing",
"Listener Failures": "Luisteraarfouten",
"Listener Status": "Luisteraarstatus",
"Limit Bandwidth in LAN": "Beperk de bandbreedte op het lokale netwerk",
"Listener Failures": "Luisteraarsfouten",
"Listener Status": "Luisteraarsstatus",
"Listeners": "Luisteraars",
"Loading data...": "Gegevens laden...",
"Loading...": "Laden...",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Verschil met vorige versie weergeven",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Weergegeven in plaats van de apparaat-ID in de cluster-status. Zal aan andere apparaten voorgesteld worden als een optionele standaardnaam.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Weergegeven in plaats van de apparaat-ID in de clusterstatus. Zal bijgewerkt worden met de naam die het apparaat voorstelt wanneer leeg gelaten.",
"Shutdown": "Afsluiten",
"Shut Down": "Afsluiten",
"Shutdown Complete": "Afsluiten voltooid",
"Simple": "Eenvoudig",
"Simple File Versioning": "Eenvoudig versiebeheer",
@@ -386,6 +389,7 @@
"Staggered File Versioning": "Gespreid versiebeheer",
"Start Browser": "Browser starten",
"Statistics": "Statistieken",
"Stay logged in": "Blijf aangemeld",
"Stopped": "Gestopt",
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "Bewaart en synchroniseert alleen versleutelde gegevens. Mappen op alle verbonden apparaten moeten met hetzelfde wachtwoord ingesteld worden of ook van het type \"{{receiveEncrypted}}\" zijn.",
"Subject:": "Onderwerp:",

View File

@@ -187,7 +187,7 @@
"Show QR": "Vis QR",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vist i staden for einings-ID-en i klyngjestatusen. Vil verta kringkasta til dei andre einingane som eit valfritt standardnamn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i staden for mappe-ID-en i klyngjestatuses. Vil verta oppdatert til namnet eininga kringkastar dersom tomt.",
"Shutdown": "Slå Av",
"Shut Down": "Slå Av",
"Shutdown Complete": "Slått av",
"Simple File Versioning": "Enkel filutgåvehandtering",
"Single level wildcard (matches within a directory only)": "Enkeltnivå-jokerteikn (søkjer berre i éi mappe)",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Dozwolone sieci",
"Alphabetic": "Alfabetycznie",
"Altered by ignoring deletes.": "Zmieniono przez ignorowanie usuniętych",
"Always turned on when the folder type is \"{%foldertype%}\".": "Zawsze włączone, gdy typ folderu to \"{{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.": "Zewnętrzne polecenie odpowiedzialne jest za wersjonowanie. Musi ono usunąć plik ze współdzielonego folderu. Jeżeli ścieżka do aplikacji zawiera spacje, to powinna ona być zamknięta w cudzysłowie.",
"Anonymous Usage Reporting": "Anonimowe statystyki użycia",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Format anonimowych statystyk użycia uległ zmianie. Czy chcesz przejść na nowy format?",
@@ -52,6 +53,7 @@
"Body:": "Treść:",
"Bugs": "Błędy",
"Cancel": "Anuluj",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Nie można włączyć, jeśli typem folderu jest \"{{foldertype}}\".",
"Changelog": "Historia zmian",
"Clean out after": "Opróżnij po",
"Cleaning Versions": "Czyszczenie wersji",
@@ -154,7 +156,7 @@
"Failed Items": "Elementy zakończone niepowodzeniem",
"Failed to load file versions.": "Nie udało się załadować wersji plików.",
"Failed to load ignore patterns.": "Nie udało się załadować wzorców ignorowania.",
"Failed to setup, retrying": "Nie udało się ustawić; ponawiam próbę",
"Failed to set up, retrying": "Nie udało się ustawić; ponawiam próbę",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Błąd połączenia do serwerów IPv6 może wystąpić, gdy w ogóle nie ma połączenia po IPv6.",
"File Pull Order": "Kolejność pobierania plików",
"File Versioning": "Wersjonowanie plików",
@@ -225,6 +227,7 @@
"Learn more": "Dowiedz się więcej",
"Learn more at {%url%}": "Dowiedz się więcej na {{url}}",
"Limit": "Ograniczenie",
"Limit Bandwidth in LAN": "Ogranicz przepustowość w sieci lokalnej LAN",
"Listener Failures": "Błędy nasłuchujących",
"Listener Status": "Stan nasłuchujących",
"Listeners": "Nasłuchujący",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Pokaż diff z poprzednią wersją",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Będzie anonsowana do innych urządzeń jako opcjonalna nazwa domyślna.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Zostanie zaktualizowana do nazwy anonsowanej przez urządzenie, jeżeli pozostanie pusta.",
"Shutdown": "Wyłącz",
"Shut Down": "Wyłącz",
"Shutdown Complete": "Wyłączanie ukończone",
"Simple": "Proste",
"Simple File Versioning": "Proste wersjonowanie plików",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Redes permitidas",
"Alphabetic": "Alfabética",
"Altered by ignoring deletes.": "Alterado ignorando exclusões.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre ativado quando o tipo de pasta for \"{{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.": "Um comando externo controla o controle de versão. Tem que remover o arquivo da pasta compartilhada. Se o caminho para o aplicativo contiver espaços, ele deve ser colocado entre aspas.",
"Anonymous Usage Reporting": "Relatórios anônimos de uso",
"Anonymous usage report format has changed. Would you like to move to the new format?": "O formato do relatório anônimo de uso mudou. Gostaria de usar o formato novo?",
@@ -52,6 +53,7 @@
"Body:": "Corpo:",
"Bugs": "Erros",
"Cancel": "Cancelar",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Não pode ser ativado se o tipo de pasta for \"{{foldertype}}\".",
"Changelog": "Registro de alterações",
"Clean out after": "Limpar depois de",
"Cleaning Versions": "Limpando Versões",
@@ -154,7 +156,7 @@
"Failed Items": "Itens com falha",
"Failed to load file versions.": "Falha ao carregar versões do arquivo.",
"Failed to load ignore patterns.": "Falha ao carregar os padrões para ignorar.",
"Failed to setup, retrying": "Não foi possível configurar, tentando novamente",
"Failed to set up, retrying": "Não foi possível configurar, tentando novamente",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Falhas na conexão a servidores IPv6 são esperadas caso não haja conectividade IPv6.",
"File Pull Order": "Ordem de retirada do arquivo",
"File Versioning": "Versionamento de arquivos",
@@ -368,7 +370,7 @@
"Show diff with previous version": "Mostrar diferenças da versão anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrado no lugar do ID do dispositivo no indicador de estado do grupo. Será divulgado aos outros dispositivos como um nome opcional e pré-definido.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrado no lugar do ID do dispositivo no indicador de estado do grupo. Será atualizado para o nome que o dispositivo divulga, caso seja deixado em branco.",
"Shutdown": "Desligar",
"Shut Down": "Desligar",
"Shutdown Complete": "Desligamento completado",
"Simple": "Simples",
"Simple File Versioning": "Simples",

View File

@@ -27,6 +27,7 @@
"Allowed Networks": "Redes permitidas",
"Alphabetic": "Alfabética",
"Altered by ignoring deletes.": "Alterada por terem sido ignoradas as eliminações.",
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre ligado quando o tipo de pasta é \"{{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.": "Um comando externo gere as versões. Esse comando tem que remover o ficheiro da pasta partilhada. Se o caminho para a aplicação contiver espaços, então terá de o escrever entre aspas.",
"Anonymous Usage Reporting": "Enviar relatórios anónimos de utilização",
"Anonymous usage report format has changed. Would you like to move to the new format?": "O formato do relatório anónimo de utilização foi alterado. Gostaria de mudar para o novo formato?",
@@ -52,6 +53,7 @@
"Body:": "Corpo:",
"Bugs": "Erros",
"Cancel": "Cancelar",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Não pode ser habilitado quando o tipo de pasta é \"{{foldertype}}\".",
"Changelog": "Registo de alterações",
"Clean out after": "Esvaziar ao fim de",
"Cleaning Versions": "Limpando versões",
@@ -154,7 +156,7 @@
"Failed Items": "Itens que falharam",
"Failed to load file versions.": "Falha ao carregar as versões do ficheiro.",
"Failed to load ignore patterns.": "Falha ao carregar os padrões de exclusão.",
"Failed to setup, retrying": "A preparação falhou, a tentar novamente",
"Failed to set up, retrying": "A preparação falhou, a tentar novamente",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "São esperadas falhas na ligação a servidores IPv6 se não existir conectividade IPv6.",
"File Pull Order": "Ordem de obtenção de ficheiros",
"File Versioning": "Gestão de versões de ficheiros",
@@ -368,7 +370,7 @@
"Show diff with previous version": "Mostrar diferenças em relação à versão anterior",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será divulgado aos outros dispositivos como um nome predefinido opcional.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será actualizado para o nome que o dispositivo divulga, se for deixado em branco.",
"Shutdown": "Desligar",
"Shut Down": "Desligar",
"Shutdown Complete": "Encerramento completado",
"Simple": "Simples",
"Simple File Versioning": "Simples",

View File

@@ -26,6 +26,7 @@
"Allow Anonymous Usage Reporting?": "Permiteţi raportarea anonimă de folosire a aplicaţiei?",
"Allowed Networks": "Rețele permise",
"Alphabetic": "Alfabetic",
"Altered by ignoring deletes.": "Modificat prin ignorarea ștergerilor.",
"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.": "O comandă externă gestionează versiunea. Trebuie să elimine fișierul din mapa partajat. Dacă calea către aplicație conține spații, ar trebui să fie pusă între ghilimele.",
"Anonymous Usage Reporting": "Raport Anonim despre Folosirea Aplicației",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formatul raportului de utilizare anonim s-a schimbat. Doriți să vă mutați în noul format?",
@@ -143,7 +144,6 @@
"Error": "Eroare",
"External File Versioning": "Administrare externă a versiunilor documentului",
"Failed Items": "Failed Items",
"Failed to setup, retrying": "Failed to setup, retrying",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "File Pull Order",
"File Versioning": "Versiune Fișier",
@@ -312,7 +312,7 @@
"Show diff with previous version": "Show diff with previous version",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vizibil în locul ID-ului dispozitivului într-un grup. Va fi sugerat celorlalte dispozitive ca nume opţional. ",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vizibil în locul ID-ului dispozitivului într-un grup. Va fi înlocuit de numele sugerat de dispozitiv daca nu este completat. ",
"Shutdown": "Opreşte",
"Shut Down": "Opreşte",
"Shutdown Complete": "Oprește Complet",
"Simple File Versioning": "Versiuni simple ale documentelor",
"Single level wildcard (matches within a directory only)": "Asterisc de nivel simplu (corespunde doar unui fişier)",

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?": "Формат анонимных отчётов изменился. Хотите переключиться на новый формат?",
@@ -52,6 +53,7 @@
"Body:": "Тело:",
"Bugs": "Ошибки",
"Cancel": "Отмена",
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Не может быть включено для папок с типом «{{foldertype}}».",
"Changelog": "Журнал изменений",
"Clean out after": "Очистить после",
"Cleaning Versions": "Очистка версий",
@@ -154,7 +156,7 @@
"Failed Items": "Сбойные объекты",
"Failed to load file versions.": "Не удалось загрузить версии файлов.",
"Failed to load ignore patterns.": "Не удалось загрузить шаблоны игнорирования.",
"Failed to setup, retrying": "Не удалось настроить, пробуем ещё",
"Failed to set up, retrying": "Не удалось настроить, пробуем ещё",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Если нет IPv6-соединений, при подключении к IPv6-серверам произойдёт ошибка.",
"File Pull Order": "Порядок получения файлов",
"File Versioning": "Управление версиями",
@@ -171,8 +173,8 @@
"Folder Path": "Путь к папке",
"Folder Status": "Статус папки",
"Folder Type": "Тип папки",
"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}}» не может быть изменён после добавления. Вам необходимо убрать папку, удалить или дешифровать данные на диске, а затем снова добавить папку.",
"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.": "Для следующих папок произошла ошибка при запуске отслеживания изменений. Попытки будут повторяться раз в минуту, и ошибки скоро могут быть устранены. Если этого не произойдёт, попробуйте разобраться в причинах и попросите поддержки, если у вас не получится.",
"Forever": "Вечно",
@@ -225,6 +227,7 @@
"Learn more": "Узнать больше",
"Learn more at {%url%}": "Узнать больше на сайте {{url}}",
"Limit": "Ограничение",
"Limit Bandwidth in LAN": "Ограничить пропускную способность в локальной сети",
"Listener Failures": "Ошибки прослушивателя",
"Listener Status": "Статус прослушивателя",
"Listeners": "Прослушиватель",
@@ -368,7 +371,7 @@
"Show diff with previous version": "Показать различия с предыдущей версией",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Отображается вместо ID устройства в статусе группы. Будет разослан другим устройствам в качестве имени по умолчанию.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Отображается вместо ID устройства в статусе группы. Если поле не заполнено, то будет установлено имя, передаваемое этим устройством.",
"Shutdown": "Выключить",
"Shut Down": "Выключить",
"Shutdown Complete": "Выключение",
"Simple": "Просто",
"Simple File Versioning": "Простое управление версиями файлов",

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