Compare commits

..

38 Commits

Author SHA1 Message Date
Jakob Borg
ad8c266f76 Update docs & translation 2015-11-15 18:15:10 +01:00
Jakob Borg
807c3bdcc7 Merge pull request #2473 from syncthing/revert-2470-nostoppedrescan
Revert "Don't show "Rescan" button for stopped folders"
2015-11-14 21:10:52 +01:00
Audrius Butkevicius
62efbd17de Revert "Don't show "Rescan" button for stopped folders" 2015-11-14 14:01:22 -05:00
Audrius Butkevicius
d99350fd61 Merge pull request #2470 from calmh/nostoppedrescan
Don't show "Rescan" button for stopped folders
2015-11-14 09:09:28 -05:00
Jakob Borg
40c70a9a2a Don't show "Rescan" button for stopped folders 2015-11-14 12:14:09 +01:00
Audrius Butkevicius
8fb7f40a6a Merge pull request #2468 from calmh/removefolder
Remove folder without restart (fixes #2262)
2015-11-13 09:51:58 -05:00
Jakob Borg
2f12d41d9d Don't dirty blockmap key between lookups (fixes #2455) 2015-11-13 15:44:30 +01:00
Jakob Borg
9fbdb6b305 Cancel a running scan 2015-11-13 15:30:21 +01:00
Jakob Borg
73285cadb6 Remove folder without restart (fixes #2262) 2015-11-13 13:32:52 +01:00
Jakob Borg
56f1c295b6 Merge pull request #2462 from AudriusButkevicius/mtimes
Use virtualMtime when deciding if a file is up to date
2015-11-12 08:48:45 +01:00
Jakob Borg
7f76ed8413 Fix build 2015-11-12 08:46:13 +01:00
AudriusButkevicius
f7edd36931 Use virtualMtime when deciding if a file is up to date 2015-11-12 03:40:06 +00:00
Audrius Butkevicius
c39f2b7c05 Merge pull request #2463 from boone/fix_typos
Fix typos.
2015-11-11 21:29:34 -05:00
Mike Boone
342036408e Fix typos. 2015-11-11 21:20:34 -05:00
Jakob Borg
f4904fce17 Merge pull request #2449 from Stefan-Code/upgrade-system
made upgrade-system smarter (fixes #2446)
2015-11-10 21:15:02 +01:00
Stefan Kuntz
2abb2de753 Made upgrade-system smarter (fixes #2446) 2015-11-10 17:41:50 +01:00
Jakob Borg
ef0a0db07e More local discovery URL debugging (ref #2444) 2015-11-10 10:16:55 +01:00
Jakob Borg
a45795efec Add tylerbrazier 2015-11-10 08:20:16 +01:00
Jakob Borg
88ae353aef Merge pull request #2443 from tylerbrazier/master
Audit logins with new Login event (fixes #2377)
2015-11-10 08:19:03 +01:00
Tyler Brazier
97b9690711 Audit logins with new LoginAttempt event (fixes #2377) 2015-11-10 00:49:51 -05:00
Audrius Butkevicius
48ce356d5c Merge pull request #2448 from calmh/connhandling
Refactor out methods resolveAddresses, connectDirect, connectViaRelay
2015-11-09 22:01:06 -05:00
Audrius Butkevicius
92451f94bc Merge pull request #2450 from syncthing/Zillode-patch-1
Correct commentary for ConnectionStats
2015-11-09 18:32:19 -05:00
Zillode
593632045d Correct commentary for ConnectionStats
Related to https://github.com/syncthing/syncthing-android/issues/473 and 944d9c84a0
ConnectionStats returns connection information for all devices, even when disconnected.
2015-11-09 23:58:06 +01:00
Jakob Borg
e3c55ef307 Fix address list in DeviceDiscovered, add debug prints (ref #2444) 2015-11-09 21:36:17 +01:00
Jakob Borg
edf1730fd2 Merge pull request #2447 from alex2108/master
Add default-v4 and default-v6 as options for discovery
2015-11-09 16:02:37 +01:00
Alexander Graf
34cd8e3f95 Add default-v4 and default-v6 as options for discovery 2015-11-09 15:56:46 +01:00
Jakob Borg
242cce022a Refactor out methods resolveAddresses, connectDirect, connectViaRelay 2015-11-09 15:35:32 +01:00
Jakob Borg
19bf51cefb Revert "Merge pull request #2440 from Stefan-Code/master"
This reverts commit 81bc6bf34b, reversing
changes made to 7de736e8d0.

Unfortunately this tricks the upgrade system into picking the wrong
binary. We need to fix the upgrade system before merging this.
2015-11-09 14:23:26 +01:00
Jakob Borg
74a2e80142 Update docs & translations 2015-11-09 14:00:10 +01:00
Jakob Borg
b9b630e3b6 Change certificate on discovery-2 2015-11-09 13:58:44 +01:00
Jakob Borg
f0bdf833d1 Oh come *on* 2015-11-09 12:39:09 +01:00
Jakob Borg
81bc6bf34b Merge pull request #2440 from Stefan-Code/master
Added ufw firewall application preset
2015-11-09 12:19:42 +01:00
Jakob Borg
7de736e8d0 Ok then, lower case 2015-11-09 12:17:23 +01:00
Jakob Borg
cd097e0fce Add Stefan-Code 2015-11-09 12:14:32 +01:00
Stefan-Code
cc81a7ccfe added ufw firewall application preset (fixes #2435) 2015-11-09 11:58:59 +01:00
Jakob Borg
58d320c270 String slice formatting 2015-11-08 18:06:06 +01:00
Jakob Borg
59565fd1d1 Woops 2015-11-07 11:25:00 +01:00
Jakob Borg
55592137a2 Use constructor functions for FolderConfiguration and DeviceConfiguration 2015-11-07 09:50:04 +01:00
51 changed files with 680 additions and 424 deletions

View File

@@ -61,10 +61,12 @@ Piotr Bejda <piotrb10@gmail.com>
Ryan Sullivan <kayoticsully@gmail.com>
Sergey Mishin <ralder@yandex.ru>
Stefan Tatschner <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org>
Stefan Kuntz <stefan.github@gmail.com> <Stefan.github@gmail.com>
Tim Abell <tim@timwise.co.uk>
Tobias Nygren <tnn@nygren.pp.se>
Tomas Cerveny <kozec@kozec.com>
Tully Robinson <tully@tojr.org>
Tyler Brazier <tyler@tylerbrazier.com>
Veeti Paananen <veeti.paananen@rojekti.fi>
Vil Brekin <vilbrekin@gmail.com>
Yannic A. <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>

2
NICKS
View File

@@ -7,6 +7,7 @@ LordLandon <lordlandon@gmail.com>
Moter8 <moter8@gmail.com>
Nutomic <me@nutomic.com>
Rewt0r <rewt0r@gmx.com> <Rewt0r@users.noreply.github.com>
Stefan-Code <stefan.github@gmail.com> <Stefan.github@gmail.com>
Vilbrekin <vilbrekin@gmail.com>
Zillode <zillode@zillode.be>
acogdev <jake@acogdev.com>
@@ -64,6 +65,7 @@ simplypeachy <aD@simplypeachy.co.uk> <simplypeachy@users.noreply.github.com>
timabell <tim@timwise.co.uk>
tnn2 <tnn@nygren.pp.se>
tojrobinson <tully@tojr.org>
tylerbrazier <tyler@tylerbrazier.com>
uok <ueomkail@gmail.com> <uok@users.noreply.github.com>
veeti <veeti.paananen@rojekti.fi>
wsgcsysadmin <e.meitner@willystreet.coo>

View File

@@ -15,6 +15,7 @@ import (
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/sync"
"golang.org/x/crypto/bcrypt"
)
@@ -24,6 +25,13 @@ var (
sessionsMut = sync.NewMutex()
)
func emitLoginAttempt(success bool, username string) {
events.Default.Log(events.LoginAttempt, map[string]interface{}{
"success": success,
"username": username,
})
}
func basicAuthAndSessionMiddleware(cookieName string, cfg config.GUIConfiguration, next http.Handler) http.Handler {
apiKey := cfg.APIKey()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -70,12 +78,15 @@ func basicAuthAndSessionMiddleware(cookieName string, cfg config.GUIConfiguratio
return
}
if string(fields[0]) != cfg.User {
username := string(fields[0])
if username != cfg.User {
emitLoginAttempt(false, username)
error()
return
}
if err := bcrypt.CompareHashAndPassword([]byte(cfg.Password), fields[1]); err != nil {
emitLoginAttempt(false, username)
error()
return
}
@@ -90,6 +101,7 @@ func basicAuthAndSessionMiddleware(cookieName string, cfg config.GUIConfiguratio
MaxAge: 0,
})
emitLoginAttempt(true, username)
next.ServeHTTP(w, r)
})
}

View File

@@ -621,7 +621,10 @@ func syncthingMain() {
}
protectedFiles := []string{
locations[locDatabase], locations[locConfigFile], locations[locCertFile], locations[locKeyFile],
locations[locDatabase],
locations[locConfigFile],
locations[locCertFile],
locations[locKeyFile],
}
// Remove database entries for folders that no longer exist in the config
@@ -904,25 +907,19 @@ func setupGUI(mainSvc *suture.Supervisor, cfg *config.Wrapper, m *model.Model, a
}
func defaultConfig(myName string) config.Configuration {
defaultFolder := config.NewFolderConfiguration("default", locations[locDefFolder])
defaultFolder.RescanIntervalS = 60
defaultFolder.MinDiskFreePct = 1
defaultFolder.Devices = []config.FolderDeviceConfiguration{{DeviceID: myID}}
defaultFolder.AutoNormalize = true
defaultFolder.MaxConflicts = -1
thisDevice := config.NewDeviceConfiguration(myID, myName)
thisDevice.Addresses = []string{"dynamic"}
newCfg := config.New(myID)
newCfg.Folders = []config.FolderConfiguration{
{
ID: "default",
RawPath: locations[locDefFolder],
RescanIntervalS: 60,
MinDiskFreePct: 1,
Devices: []config.FolderDeviceConfiguration{{DeviceID: myID}},
AutoNormalize: true,
MaxConflicts: -1,
},
}
newCfg.Devices = []config.DeviceConfiguration{
{
DeviceID: myID,
Addresses: []string{"dynamic"},
Name: myName,
},
}
newCfg.Folders = []config.FolderConfiguration{defaultFolder}
newCfg.Devices = []config.DeviceConfiguration{thisDevice}
port, err := getFreePort("127.0.0.1", 8384)
if err != nil {

View File

@@ -182,7 +182,7 @@ func reportData(cfg *config.Wrapper, m *model.Model) map[string]interface{} {
defaultAnnounceServersDNS, defaultAnnounceServersIP, otherAnnounceServers := 0, 0, 0
for _, addr := range cfg.Options().GlobalAnnServers {
if addr == "default" {
if addr == "default" || addr == "default-v4" || addr == "default-v6" {
defaultAnnounceServersDNS++
} else if stringIn(addr, config.DefaultDiscoveryServersIP) {
defaultAnnounceServersIP++

View File

@@ -149,6 +149,16 @@ func (s *verboseSvc) formatEvent(ev events.Event) string {
data := ev.Data.(map[string][]string)
newRelays := data["new"]
return fmt.Sprintf("Relay state changed; connected relay(s) are %s.", strings.Join(newRelays, ", "))
case events.LoginAttempt:
data := ev.Data.(map[string]interface{})
username := data["username"].(string)
var success string
if data["success"].(bool) {
success = "successful"
} else {
success = "failed"
}
return fmt.Sprintf("Login %s for username %s.", success, username)
}

View File

@@ -1,8 +1,8 @@
{
"A negative number of days doesn't make sense.": "Няма логика на зададен отрицателен брой дни.",
"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": "За програмата",
"Actions": "Действия",
"Add": "Добави",
"Add Device": "Добави устройство",
@@ -13,36 +13,36 @@
"Advanced": "Допълнителни",
"Advanced Configuration": "Допълнителни настройки",
"All Data": "Всички данни",
"Allow Anonymous Usage Reporting?": "Разреши анонимен доклад за ползване на програмата?",
"Allow Anonymous Usage Reporting?": "Разреши анонимно докладване за употребата на програмата?",
"Alphabetic": "Азбучен ред",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Друга команда се занимава с версиите. Тази команда трябва да премахни файла от синхронизираната папка.",
"Anonymous Usage Reporting": "Анонимен Доклад",
"Anonymous Usage Reporting": "Анонимен доклад",
"Any devices configured on an introducer device will be added to this device as well.": "Устройства настроени на introducer компютъра също ще бъдат добавени към този компютър.",
"Automatic upgrades": "Автоматични ъпдейти",
"Be careful!": "Внимавай!",
"Automatic upgrades": "Автоматично обновяване",
"Be careful!": "Внимание!",
"Bugs": "Бъгове",
"CPU Utilization": "Натоварване на Процесора",
"Changelog": "Сипъск с промени",
"CPU Utilization": "Процесор в употреба",
"Changelog": "Списък с промени",
"Clean out after": "Изчисти след",
"Close": "Затвори",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, използван в началото на реда",
"Compression": "Компресия",
"Connection Error": "Грешка при Свързването",
"Compression": "Компресиране",
"Connection Error": "Грешка при свързването",
"Copied from elsewhere": "Копиране от някъде другаде",
"Copied from original": "Копиран от оригинала",
"Copyright © 2015 the following Contributors:": "Правата запазени © 2015 Сътрудници:",
"Copyright © 2015 the following Contributors:": "Всички правата запазени © 2015 Сътрудници:",
"Delete": "Изтрий",
"Deleted": "Изтрито",
"Device ID": "Идентификатор на устройство",
"Device Identification": "Идентификация на устройство",
"Device Identification": "Идентификатор на устройство",
"Device Name": "Име на устройство",
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Устройство {{device}} ({{address}}) желае да се свърже. Добави ново устройство?",
"Devices": "Устройства",
"Disconnected": "Прекрати Връзката",
"Disconnected": "Не е свързано",
"Discovery": "Откриване",
"Documentation": "Документация",
"Download Rate": "Скорост на Теглене",
"Download Rate": "Скорост на сваляне",
"Downloaded": "Изтеглен",
"Downloading": "Изтегляне",
"Edit": "Промени",
@@ -50,49 +50,49 @@
"Edit Folder": "Промени папка",
"Editing": "Променяне",
"Enable UPnP": "Включи UPnP",
"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 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.": "Добави шаблони за игнориране, по един на ред.",
"Error": "Грешка",
"External File Versioning": "Външно упраление на версиите",
"External File Versioning": "Външно управление на версиите",
"Failed Items": "Неуспешни",
"File Pull Order": "По ред на дърпане",
"File Versioning": "Файлови Версии",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Битовете за права за достъп са игнорирани, когато се проверява за промени. Използвай с файлови системи тип FAT.",
"File Pull Order": "Ред на сваляне",
"File Versioning": "Версии на файловете",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Битовете за права за достъп ще бъдат игнорирани, когато се проверява за промени. Ползвайте за файлови системи тип FAT.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Файловете биват преместени в .stversions папка, когато са заменен или изтрити от Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Когато syncthing замени или изтрие файл той се премества в .stversions и преименува с дабавени дата и час.",
"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 moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Когато syncthing замени или изтрие файл той се премества в .stversions и преименува с набавени дата и час.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Защитава файловете от промени направени на други устройства, но промените направени на това устройство ще бъдат синхронизирани с останалите устройства.",
"Folder": "Папка",
"Folder ID": "Идентификатор на папка",
"Folder ID": "Идентификатор на папката",
"Folder Master": "Главна папка",
"Folder Path": "Път до папката",
"Folders": "Папки",
"GUI": "Потребителски интефейс",
"GUI Authentication Password": "Парола за Потребителския Интерфейс",
"GUI Authentication User": "Потребител за Потребителския Интерфейс",
"GUI Listen Addresses": "Адрес за Свързване с Потребителския Интерфейс",
"GUI": "Потребителски интерфейс",
"GUI Authentication Password": "Парола за потребителския интерфейс",
"GUI Authentication User": "Потребител за потребителския интерфейс",
"GUI Listen Addresses": "Адрес за свързване с потребителския интерфейс",
"Generate": "Генерирай",
"Global Discovery": "Глобавно Откриване",
"Global Discovery Server": "Сървър за Глобално Откриване",
"Global Discovery": "Глобално откриване",
"Global Discovery Server": "Сървър за глобално откриване",
"Global State": "Глобално състояние",
"Help": "Помощ",
"Home page": "Начална страница",
"Ignore": "Игнорирай",
"Ignore Patterns": "Шаблони за Игнориране",
"Ignore Permissions": "Игнорирай Права за Достъп",
"Incoming Rate Limit (KiB/s)": "Входящ Лимит на Скоростта (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Неправилни настройки могат да повредят съдържанието на папката и да попречат на по-нататъшно синхронизиране.",
"Ignore Patterns": "Шаблони за игнориране",
"Ignore Permissions": "Игнорирай правата за достъп",
"Incoming Rate Limit (KiB/s)": "Входящ лимит на скоростта (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Неправилни настройки могат да повредят файловете и да попречат на синхронизирането.",
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Обратното на даденото условие (пр. не изключвай)",
"Keep Versions": "Пази Версии",
"Largest First": "Най-големите първо",
"Keep Versions": "Пази версии",
"Largest First": " Първо най-големите",
"Last File Received": "Последния получен файл",
"Last seen": "Последно видян",
"Later": "По-късно",
"Local Discovery": "Локално Откриване",
"Local Discovery": "Локално откриване",
"Local State": "Локално състояние",
"Local State (Total)": "Локално Състояние (Общо)",
"Local State (Total)": "Локално състояние (Общо)",
"Major Upgrade": "Основно Обновяване",
"Maximum Age": "Максимална Възраст",
"Maximum Age": "Максимална възраст",
"Metadata Only": "Само мета информация",
"Minimum Free Disk Space": "Минимално свободно дисково пространство",
"Move to top of queue": "Премести в началото на опашката",
@@ -100,66 +100,66 @@
"Never": "Никога",
"New Device": "Ново устройство",
"New Folder": "Нова папка",
"Newest First": "Най-новите първо",
"Newest First": "Първо най-новите",
"No": "Не",
"No File Versioning": "Няма Файлови Версии",
"No File Versioning": "Без версии",
"Notice": "Известие",
"OK": "ОК",
"Off": "Изключено",
"Oldest First": "Най-старите първо",
"Oldest First": "Първо най-старите",
"Options": "Настройки",
"Out of Sync": "Не синхронизиран",
"Out of Sync": "Несинхронизирано",
"Out of Sync Items": "Несинхронизирани елементи",
"Outgoing Rate Limit (KiB/s)": "Лимит на Изходящата Скорост (KiB/s)",
"Override Changes": "Замени Промените",
"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": "Пътят до папката на този компютър. Ще бъде създадена ако не съществува. Символът тилда (~) може да бъде използван като заместител на",
"Outgoing Rate Limit (KiB/s)": "Лимит на изходящата скорост (KiB/s)",
"Override Changes": "Наложи локалните промени",
"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 folder in the folder).": "Пътят, където версиите да бъдат складирани(остави празно за папката .stversions).",
"Pause": "Пауза",
"Paused": "На пауза",
"Please consult the release notes before performing a major upgrade.": "Моля прочети бележките по обновяването преди да започнеш.",
"Please wait": "Моля изчакай",
"Preview": "Преглед",
"Preview Usage Report": "Разгледай Доклада за Използване",
"Preview Usage Report": "Разгледай доклада за използване",
"Quick guide to supported patterns": "Бърз наръчник към поддържаните шаблони",
"RAM Utilization": "RAM Натоварване",
"Random": "Произволно",
"RAM Utilization": "RAM в употреба",
"Random": "Произволен",
"Relayed via": "Препратено през",
"Relays": "Препращачи",
"Release Notes": "Бележки по обновяването",
"Remove": "Премахни",
"Rescan": "Повторно Сканиране",
"Rescan All": "Пълно повторно сканиране",
"Rescan Interval": "Интервал за Повторно Сканиране",
"Rescan": "Сканирай повторно",
"Rescan All": "Сканирай повторно всички",
"Rescan Interval": "Интервал за повторно сканиране",
"Restart": "Рестартирай",
"Restart Needed": "Изискава се Рестартиране",
"Restart Needed": "Изисква се рестартиране",
"Restarting": "Рестартиране",
"Resume": "Пусни",
"Reused": "Повторно използван",
"Save": "Запази",
"Scanning": "Сканиране",
"Select the devices to share this folder with.": "Избери устройствата, с които да споделиш тази папка.",
"Select the devices to share this folder with.": "Изберете устройствата, с които да споделите папката.",
"Select the folders to share with this device.": "Изберете папките за споделяне с това устройство.",
"Settings": "Настройки",
"Share": "Сподели",
"Share Folder": "Сподели папка",
"Share Folders With Device": "Сподели папки с това устройство",
"Share With Devices": "Сподели с устройства",
"Share With Devices": "Споделяне с устройства",
"Share this folder?": "Сподели тази папка?",
"Shared With": "Споделена със",
"Short identifier for the folder. Must be the same on all cluster devices.": "Кратък идентификатор на папката. Трябва да бъде същият на всички компютри.",
"Show ID": "Покажи Идентификатора",
"Shared With": "Споделена с",
"Short identifier for the folder. Must be the same on all cluster devices.": "Идентификаторът на папката трябва да бъде еднакъв на всички устройства.",
"Show 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 updated to the name the device advertises if left empty.": "Покажи вместо идентификатор на устройството в статус на клъстъра. Ще бъде обновено с името по подразбиране изпратено от другия компютър.",
"Shutdown": "Спри Програмата",
"Shutdown": "Спри програмата",
"Shutdown Complete": "Спирането завършено",
"Simple File Versioning": "Опростени Файлови Версии",
"Simple File Versioning": "Опростени версии",
"Single level wildcard (matches within a directory only)": "Маска на едно ниво (покрива само в папка)",
"Smallest First": "Най-малките първо",
"Source Code": "Сорс Код",
"Staggered File Versioning": "Наслагващи се Файлови Версии",
"Start Browser": "Стартирай Браузъра",
"Smallest First": "Първо най-малките",
"Source Code": "Сорс код",
"Staggered File Versioning": "Наслагващи се версии",
"Start Browser": "Стартирай браузъра",
"Statistics": "Статистика",
"Stopped": "Спряна",
"Stopped": "Без синхронизиране",
"Support": "Помощ",
"Sync Protocol Listen Addresses": "Адрес за слушане на синхронизиращия протокол",
"Syncing": "Синхронизиране",
@@ -172,12 +172,12 @@
"The aggregated statistics are publicly available at {%url%}.": "Сумарната статистика е публично достъпна на {{url}}.",
"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 \"Edit > 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 device ID to enter here can be found in the \"Edit > 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 first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Първият параметър за командата е пътя до папката, а вторият е релативния път в самата папка.",
"The folder ID cannot be blank.": "Полето идентификатор на папка неможе да бъде празно.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Идентификаторът на папка трябва да бъде къс (64 символа или по-малко) състоящ се само от букви, цифри, точка(.), тире(-) и подчерта (_).",
"The folder ID cannot be blank.": "Полето идентификатор на папка не може да бъде празно.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Идентификаторът на папка трябва да бъде къс (64 символа или по-малко) състоящ се само от букви, цифри, точка (.), тире (-) и подчерта (_).",
"The folder ID must be unique.": "Идентификаторът на папката тряба да бъде уникален.",
"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 дена се пази версия всеки ден, до максимума се пази една версия всяка седмица.",
@@ -185,29 +185,29 @@
"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 minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Минималното свободно дисково пространство в проценти трябва да е между 0 и 100 (включително).",
"The number of days must be a number and cannot be blank.": "Броят дни трябва да бъде число и неможе да бъде празно.",
"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 must be a non-negative number (0: no limit)": "Ограничението на скорста трябва да бъде положително число (0: неограничено)",
"The path cannot be blank.": "Пътят не може да бъде празен.",
"The rate limit must be a non-negative number (0: no limit)": "Ограничението на скоростта трябва да бъде положително число (0: неограничено)",
"The rescan interval must be a non-negative number of seconds.": "Интервала на сканиране трябва да бъде не отрицателно число в секунди.",
"They are retried automatically and will be synced when the error is resolved.": "Ще бъдат спрени и автоматично синхронизирани, когато грешката бъде оправена.",
"This is a major version upgrade.": "Това е нова основна версия.",
"Trash Can File Versioning": "Версии на файлове в кошчето",
"Unknown": "Неясен",
"Unshared": "Споделянето прекратено",
"Trash Can File Versioning": "Само на файловете в кошчето",
"Unknown": "Неясно",
"Unshared": "Несподелена",
"Unused": "Неизползван",
"Up to Date": "Актуален",
"Up to Date": "Синхронизирано",
"Updated": "Обновено",
"Upgrade": "Обнови",
"Upgrade To {%version%}": "Обновен До {{version}}",
"Upgrade To {%version%}": "Обновен до {{version}}",
"Upgrading": "Обновяване",
"Upload Rate": "Скорост на Качване",
"Uptime": "Работи вече",
"Use HTTPS for GUI": "Използвай HTTPS за Потребителския Интерфейс",
"Upload Rate": "Скорост на качване",
"Uptime": "Работи от",
"Use HTTPS for GUI": "Използвай HTTPS за потребителския интерфейс",
"Version": "Версия",
"Versions Path": "Път до Версиите",
"Versions Path": "Път до версиите",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Версиите биват изтривани автоматично, когато са по-стари от максималната възраст или надминават броя файлове разрешени в даден интервал.",
"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.": "Когато добавяш нов идентификатор на папка помни, че той се използва за свързване на папките на различни устройства. Главни/малки букви са от значение и трябва да са еднакви на всички устройства.",
@@ -215,6 +215,6 @@
"You must keep at least one version.": "Трябва да пазиш поне една версия.",
"days": "дни",
"full documentation": "пълна документация",
"items": "артикула",
"items": "елемента",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} желае да сподели папка \"{{folder}}\"."
}

View File

@@ -10,8 +10,8 @@
"Add new folder?": "¿Añadir una nueva carpeta?",
"Address": "Dirección",
"Addresses": "Direcciones",
"Advanced": "Advanced",
"Advanced Configuration": "Advanced Configuration",
"Advanced": "Avanzado",
"Advanced Configuration": "Configuración Avanzada",
"All Data": "Todos los datos",
"Allow Anonymous Usage Reporting?": "¿Deseas permitir el envío anónimo de informes de uso?",
"Alphabetic": "Alfabético",
@@ -19,7 +19,7 @@
"Anonymous Usage Reporting": "Informe anónimo de uso",
"Any devices configured on an introducer device will be added to this device as well.": "Cualquier dispositivo configurado en un dispositivo de introducción será añadido también.",
"Automatic upgrades": "Actualizaciones automáticas",
"Be careful!": "Be careful!",
"Be careful!": "¡Ten cuidado!",
"Bugs": "Errores (bugs)",
"CPU Utilization": "Uso de CPU",
"Changelog": "Informe de cambios",
@@ -40,7 +40,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "El dispositivo {{device}} ({{address}}) quiere conectarse. ¿Añadir nuevo dispositivo?",
"Devices": "Dispositivos",
"Disconnected": "Desconectado",
"Discovery": "Discovery",
"Discovery": "Descubrimiento",
"Documentation": "Documentación",
"Download Rate": "Velocidad de descarga",
"Downloaded": "Descargado",
@@ -50,18 +50,18 @@
"Edit Folder": "Editar repositorio",
"Editing": "Editando",
"Enable UPnP": "Habilitar UPnP",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduzca separados por comas (\"tcp://ip:port\", \"tcp://host:port\") direcciones o \"dynamic\" para llevar a cabo la detección automática de la dirección.",
"Enter ignore patterns, one per line.": "Introducir patrones a ignorar, uno por línea.",
"Error": "Error",
"External File Versioning": "Versionado externo de fichero",
"Failed Items": "Failed Items",
"Failed Items": "Elementos fallidos",
"File Pull Order": "Orden de ficheros del pull",
"File Versioning": "Versionado de ficheros",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Los bits de permiso de ficheros son ignorados cuando se buscan cambios. Utilizar en sistemas de ficheros FAT.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Los archivos serán movidos a la carpeta .stversions cuando sean reemplazados o borrados por Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Los ficheros son cambiados a versiones con indicación de fecha en una carpeta \".stversions\" cuando son reemplazados o borrados por 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.": "Los ficheros son protegidos por los cambios hechos en otros dispositivos, pero los cambios hechos en este dispositivo serán enviados al resto del grupo (cluster).",
"Folder": "Folder",
"Folder": "Carpeta",
"Folder ID": "ID de carpeta",
"Folder Master": "Carpeta principal",
"Folder Path": "Ruta de la carpeta",
@@ -75,12 +75,12 @@
"Global Discovery Server": "Servidor de descubrimiento global",
"Global State": "Estado global",
"Help": "Ayuda",
"Home page": "Home page",
"Home page": "Página de inicio",
"Ignore": "Ignorar",
"Ignore Patterns": "Patrones a ignorar",
"Ignore Permissions": "Permisos a ignorar",
"Incoming Rate Limit (KiB/s)": "Límite de descarga (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 configuration may damage your folder contents and render Syncthing inoperable.": "Una configuración incorrecta puede dañar los contenidos de la carpeta y hacer que Syncthing no funcione.",
"Introducer": "Presentador",
"Inversion of the given condition (i.e. do not exclude)": "Inversión de la condición dada (por ejemplo, \"no excluir\")",
"Keep Versions": "Mantener versiones",
@@ -94,7 +94,7 @@
"Major Upgrade": "Actualización importante",
"Maximum Age": "Edad máxima",
"Metadata Only": "Sólo metadatos",
"Minimum Free Disk Space": "Minimum Free Disk Space",
"Minimum Free Disk Space": "Espacio mínimo libre en disco",
"Move to top of queue": "Mover al principio de la cola",
"Multi level wildcard (matches multiple directory levels)": "Comodín multinivel (coincide con múltiples niveles de directorio)",
"Never": "Nunca",
@@ -107,15 +107,15 @@
"OK": "OK",
"Off": "Desconectar",
"Oldest First": "El más antiguo primero",
"Options": "Options",
"Out of Sync": "Out of Sync",
"Options": "Opciones",
"Out of Sync": "No sincronizado",
"Out of Sync Items": "Elementos no sincronizados",
"Outgoing Rate Limit (KiB/s)": "Límite de subida (KiB/s)",
"Override Changes": "Anular cambios",
"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": "Ruta a la carpeta en la máquina local. Se creará si no existe. El carácter de la tilde (~) puede usarse como atajo.",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Ruta donde se almacenarán las versiones (dejar vacío para usar la carpeta por defecto \".stversions\").",
"Pause": "Pause",
"Paused": "Paused",
"Pause": "Pausar",
"Paused": "Pausado",
"Please consult the release notes before performing a major upgrade.": "Por favor, consultar las notas de la versión antes de realizar una actualización importante.",
"Please wait": "Por favor, espere",
"Preview": "Vista previa",
@@ -123,17 +123,17 @@
"Quick guide to supported patterns": "Guía rápida de patrones soportados",
"RAM Utilization": "Uso de RAM",
"Random": "Aleatorio",
"Relayed via": "Relayed via",
"Relays": "Relays",
"Relayed via": "Respaldada a través",
"Relays": "Respaldos",
"Release Notes": "Notas de la versión",
"Remove": "Remove",
"Remove": "Eliminar",
"Rescan": "Volver a buscar",
"Rescan All": "Volver a buscar todo",
"Rescan Interval": "Intervalo de nueva búsqueda",
"Restart": "Reiniciar",
"Restart Needed": "Reinicio necesario",
"Restarting": "Reiniciando",
"Resume": "Resume",
"Resume": "Continuar",
"Reused": "Reutilizado",
"Save": "Guardar",
"Scanning": "Rastreando",
@@ -158,7 +158,7 @@
"Source Code": "Código fuente",
"Staggered File Versioning": "Versionado escalonado de fichero",
"Start Browser": "Iniciar el navegador",
"Statistics": "Statistics",
"Statistics": "Estadísticas",
"Stopped": "Detenido",
"Support": "Soporte",
"Sync Protocol Listen Addresses": "Direcciones de escucha del protocolo de sincronización",
@@ -181,18 +181,18 @@
"The folder ID must be unique.": "La ID de la carpeta debe ser única.",
"The folder path cannot be blank.": "La ruta de la carpeta no puede estar en blanco.",
"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.": "Se utilizan los siguientes intervalos: para la primera hora se mantiene una versión cada 30 segundos, para el primer día se mantiene una versión cada hora, para los primeros 30 días se mantiene una versión diaria hasta la edad máxima de una semana.",
"The following items could not be synchronized.": "The following items could not be synchronized.",
"The following items could not be synchronized.": "Los siguientes artículos no pueden ser sincronizados.",
"The maximum age must be a number and cannot be blank.": "La edad máxima debe ser un número y no puede estar vacía.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "El tiempo máximo para mantener una versión en días (introducir 0 para mantener las versiones indefinidamente).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "El porcentaje de espacio libre mínimo debe ser un número no negativo entre 0 y 100 (ambos inclusive).",
"The number of days must be a number and cannot be blank.": "El número de días debe ser un número y no puede estar en blanco.",
"The number of days to keep files in the trash can. Zero means forever.": "El número de días para mantener los archivos en la papelera. Cero significa \"para siempre\".",
"The number of old versions to keep, per file.": "El número de versiones a antiguas a mantener para cada fichero.",
"The number of versions must be a number and cannot be blank.": "El número de versiones debe ser un número y no puede estar vacío.",
"The path cannot be blank.": "La ruta no puede estar vacía.",
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
"The rate limit must be a non-negative number (0: no limit)": "El límite de velocidad debe ser un número no negativo (0: sin límite)",
"The rescan interval must be a non-negative number of seconds.": "El intervalo de actualización debe ser un número positivo de segundos.",
"They are retried automatically and will be synced when the error is resolved.": "They are retried automatically and will be synced when the error is resolved.",
"They are retried automatically and will be synced when the error is resolved.": "Se reintentarán de forma automática y se sincronizarán cuando se resuelva el error.",
"This is a major version upgrade.": "Hay una actualización importante.",
"Trash Can File Versioning": "Versionado de archivos de la papelera",
"Unknown": "Desconocido",
@@ -213,7 +213,7 @@
"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.": "Cuando añada una nueva carpeta, tenga en cuenta que su ID se usa para unir carpetas entre dispositivos. Son sensibles a las mayúsculas y deben coincidir exactamente entre todos los dispositivos.",
"Yes": "Si",
"You must keep at least one version.": "Debes mantener al menos una versión.",
"days": "days",
"days": "días",
"full documentation": "Documentación completa",
"items": "Elementos",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} quiere compartir la carpeta \"{{folder}}\"."

View File

@@ -40,7 +40,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "El dispositivo {{device}} ({{address}}) se quiere conectar. ¿Agregar nuevo dispositivo?",
"Devices": "Dispositivos",
"Disconnected": "Desconectado",
"Discovery": "Discovery",
"Discovery": "Búsqueda",
"Documentation": "Documentación",
"Download Rate": "Tasa de descarga",
"Downloaded": "Descargado",
@@ -75,12 +75,12 @@
"Global Discovery Server": "Servidor global de identificación",
"Global State": "Estado global",
"Help": "Ayuda",
"Home page": "Home page",
"Home page": "Pagina de inicio",
"Ignore": "Ignorar",
"Ignore Patterns": "Patrones de exclusión",
"Ignore Permissions": "Ignorar permisos",
"Incoming Rate Limit (KiB/s)": "Límite de velocidad de entrada (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 configuration may damage your folder contents and render Syncthing inoperable.": "Configuración incorrecta puede dañar los contenidos de la carpeta y hacer Syncthing inoperable.",
"Introducer": "Introductor",
"Inversion of the given condition (i.e. do not exclude)": "Inversión de la condición dada (es decir, no excluir)",
"Keep Versions": "Conservar versiones",
@@ -94,7 +94,7 @@
"Major Upgrade": "Actualización mayor",
"Maximum Age": "Edad máxima",
"Metadata Only": "Sólo metadatos",
"Minimum Free Disk Space": "Minimum Free Disk Space",
"Minimum Free Disk Space": "Espacio mínimo libre en disco",
"Move to top of queue": "Mover al principio de la cola.",
"Multi level wildcard (matches multiple directory levels)": "Carácter comodín multinivel (coincide en el directorio y sus subdirectorios)",
"Never": "Nunca",
@@ -108,7 +108,7 @@
"Off": "Apagado",
"Oldest First": "Antiguo primero",
"Options": "Opciones",
"Out of Sync": "Out of Sync",
"Out of Sync": "Fuera de sincronización",
"Out of Sync Items": "Ítems no sincronizados",
"Outgoing Rate Limit (KiB/s)": "Tasa máxima de envío (KiB/s)",
"Override Changes": "Reemplazar los cambios",
@@ -123,8 +123,8 @@
"Quick guide to supported patterns": "Guía rápida sobre los patrones soportados",
"RAM Utilization": "Utilización de RAM",
"Random": "Aleatorio",
"Relayed via": "Relayed via",
"Relays": "Relays",
"Relayed via": "retransmitida vía",
"Relays": "Retransmisores",
"Release Notes": "Notas de lanzamiento",
"Remove": "Eliminar",
"Rescan": "Reescanear",
@@ -133,7 +133,7 @@
"Restart": "Reiniciar",
"Restart Needed": "Es necesario reiniciar",
"Restarting": "Reiniciando",
"Resume": "Resume",
"Resume": "Reanudar",
"Reused": "Reutilizado",
"Save": "Guardar",
"Scanning": "Actualización",
@@ -213,7 +213,7 @@
"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.": "Al agregar un nuevo repositorio, tenga en cuenta que la ID del repositorio se utiliza para conectar los repositorios entre dispositivos. Se distingue entre mayúsculas y minúsculas y debe ser exactamente igual en todos los dispositivos.",
"Yes": "Sí",
"You must keep at least one version.": "Debe mantener al menos una versión",
"days": "days",
"days": "días",
"full documentation": "documentación completa",
"items": "ítems",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} quiere compartir repositorio \"{{folder}}\"."

View File

@@ -38,9 +38,9 @@
"Device Identification": "Identification de l'appareil",
"Device Name": "Nom du périphérique",
"Device {%device%} ({%address%}) wants to connect. Add new device?": "L'appareil {{device}} ({{address}}) veut se connecter. Voulez-vous ajouter cette appareil ?",
"Devices": "Appareil",
"Devices": "Appareils",
"Disconnected": "Déconnecté",
"Discovery": "Discovery",
"Discovery": "Découverte",
"Documentation": "Documentation",
"Download Rate": "Débit de réception",
"Downloaded": "Téléchargé",

View File

@@ -1,6 +1,6 @@
{
"A negative number of days doesn't make sense.": "Et negativt antall dager gir ikke mening.",
"A new major version may not be compatible with previous versions.": "En ny hovedversjon kan bli ikke-kompatibel med en eldre versjon.",
"A new major version may not be compatible with previous versions.": "En ny hovedversjon er ikke nødvendigvis kompatibel med eldre versjoner.",
"API Key": "API-nøkkel",
"About": "Om",
"Actions": "Handlinger",
@@ -40,7 +40,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Enhet {{device}} ({{address}}) ønsker å koble seg til. Legg til ny enhet?",
"Devices": "Enheter",
"Disconnected": "Frakoblet",
"Discovery": "Discovery",
"Discovery": "Oppdagelse",
"Documentation": "Dokumentasjon",
"Download Rate": "Nedlastingsrate",
"Downloaded": "Lastet ned",
@@ -57,8 +57,8 @@
"Failed Items": "Elementsynkronisering som har feilet",
"File Pull Order": "Filenes Henterekkefølge",
"File Versioning": "Versjonskontroll",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Fil bit-rettigheter ignoreres når forandringer oppdages. Bruk FAT filsystem. ",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer som slettes eller erstattes av Syncthing flyttes til katalogen .stversions",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Informasjon om filrettigheter ignoreres når det letes etter endringer. Bruk FAT filsystem. ",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer som slettes eller erstattes av Syncthing flyttes til katalogen .stversions.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer flyttes til en datostemplet versjon i .stversions-katalogen når den oppdateres eller slettes av 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.": "Filer er beskyttet mot endringer som er gjort på andre enheter, men endringer som er gjort på denne enheten blir sendt til resten av gruppen.",
"Folder": "Katalog",
@@ -80,7 +80,7 @@
"Ignore Patterns": "Utelatelsesmønster",
"Ignore Permissions": "Ignorer Tilgangsbit",
"Incoming Rate Limit (KiB/s)": "Innkommende Hastighetsbegrensning (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Feilaktige innstillinger kan skade innholdet i dine delte kataloger og hindre Syncthing i å fungere. ",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Feilaktige innstillinger kan skade innholdet i dine delte kataloger og hindre Syncthing i å fungere.",
"Introducer": "Introduktør",
"Inversion of the given condition (i.e. do not exclude)": "Invers av den gitte tilstanden (t.d. ikke ekskluder)",
"Keep Versions": "Behold Versjoner",
@@ -194,7 +194,7 @@
"The rescan interval must be a non-negative number of seconds.": "Antall sekund i skanneintervallet kan ikke være negativt.",
"They are retried automatically and will be synced when the error is resolved.": "Disse hentes automatisk og vil synkroniseres når feilen er blitt utbedret.",
"This is a major version upgrade.": "Dette er en hovedoppgradering",
"Trash Can File Versioning": "Fil Versjonskontroll i papirkurven",
"Trash Can File Versioning": "Papirkurv Versjonskontroll",
"Unknown": "Ukjent",
"Unshared": "Ikke delt",
"Unused": "Ikke i bruk",

View File

@@ -1,6 +1,6 @@
{
"A negative number of days doesn't make sense.": "A negative number of days doesn't make sense.",
"A new major version may not be compatible with previous versions.": "A new major version may not be compatible with previous versions.",
"A negative number of days doesn't make sense.": "Eit negativt tal dagar har ikkje meining.",
"A new major version may not be compatible with previous versions.": "Ein ny hovudversjon er ikkje nødvendigvis kompatibel med eldre versjonar. ",
"API Key": "API-nøkkel",
"About": "Om",
"Actions": "Handlingar",
@@ -15,7 +15,7 @@
"All Data": "Alle data",
"Allow Anonymous Usage Reporting?": "Tillata anonymisert bruksrapportering?",
"Alphabetic": "Alfabetisk",
"An external command handles the versioning. It has to remove the file from the synced folder.": "An external command handles the versioning. It has to remove the file from the synced folder.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Ein ekstern kommando håndterer filutgåver. Den må sørge for at fila blir fjerna frå den synkroniserte mappa.",
"Anonymous Usage Reporting": "Anonymisert bruksrapportering",
"Any devices configured on an introducer device will be added to this device as well.": "Einingar konfigurert på ei introduksjonseining vil òg verta lagt til denne eininga.",
"Automatic upgrades": "Automatiske oppdateringar",
@@ -23,7 +23,7 @@
"Bugs": "Programfeil",
"CPU Utilization": "CPU-utnytting",
"Changelog": "Endringslogg",
"Clean out after": "Clean out after",
"Clean out after": "Tøm etter",
"Close": "Lukk",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentar, når brukt i starten av linja",
@@ -40,7 +40,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Eininga {{device}} ({{address}}) vil kopla seg til. Vil du leggja ho til?",
"Devices": "Einingar",
"Disconnected": "Fråkopla",
"Discovery": "Discovery",
"Discovery": "Oppdaging",
"Documentation": "Dokumentasjon",
"Download Rate": "Nedlastingsfart",
"Downloaded": "Lasta ned",
@@ -54,12 +54,12 @@
"Enter ignore patterns, one per line.": "Skriv inn mønster som skal utelatast, eitt per linje.",
"Error": "Feilmelding",
"External File Versioning": "Ekstern filutgåvehandtering",
"Failed Items": "Failed Items",
"File Pull Order": "File Pull Order",
"Failed Items": "Feilande element",
"File Pull Order": "Henterekkefølge for filer",
"File Versioning": "Filutgåvekontroll",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "File permission bits are ignored when looking for changes. Use on FAT file systems.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Files are moved to .stversions folder when replaced or deleted by Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Informasjon om filrettar vert ignorert når det blir leita etter endringar. Bruk på FAT filsystem. ",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer som Syncthing slettar eller skriv over vert flytta til katalogen .stversions.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer som Syncthing oppdaterar eller sletter vert flytta til ein datostempla versjon i .stversions-katalogen.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer er beskytta mot endringar gjort på andre einingar, men endringar gjort på denne eininga vert sende til resten av klyngja.",
"Folder": "Mappe",
"Folder ID": "Mappe ID",
@@ -80,7 +80,7 @@
"Ignore Patterns": "Utelatingsmønster",
"Ignore Permissions": "Ignorer tilgangar",
"Incoming Rate Limit (KiB/s)": "Innkomande hastigheitsgrense (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 configuration may damage your folder contents and render Syncthing inoperable.": "Feil innstillingar kan skade innhaldet i dine delte katalogar og hindre Syncthing i å fungere.",
"Introducer": "Introduktør",
"Inversion of the given condition (i.e. do not exclude)": "Det motsette av den gitte tilstanden (dvs. ekskluder ikkje)",
"Keep Versions": "Behald Versjonar",
@@ -90,11 +90,11 @@
"Later": "Seinare",
"Local Discovery": "Lokal oppdaging",
"Local State": "Lokal Tilstand",
"Local State (Total)": "Local State (Total)",
"Major Upgrade": "Major Upgrade",
"Local State (Total)": "Lokal tilstand (total)",
"Major Upgrade": "Hovudoppgradering",
"Maximum Age": "Maksimal Levetid",
"Metadata Only": "Berre metadata",
"Minimum Free Disk Space": "Minimum Free Disk Space",
"Minimum Free Disk Space": "Naudsynt ledig diskplass",
"Move to top of queue": "Flytt øvst i køen",
"Multi level wildcard (matches multiple directory levels)": "Fleirnivå-jokerteikn (søkjer på fleire mappenivå)",
"Never": "Aldri",
@@ -116,15 +116,15 @@
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Plasseringa for lagra versjonar (la denne vera tom for å bruka standard .stversions-mappa i mappa).",
"Pause": "Stans",
"Paused": "Stansa",
"Please consult the release notes before performing a major upgrade.": "Please consult the release notes before performing a major upgrade.",
"Please consult the release notes before performing a major upgrade.": "Sjå \"release notes\" før ei hovudoppgradering vert utført.",
"Please wait": "Gjer vel og vent",
"Preview": "Førehandsvisning",
"Preview Usage Report": "Førehandsvis bruksrapporten",
"Quick guide to supported patterns": "Kjapp innføring i godkjente mønster",
"RAM Utilization": "Minnebruk",
"Random": "Tilfeldig",
"Relayed via": "Relayed via",
"Relays": "Relays",
"Relayed via": "Relé via",
"Relays": "Reléer",
"Release Notes": "Utgivingsnotat",
"Remove": "Fjern",
"Rescan": "Skann På Ny",
@@ -168,7 +168,7 @@
"Syncthing is restarting.": "Syncthing startar på ny.",
"Syncthing is upgrading.": "Syncthing oppgraderer.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ut til å vera nede, eller så er det eit problem med nettilkoplinga di. Prøvar på ny …",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing ser ut til å ha støtt på eit problem under behandling av din førespurnad. Vær vennleg å oppfrisk nettlesaren eller start Syncthing på nytt om problemet vedvarer.",
"The aggregated statistics are publicly available at {%url%}.": "Samla statistikk er opent tilgjengeleg på {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Instillingane har blitt lagra men ikkje aktivert. Syncthing må starta på ny for å aktivera dei nye instillingane.",
"The device ID cannot be blank.": "Eining ID kan ikkje vera tom.",
@@ -184,17 +184,17 @@
"The following items could not be synchronized.": "Fyljande filer kunne ikkje synkroniserast.",
"The maximum age must be a number and cannot be blank.": "Maksimal levetid må vera eit tal og kan ikkje vera tomt.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Høgaste tidsrom å behalda ei utgåve (i dagar, set til 0 for å behalda versjonane for alltid).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Nødvendig ledig diskplass må vere eit tal mellom 0 og 100.",
"The number of days must be a number and cannot be blank.": "Tal på dagar må ver eit tal og kan ikkje vera tomt.",
"The number of days to keep files in the trash can. Zero means forever.": "The number of days to keep files in the trash can. Zero means forever.",
"The number of days to keep files in the trash can. Zero means forever.": "Antall dagar å behalda filer i søppelkorga. Null betyr for alltid.",
"The number of old versions to keep, per file.": "Tal på gamle versjonar ein skal behalda, per fil.",
"The number of versions must be a number and cannot be blank.": "Tal på versjonar må vera eit tal og kan ikkje vera tomt.",
"The path cannot be blank.": "Bana kan ikkje vera tom.",
"The rate limit must be a non-negative number (0: no limit)": "Hastigheitsgrensa må ver eit positivt tall (0: ingen grensa)",
"The rescan interval must be a non-negative number of seconds.": "Talet på sekund i skanneintervallet kan ikkje vera negativt.",
"They are retried automatically and will be synced when the error is resolved.": "They are retried automatically and will be synced when the error is resolved.",
"This is a major version upgrade.": "This is a major version upgrade.",
"Trash Can File Versioning": "Trash Can File Versioning",
"They are retried automatically and will be synced when the error is resolved.": "Desse vil bli prøvd på nytt automatisk og vil bli synkronisert når feilen har blitt utbetra.",
"This is a major version upgrade.": "Dette er ei hovudoppgradering",
"Trash Can File Versioning": "Papirkorg filutgåvehandtering",
"Unknown": "Ukjent",
"Unshared": "Ikkje delt",
"Unused": "Ubrukt",
@@ -213,7 +213,7 @@
"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.": "Hugs at når ei ny mappe vert lagt til, vert mappe-ID-en brukt til å binda saman mappene mellom einingane. Det er skilnad på store og små bokstavar, så ID-ane må vera identiske på alle einingane.",
"Yes": "Ja",
"You must keep at least one version.": "Du må behalda minst ein versjon.",
"days": "days",
"days": "dagar",
"full documentation": "all dokumentasjon",
"items": "element",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} ønskjer å dela mappa \"{{folder}}\"."

View File

@@ -109,7 +109,7 @@
"Oldest First": "Mais antigo primeiro",
"Options": "Opções",
"Out of Sync": "Fora de sincronia",
"Out of Sync Items": "Itens fora de sincronia",
"Out of Sync Items": "Fora de sincronia",
"Outgoing Rate Limit (KiB/s)": "Limite de velocidade de envio (KiB/s)",
"Override Changes": "Sobrescrever mudanças",
"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": "Caminho para a pasta na máquina local. Será criado caso não exista. O caractere til (~) pode ser usado como um atalho para",

View File

@@ -40,7 +40,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "O dispositivo {{device}} ({{address}}) quer conectar-se. Adiciono este novo dispositivo?",
"Devices": "Dispositivos",
"Disconnected": "Desconectado",
"Discovery": "Busca",
"Discovery": "Detecção",
"Documentation": "Documentação",
"Download Rate": "Velocidade de recepção",
"Downloaded": "Recebido",
@@ -50,7 +50,7 @@
"Edit Folder": "Editar pasta",
"Editing": "Editando",
"Enable UPnP": "Activar UPnP",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza endereços separados por vírgulas (\"tcp://ip:porto\", \"tcp://máquina:porto\") ou \"dynamic\" para descobrir automaticamente os endereços.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza endereços separados por vírgulas (\"tcp://ip:porto\", \"tcp://máquina:porto\") ou \"dynamic\" para detectar automaticamente os endereços.",
"Enter ignore patterns, one per line.": "Escreva os padrões de exclusão, um por linha.",
"Error": "Erro",
"External File Versioning": "Externa",
@@ -71,8 +71,8 @@
"GUI Authentication User": "Utilizador da autenticação na interface gráfica",
"GUI Listen Addresses": "Endereço de escuta da interface gráfica",
"Generate": "Gerar",
"Global Discovery": "Busca global",
"Global Discovery Server": "Servidor da busca global",
"Global Discovery": "Detecção global",
"Global Discovery Server": "Servidor de detecção global",
"Global State": "Estado global",
"Help": "Ajuda",
"Home page": "Página do projecto",
@@ -88,7 +88,7 @@
"Last File Received": "Último ficheiro recebido",
"Last seen": "Última vez que foi verificado",
"Later": "Mais tarde",
"Local Discovery": "Busca local",
"Local Discovery": "Detecção local",
"Local State": "Estado local",
"Local State (Total)": "Estado local (total)",
"Major Upgrade": "Actualização importante",
@@ -123,8 +123,8 @@
"Quick guide to supported patterns": "Guia rápido dos padrões suportados",
"RAM Utilization": "Utilização da RAM",
"Random": "Aleatória",
"Relayed via": "Transmitido via",
"Relays": "Transmissores",
"Relayed via": "Retransmitido via",
"Relays": "Retransmissores",
"Release Notes": "Notas de lançamento",
"Remove": "Remover",
"Rescan": "Verificar agora",

View File

@@ -33,7 +33,7 @@
"Copied from original": "Copiat din original",
"Copyright © 2015 the following Contributors:": "Copyright ©2015 Următorii Contribuitori:",
"Delete": "Şterge",
"Deleted": "Deleted",
"Deleted": "Șters",
"Device ID": "ID Dispozitiv",
"Device Identification": "Identificare Dispozitiv",
"Device Name": "Nume Dispozitiv",
@@ -107,7 +107,7 @@
"OK": "OK",
"Off": "Închis",
"Oldest First": "Oldest First",
"Options": "Options",
"Options": "Opțiuni",
"Out of Sync": "Out of Sync",
"Out of Sync Items": "Elemente Nesincronizate",
"Outgoing Rate Limit (KiB/s)": "Limită Viteză de Upload (KB/s)",
@@ -186,7 +186,7 @@
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Câte zile să se păstreze o versiune (setează 0 pentru nelimitat)",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).",
"The number of days must be a number and cannot be blank.": "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 days to keep files in the trash can. Zero means forever.",
"The number of days to keep files in the trash can. Zero means forever.": "Numărul de zile pentru a păstra fișierele in urnă.Zero înseamnă permanent.",
"The number of old versions to keep, per file.": "Numărul de versiuni vechi de salvat per fişier.",
"The number of versions must be a number and cannot be blank.": "Numărul de versiuni trebuie să fie un număr şi nu poate fi gol.",
"The path cannot be blank.": "Locația nu poate fi goală.",

View File

@@ -72,11 +72,13 @@
<li class="auto-generated">Piotr Bejda</li>
<li class="auto-generated">Ryan Sullivan</li>
<li class="auto-generated">Sergey Mishin</li>
<li class="auto-generated">Stefan Kuntz</li>
<li class="auto-generated">Stefan Tatschner</li>
<li class="auto-generated">Tim Abell</li>
<li class="auto-generated">Tobias Nygren</li>
<li class="auto-generated">Tomas Cerveny</li>
<li class="auto-generated">Tully Robinson</li>
<li class="auto-generated">Tyler Brazier</li>
<li class="auto-generated">Veeti Paananen</li>
<li class="auto-generated">Vil Brekin</li>
<li class="auto-generated">Yannic A.</li>

View File

File diff suppressed because one or more lines are too long

View File

@@ -29,18 +29,25 @@ const (
)
var (
// DefaultDiscoveryServers should be substituted when the configuration
// contains <globalAnnounceServer>default</globalAnnounceServer>. This is
// DefaultDiscoveryServersV4 should be substituted when the configuration
// contains <globalAnnounceServer>default-v4</globalAnnounceServer>. This is
// done by the "consumer" of the configuration, as we don't want these
// saved to the config.
DefaultDiscoveryServers = []string{
DefaultDiscoveryServersV4 = []string{
"https://discovery-v4-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA", // 194.126.249.5, Sweden
"https://discovery-v4-2.syncthing.net/?id=AQEHEO2-XOS7QRA-X2COH5K-PO6OPVA-EWOSEGO-KZFMD32-XJ4ZV46-CUUVKAS", // 45.55.230.38, USA
"https://discovery-v4-2.syncthing.net/?id=DVU36WY-H3LVZHW-E6LLFRE-YAFN5EL-HILWRYP-OC2M47J-Z4PE62Y-ADIBDQC", // 45.55.230.38, USA
"https://discovery-v4-3.syncthing.net/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4", // 128.199.95.124, Singapore
}
// DefaultDiscoveryServersV6 should be substituted when the configuration
// contains <globalAnnounceServer>default-v6</globalAnnounceServer>.
DefaultDiscoveryServersV6 = []string{
"https://discovery-v6-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA", // 2001:470:28:4d6::5, Sweden
"https://discovery-v6-2.syncthing.net/?id=AQEHEO2-XOS7QRA-X2COH5K-PO6OPVA-EWOSEGO-KZFMD32-XJ4ZV46-CUUVKAS", // 2604:a880:800:10::182:a001, USA
"https://discovery-v6-2.syncthing.net/?id=DVU36WY-H3LVZHW-E6LLFRE-YAFN5EL-HILWRYP-OC2M47J-Z4PE62Y-ADIBDQC", // 2604:a880:800:10::182:a001, USA
"https://discovery-v6-3.syncthing.net/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4", // 2400:6180:0:d0::d9:d001, Singapore
}
// DefaultDiscoveryServers should be substituted when the configuration
// contains <globalAnnounceServer>default</globalAnnounceServer>.
DefaultDiscoveryServers = append(DefaultDiscoveryServersV4, DefaultDiscoveryServersV6...)
// DefaultDiscoveryServersIP is used by the usage reporting.
// XXX: Detect Android, and use this is we still don't have working DNS?

View File

@@ -17,6 +17,13 @@ type DeviceConfiguration struct {
Introducer bool `xml:"introducer,attr" json:"introducer"`
}
func NewDeviceConfiguration(id protocol.DeviceID, name string) DeviceConfiguration {
return DeviceConfiguration{
DeviceID: id,
Name: name,
}
}
func (orig DeviceConfiguration) Copy() DeviceConfiguration {
c := orig
c.Addresses = make([]string, len(orig.Addresses))

View File

@@ -44,6 +44,15 @@ type FolderDeviceConfiguration struct {
DeviceID protocol.DeviceID `xml:"id,attr" json:"deviceID"`
}
func NewFolderConfiguration(id, path string) FolderConfiguration {
f := FolderConfiguration{
ID: id,
RawPath: path,
}
f.prepare()
return f
}
func (f FolderConfiguration) Copy() FolderConfiguration {
c := f
c.Devices = make([]FolderDeviceConfiguration, len(f.Devices))

View File

@@ -31,7 +31,7 @@ import (
// If all verification calls returns nil, CommitConfiguration() is called for
// each subscribing object. The callee returns true if the new configuration
// has been successfully applied, otherwise false. Any Commit() call returning
// false will result in a "restart needed" respone to the API/user. Note that
// false will result in a "restart needed" response to the API/user. Note that
// the new configuration will still have been applied by those who were
// capable of doing so.
type Committer interface {
@@ -310,9 +310,14 @@ func (w *Wrapper) Save() error {
func (w *Wrapper) GlobalDiscoveryServers() []string {
var servers []string
for _, srv := range w.cfg.Options.GlobalAnnServers {
if srv == "default" {
switch srv {
case "default":
servers = append(servers, DefaultDiscoveryServers...)
} else {
case "default-v4":
servers = append(servers, DefaultDiscoveryServersV4...)
case "default-v6":
servers = append(servers, DefaultDiscoveryServersV6...)
default:
servers = append(servers, srv)
}
}

View File

@@ -280,49 +280,18 @@ func (s *connectionSvc) connect() {
continue
}
var addrs []string
var relays []discover.Relay
for _, addr := range deviceCfg.Addresses {
if addr == "dynamic" {
if s.discoverer != nil {
if t, r, err := s.discoverer.Lookup(deviceID); err == nil {
addrs = append(addrs, t...)
relays = append(relays, r...)
}
}
} else {
addrs = append(addrs, addr)
}
}
addrs, relays := s.resolveAddresses(deviceID, deviceCfg.Addresses)
for _, addr := range addrs {
uri, err := url.Parse(addr)
if err != nil {
l.Infoln("Failed to parse connection url:", addr, err)
continue
if conn := s.connectDirect(deviceID, addr); conn != nil {
if connected {
s.model.Close(deviceID, fmt.Errorf("switching connections"))
}
s.conns <- model.IntermediateConnection{
conn, model.ConnectionTypeDirectDial,
}
continue nextDevice
}
dialer, ok := dialers[uri.Scheme]
if !ok {
l.Infoln("Unknown address schema", uri)
continue
}
l.Debugln("dial", deviceCfg.DeviceID, uri)
conn, err := dialer(uri, s.tlsCfg)
if err != nil {
l.Debugln("dial failed", deviceCfg.DeviceID, uri, err)
continue
}
if connected {
s.model.Close(deviceID, fmt.Errorf("switching connections"))
}
s.conns <- model.IntermediateConnection{
conn, model.ConnectionTypeDirectDial,
}
continue nextDevice
}
// Only connect via relays if not already connected
@@ -345,45 +314,12 @@ func (s *connectionSvc) connect() {
s.lastRelayCheck[deviceID] = time.Now()
for _, addr := range relays {
uri, err := url.Parse(addr.URL)
if err != nil {
l.Infoln("Failed to parse relay connection url:", addr, err)
continue
if conn := s.connectViaRelay(deviceID, addr); conn != nil {
s.conns <- model.IntermediateConnection{
conn, model.ConnectionTypeRelayDial,
}
continue nextDevice
}
inv, err := client.GetInvitationFromRelay(uri, deviceID, s.tlsCfg.Certificates)
if err != nil {
l.Debugf("Failed to get invitation for %s from %s: %v", deviceID, uri, err)
continue
} else {
l.Debugln("Succesfully retrieved relay invitation", inv, "from", uri)
}
conn, err := client.JoinSession(inv)
if err != nil {
l.Debugf("Failed to join relay session %s: %v", inv, err)
continue
} else {
l.Debugln("Sucessfully joined relay session", inv)
}
var tc *tls.Conn
if inv.ServerSocket {
tc = tls.Server(conn, s.tlsCfg)
} else {
tc = tls.Client(conn, s.tlsCfg)
}
err = tc.Handshake()
if err != nil {
l.Infof("TLS handshake (BEP/relay %s): %v", inv, err)
tc.Close()
continue
}
s.conns <- model.IntermediateConnection{
tc, model.ConnectionTypeRelayDial,
}
continue nextDevice
}
}
@@ -395,6 +331,84 @@ func (s *connectionSvc) connect() {
}
}
func (s *connectionSvc) resolveAddresses(deviceID protocol.DeviceID, inAddrs []string) (addrs []string, relays []discover.Relay) {
for _, addr := range inAddrs {
if addr == "dynamic" {
if s.discoverer != nil {
if t, r, err := s.discoverer.Lookup(deviceID); err == nil {
addrs = append(addrs, t...)
relays = append(relays, r...)
}
}
} else {
addrs = append(addrs, addr)
}
}
return
}
func (s *connectionSvc) connectDirect(deviceID protocol.DeviceID, addr string) *tls.Conn {
uri, err := url.Parse(addr)
if err != nil {
l.Infoln("Failed to parse connection url:", addr, err)
return nil
}
dialer, ok := dialers[uri.Scheme]
if !ok {
l.Infoln("Unknown address schema", uri)
return nil
}
l.Debugln("dial", deviceID, uri)
conn, err := dialer(uri, s.tlsCfg)
if err != nil {
l.Debugln("dial failed", deviceID, uri, err)
return nil
}
return conn
}
func (s *connectionSvc) connectViaRelay(deviceID protocol.DeviceID, addr discover.Relay) *tls.Conn {
uri, err := url.Parse(addr.URL)
if err != nil {
l.Infoln("Failed to parse relay connection url:", addr, err)
return nil
}
inv, err := client.GetInvitationFromRelay(uri, deviceID, s.tlsCfg.Certificates)
if err != nil {
l.Debugf("Failed to get invitation for %s from %s: %v", deviceID, uri, err)
return nil
}
l.Debugln("Succesfully retrieved relay invitation", inv, "from", uri)
conn, err := client.JoinSession(inv)
if err != nil {
l.Debugf("Failed to join relay session %s: %v", inv, err)
return nil
}
l.Debugln("Successfully joined relay session", inv)
var tc *tls.Conn
if inv.ServerSocket {
tc = tls.Server(conn, s.tlsCfg)
} else {
tc = tls.Client(conn, s.tlsCfg)
}
err = tc.Handshake()
if err != nil {
l.Infof("TLS handshake (BEP/relay %s): %v", inv, err)
tc.Close()
return nil
}
return tc
}
func (s *connectionSvc) acceptRelayConns() {
for {
conn := s.relaySvc.Accept()

View File

@@ -214,6 +214,9 @@ func blockKeyInto(o, hash []byte, folder, file string) []byte {
}
o[0] = KeyTypeBlock
copy(o[1:], []byte(folder))
for i := len(folder); i < 64; i++ {
o[1+i] = 0
}
copy(o[1+64:], []byte(hash))
copy(o[1+64+32:], []byte(file))
return o

View File

@@ -45,7 +45,7 @@ func (r *VirtualMtimeRepo) UpdateMtime(path string, diskMtime, actualMtime time.
func (r *VirtualMtimeRepo) GetMtime(path string, diskMtime time.Time) time.Time {
data, exists := r.ns.Bytes(path)
if !exists {
// Absense of debug print is significant enough in itself here
// Absence of debug print is significant enough in itself here
return diskMtime
}

View File

@@ -24,7 +24,7 @@ connection addresses (if any) and relay addresses (if any).
}
It's OK for either of the "direct" or "relays" fields to be either the empty
list ([]), null, or missing entirely. An announcment with both fields missing
list ([]), null, or missing entirely. An announcement with both fields missing
or empty is however not useful...
Any empty or unspecified IP addresses (i.e. addresses like tcp://:22000,
@@ -39,7 +39,7 @@ The server response is empty, with code 200 (OK) on success. If no certificate
was presented, status 403 (Forbidden) is returned. If the posted data doesn't
conform to the expected format, 400 (Bad Request) is returned.
In successfull responses, the server may return a "Reannounce-After" header
In successful responses, the server may return a "Reannounce-After" header
containing the number of seconds after which the client should perform a new
announcement.
@@ -58,7 +58,7 @@ Queries are performed as HTTPS GET requests to the announce server URL. The
requested device ID is passed as the query parameter "device", in canonical
string form, i.e. https://announce.syncthing.net/?device=ABC12345-....
Successfull responses will have status code 200 (OK) and carry a JSON payload
Successful responses will have status code 200 (OK) and carry a JSON payload
of the same format as the announcement above. The response will not contain
empty or unspecified addresses.

View File

@@ -196,6 +196,7 @@ func (c *localClient) registerDevice(src net.Addr, device Device) bool {
// Any empty or unspecified addresses should be set to the source address
// of the announcement. We also skip any addresses we can't parse.
l.Debugln("discover: Registering addresses for", id)
var validAddresses []string
for _, addr := range device.Addresses {
u, err := url.Parse(addr.URL)
@@ -214,9 +215,12 @@ func (c *localClient) registerDevice(src net.Addr, device Device) bool {
continue
}
u.Host = net.JoinHostPort(host, strconv.Itoa(tcpAddr.Port))
l.Debugf("discover: Reconstructed URL is %#v", u)
validAddresses = append(validAddresses, u.String())
l.Debugf("discover: Replaced address %v in %s to get %s", tcpAddr.IP, addr.URL, u.String())
} else {
validAddresses = append(validAddresses, addr.URL)
l.Debugf("discover: Accepted address %s verbatim", addr.URL)
}
}
@@ -230,7 +234,7 @@ func (c *localClient) registerDevice(src net.Addr, device Device) bool {
if isNewDevice {
events.Default.Log(events.DeviceDiscovered, map[string]interface{}{
"device": id.String(),
"addrs": device.Addresses,
"addrs": validAddresses,
"relays": device.Relays,
})
}

View File

@@ -41,6 +41,7 @@ const (
FolderScanProgress
ExternalPortMappingChanged
RelayStateChanged
LoginAttempt
AllEvents = (1 << iota) - 1
)
@@ -93,6 +94,8 @@ func (t EventType) String() string {
return "ExternalPortMappingChanged"
case RelayStateChanged:
return "RelayStateChanged"
case LoginAttempt:
return "LoginAttempt"
default:
return "Unknown"
}
@@ -281,7 +284,7 @@ func (s *BufferedSubscription) Since(id int, into []Event) []Event {
}
// Error returns a string pointer suitable for JSON marshalling errors. It
// retains the "null on sucess" semantics, but ensures the error result is a
// retains the "null on success" semantics, but ensures the error result is a
// string regardless of the underlying concrete error type.
func Error(err error) *string {
if err == nil {

View File

@@ -78,7 +78,7 @@ func TestFacilityDebugging(t *testing.T) {
f1.Debugln("Debug line from f1")
if msgs != 1 {
t.Fatalf("Incorrent number of messages, %d != 1", msgs)
t.Fatalf("Incorrect number of messages, %d != 1", msgs)
}
}

View File

@@ -75,15 +75,16 @@ type Model struct {
clientName string
clientVersion string
folderCfgs map[string]config.FolderConfiguration // folder -> cfg
folderFiles map[string]*db.FileSet // folder -> files
folderDevices map[string][]protocol.DeviceID // folder -> deviceIDs
deviceFolders map[protocol.DeviceID][]string // deviceID -> folders
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
folderIgnores map[string]*ignore.Matcher // folder -> matcher object
folderRunners map[string]service // folder -> puller or scanner
folderStatRefs map[string]*stats.FolderStatisticsReference // folder -> statsRef
fmut sync.RWMutex // protects the above
folderCfgs map[string]config.FolderConfiguration // folder -> cfg
folderFiles map[string]*db.FileSet // folder -> files
folderDevices map[string][]protocol.DeviceID // folder -> deviceIDs
deviceFolders map[protocol.DeviceID][]string // deviceID -> folders
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
folderIgnores map[string]*ignore.Matcher // folder -> matcher object
folderRunners map[string]service // folder -> puller or scanner
folderRunnerTokens map[string][]suture.ServiceToken // folder -> tokens for puller or scanner
folderStatRefs map[string]*stats.FolderStatisticsReference // folder -> statsRef
fmut sync.RWMutex // protects the above
conn map[protocol.DeviceID]Connection
deviceVer map[protocol.DeviceID]string
@@ -105,28 +106,29 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
l.Debugln(line)
},
}),
cfg: cfg,
db: ldb,
finder: db.NewBlockFinder(ldb),
progressEmitter: NewProgressEmitter(cfg),
id: id,
shortID: id.Short(),
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
protectedFiles: protectedFiles,
deviceName: deviceName,
clientName: clientName,
clientVersion: clientVersion,
folderCfgs: make(map[string]config.FolderConfiguration),
folderFiles: make(map[string]*db.FileSet),
folderDevices: make(map[string][]protocol.DeviceID),
deviceFolders: make(map[protocol.DeviceID][]string),
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
folderIgnores: make(map[string]*ignore.Matcher),
folderRunners: make(map[string]service),
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
conn: make(map[protocol.DeviceID]Connection),
deviceVer: make(map[protocol.DeviceID]string),
devicePaused: make(map[protocol.DeviceID]bool),
cfg: cfg,
db: ldb,
finder: db.NewBlockFinder(ldb),
progressEmitter: NewProgressEmitter(cfg),
id: id,
shortID: id.Short(),
cacheIgnoredFiles: cfg.Options().CacheIgnoredFiles,
protectedFiles: protectedFiles,
deviceName: deviceName,
clientName: clientName,
clientVersion: clientVersion,
folderCfgs: make(map[string]config.FolderConfiguration),
folderFiles: make(map[string]*db.FileSet),
folderDevices: make(map[string][]protocol.DeviceID),
deviceFolders: make(map[protocol.DeviceID][]string),
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
folderIgnores: make(map[string]*ignore.Matcher),
folderRunners: make(map[string]service),
folderRunnerTokens: make(map[string][]suture.ServiceToken),
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
conn: make(map[protocol.DeviceID]Connection),
deviceVer: make(map[protocol.DeviceID]string),
devicePaused: make(map[protocol.DeviceID]bool),
fmut: sync.NewRWMutex(),
pmut: sync.NewRWMutex(),
@@ -163,7 +165,6 @@ func (m *Model) StartFolderRW(folder string) {
}
p := newRWFolder(m, m.shortID, cfg)
m.folderRunners[folder] = p
m.fmut.Unlock()
if len(cfg.Versioning.Type) > 0 {
factory, ok := versioner.Factories[cfg.Versioning.Type]
@@ -176,14 +177,17 @@ func (m *Model) StartFolderRW(folder string) {
// The versioner implements the suture.Service interface, so
// expects to be run in the background in addition to being called
// when files are going to be archived.
m.Add(service)
token := m.Add(service)
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
}
p.versioner = versioner
}
m.warnAboutOverwritingProtectedFiles(folder)
m.Add(p)
token := m.Add(p)
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
m.fmut.Unlock()
l.Okln("Ready to synchronize", folder, "(read-write)")
}
@@ -232,13 +236,49 @@ func (m *Model) StartFolderRO(folder string) {
}
s := newROFolder(m, folder, time.Duration(cfg.RescanIntervalS)*time.Second)
m.folderRunners[folder] = s
token := m.Add(s)
m.folderRunnerTokens[folder] = append(m.folderRunnerTokens[folder], token)
m.fmut.Unlock()
m.Add(s)
l.Okln("Ready to synchronize", folder, "(read only; no external updates accepted)")
}
func (m *Model) RemoveFolder(folder string) {
m.fmut.Lock()
m.pmut.Lock()
// Stop the services running for this folder
for _, id := range m.folderRunnerTokens[folder] {
m.Remove(id)
}
// Close connections to affected devices
for _, dev := range m.folderDevices[folder] {
if conn, ok := m.conn[dev]; ok {
closeRawConn(conn)
}
}
// Clean up our config maps
delete(m.folderCfgs, folder)
delete(m.folderFiles, folder)
delete(m.folderDevices, folder)
delete(m.folderIgnores, folder)
delete(m.folderRunners, folder)
delete(m.folderRunnerTokens, folder)
delete(m.folderStatRefs, folder)
for dev, folders := range m.deviceFolders {
m.deviceFolders[dev] = stringSliceWithout(folders, folder)
}
// Remove it from the database
db.DropFolder(m.db, folder)
m.pmut.Unlock()
m.fmut.Unlock()
}
type ConnectionInfo struct {
protocol.Statistics
Connected bool
@@ -261,7 +301,7 @@ func (info ConnectionInfo) MarshalJSON() ([]byte, error) {
})
}
// ConnectionStats returns a map with connection statistics for each connected device.
// ConnectionStats returns a map with connection statistics for each device.
func (m *Model) ConnectionStats() map[string]interface{} {
type remoteAddrer interface {
RemoteAddr() net.Addr
@@ -1014,7 +1054,7 @@ func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignore
minLocalVer, err = sendIndexTo(false, minLocalVer, conn, folder, fs, ignores)
// Wait a short amount of time before entering the next loop. If there
// are continous changes happening to the local index, this gives us
// are continuous changes happening to the local index, this gives us
// time to batch them up a little.
time.Sleep(250 * time.Millisecond)
}
@@ -1250,6 +1290,11 @@ nextSub:
}
subs = unifySubs
// The cancel channel is closed whenever we return (such as from an error),
// to signal the potentially still running walker to stop.
cancel := make(chan struct{})
defer close(cancel)
w := &scanner.Walker{
Folder: folderCfg.ID,
Dir: folderCfg.Path(),
@@ -1265,6 +1310,7 @@ nextSub:
Hashers: m.numHashers(folder),
ShortID: m.shortID,
ProgressTickIntervalS: folderCfg.ScanProgressIntervalS,
Cancel: cancel,
}
runner.setState(FolderScanning)
@@ -1674,17 +1720,17 @@ func (m *Model) BringToFront(folder, file string) {
// CheckFolderHealth checks the folder for common errors and returns the
// current folder error, or nil if the folder is healthy.
func (m *Model) CheckFolderHealth(id string) error {
folder, ok := m.cfg.Folders()[id]
if !ok {
return errors.New("folder does not exist")
}
if minFree := m.cfg.Options().MinHomeDiskFreePct; minFree > 0 {
if free, err := osutil.DiskFreePercentage(m.cfg.ConfigPath()); err == nil && free < minFree {
return errors.New("home disk has insufficient free space")
}
}
folder, ok := m.cfg.Folders()[id]
if !ok {
return errors.New("folder does not exist")
}
fi, err := os.Stat(folder.Path())
v, ok := m.CurrentLocalVersion(id)
@@ -1797,9 +1843,9 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
for folderID, fromCfg := range fromFolders {
toCfg, ok := toFolders[folderID]
if !ok {
// A folder was removed. Requires restart.
l.Debugln(m, "requires restart, removing folder", folderID)
return false
// The folder was removed.
m.RemoveFolder(folderID)
continue
}
// This folder exists on both sides. Compare the device lists, as we
@@ -1848,7 +1894,7 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
}
}
// Removing a device requres restart
// Removing a device requires restart
toDevs := mapDeviceCfgs(from.Devices)
for _, dev := range from.Devices {
if _, ok := toDevs[dev.DeviceID]; !ok {
@@ -1961,3 +2007,14 @@ func closeRawConn(conn io.Closer) error {
}
return conn.Close()
}
func stringSliceWithout(ss []string, s string) []string {
for i := range ss {
if ss[i] == s {
copy(ss[i:], ss[i+1:])
ss = ss[:len(ss)-1]
return ss
}
}
return ss
}

View File

@@ -32,22 +32,11 @@ func init() {
device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
defaultFolderConfig = config.FolderConfiguration{
ID: "default",
RawPath: "testdata",
Devices: []config.FolderDeviceConfiguration{
{
DeviceID: device1,
},
},
}
defaultFolderConfig = config.NewFolderConfiguration("default", "testdata")
defaultFolderConfig.Devices = []config.FolderDeviceConfiguration{{DeviceID: device1}}
_defaultConfig := config.Configuration{
Folders: []config.FolderConfiguration{defaultFolderConfig},
Devices: []config.DeviceConfiguration{
{
DeviceID: device1,
},
},
Devices: []config.DeviceConfiguration{config.NewDeviceConfiguration(device1, "device1")},
Options: config.OptionsConfiguration{
// Don't remove temporaries directly on startup
KeepTemporariesH: 1,

View File

@@ -948,7 +948,8 @@ func (p *rwFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocks
// changes that we don't know about yet and we should scan before
// touching the file. If we can't stat the file we'll just pull it.
if info, err := osutil.Lstat(realName); err == nil {
if info.ModTime().Unix() != curFile.Modified || info.Size() != curFile.Size() {
mtime := p.virtualMtimeRepo.GetMtime(file.Name, info.ModTime())
if mtime.Unix() != curFile.Modified || info.Size() != curFile.Size() {
l.Debugln("file modified but not rescanned; not pulling:", realName)
// Scan() is synchronous (i.e. blocks until the scan is
// completed and returns an error), but a scan can't happen

View File

@@ -514,7 +514,7 @@ func TestDeregisterOnFailInPull(t *testing.T) {
p.handleFile(file, copyChan, finisherChan)
// Receove at finisher, we shoud error out as puller has nowhere to pull
// Receive at finisher, we should error out as puller has nowhere to pull
// from.
select {
case state := <-finisherBufferChan:

View File

@@ -19,13 +19,13 @@ import (
// workers are used in parallel. The outbox will become closed when the inbox
// is closed and all items handled.
func newParallelHasher(dir string, blockSize, workers int, outbox, inbox chan protocol.FileInfo, counter *int64, done chan struct{}) {
func newParallelHasher(dir string, blockSize, workers int, outbox, inbox chan protocol.FileInfo, counter *int64, done, cancel chan struct{}) {
wg := sync.NewWaitGroup()
wg.Add(workers)
for i := 0; i < workers; i++ {
go func() {
hashFiles(dir, blockSize, outbox, inbox, counter)
hashFiles(dir, blockSize, outbox, inbox, counter, cancel)
wg.Done()
}()
}
@@ -59,19 +59,33 @@ func HashFile(path string, blockSize int, sizeHint int64, counter *int64) ([]pro
return Blocks(fd, blockSize, sizeHint, counter)
}
func hashFiles(dir string, blockSize int, outbox, inbox chan protocol.FileInfo, counter *int64) {
for f := range inbox {
if f.IsDirectory() || f.IsDeleted() {
panic("Bug. Asked to hash a directory or a deleted file.")
}
func hashFiles(dir string, blockSize int, outbox, inbox chan protocol.FileInfo, counter *int64, cancel chan struct{}) {
for {
select {
case f, ok := <-inbox:
if !ok {
return
}
blocks, err := HashFile(filepath.Join(dir, f.Name), blockSize, f.CachedSize, counter)
if err != nil {
l.Debugln("hash error:", f.Name, err)
continue
}
if f.IsDirectory() || f.IsDeleted() {
panic("Bug. Asked to hash a directory or a deleted file.")
}
f.Blocks = blocks
outbox <- f
blocks, err := HashFile(filepath.Join(dir, f.Name), blockSize, f.CachedSize, counter)
if err != nil {
l.Debugln("hash error:", f.Name, err)
continue
}
f.Blocks = blocks
select {
case outbox <- f:
case <-cancel:
return
}
case <-cancel:
return
}
}
}

View File

@@ -72,6 +72,8 @@ type Walker struct {
// Optional progress tick interval which defines how often FolderScanProgress
// events are emitted. Negative number means disabled.
ProgressTickIntervalS int
// Signals cancel from the outside - when closed, we should stop walking.
Cancel chan struct{}
}
type TempNamer interface {
@@ -121,7 +123,7 @@ func (w *Walker) Walk() (chan protocol.FileInfo, error) {
// We're not required to emit scan progress events, just kick off hashers,
// and feed inputs directly from the walker.
if w.ProgressTickIntervalS < 0 {
newParallelHasher(w.Dir, w.BlockSize, w.Hashers, finishedChan, toHashChan, nil, nil)
newParallelHasher(w.Dir, w.BlockSize, w.Hashers, finishedChan, toHashChan, nil, nil, w.Cancel)
return finishedChan, nil
}
@@ -149,7 +151,7 @@ func (w *Walker) Walk() (chan protocol.FileInfo, error) {
realToHashChan := make(chan protocol.FileInfo)
done := make(chan struct{})
newParallelHasher(w.Dir, w.BlockSize, w.Hashers, finishedChan, realToHashChan, &progress, done)
newParallelHasher(w.Dir, w.BlockSize, w.Hashers, finishedChan, realToHashChan, &progress, done, w.Cancel)
// A routine which actually emits the FolderScanProgress events
// every w.ProgressTicker ticks, until the hasher routines terminate.
@@ -168,13 +170,21 @@ func (w *Walker) Walk() (chan protocol.FileInfo, error) {
"current": current,
"total": total,
})
case <-w.Cancel:
ticker.Stop()
return
}
}
}()
loop:
for _, file := range filesToHash {
l.Debugln("real to hash:", file.Name)
realToHashChan <- file
select {
case realToHashChan <- file:
case <-w.Cancel:
break loop
}
}
close(realToHashChan)
}()
@@ -329,7 +339,11 @@ func (w *Walker) walkAndHashFiles(fchan, dchan chan protocol.FileInfo) filepath.
l.Debugln("symlink changedb:", p, f)
dchan <- f
select {
case dchan <- f:
case <-w.Cancel:
return errors.New("cancelled")
}
return skip
}
@@ -363,7 +377,13 @@ func (w *Walker) walkAndHashFiles(fchan, dchan chan protocol.FileInfo) filepath.
Modified: mtime.Unix(),
}
l.Debugln("dir:", p, f)
dchan <- f
select {
case dchan <- f:
case <-w.Cancel:
return errors.New("cancelled")
}
return nil
}
@@ -406,7 +426,12 @@ func (w *Walker) walkAndHashFiles(fchan, dchan chan protocol.FileInfo) filepath.
CachedSize: info.Size(),
}
l.Debugln("to hash:", p, f)
fchan <- f
select {
case fchan <- f:
case <-w.Cancel:
return errors.New("cancelled")
}
}
return nil

View File

@@ -190,11 +190,7 @@ func readTarGz(dir string, r io.Reader) (string, error) {
return "", err
}
shortName := path.Base(hdr.Name)
l.Debugf("considering file %q", shortName)
err = archiveFileVisitor(dir, &tempName, &sig, shortName, tr)
err = archiveFileVisitor(dir, &tempName, &sig, hdr.Name, tr)
if err != nil {
return "", err
}
@@ -227,16 +223,12 @@ func readZip(dir string, r io.Reader) (string, error) {
// Iterate through the files in the archive.
for _, file := range archive.File {
shortName := path.Base(file.Name)
l.Debugf("considering file %q", shortName)
inFile, err := file.Open()
if err != nil {
return "", err
}
err = archiveFileVisitor(dir, &tempName, &sig, shortName, inFile)
err = archiveFileVisitor(dir, &tempName, &sig, file.Name, inFile)
inFile.Close()
if err != nil {
return "", err
@@ -256,18 +248,26 @@ func readZip(dir string, r io.Reader) (string, error) {
// archiveFileVisitor is called for each file in an archive. It may set
// tempFile and signature.
func archiveFileVisitor(dir string, tempFile *string, signature *[]byte, filename string, filedata io.Reader) error {
func archiveFileVisitor(dir string, tempFile *string, signature *[]byte, archivePath string, filedata io.Reader) error {
var err error
filename := path.Base(archivePath)
archiveDir := path.Dir(archivePath)
archiveDirs := strings.Split(archiveDir, "/")
if len(archiveDirs) > 1 {
//don't consider files in subfolders
return nil
}
l.Debugf("considering file %s", archivePath)
switch filename {
case "syncthing", "syncthing.exe":
l.Debugln("reading binary")
l.Debugf("found upgrade binary %s", archivePath)
*tempFile, err = writeBinary(dir, filedata)
if err != nil {
return err
}
case "syncthing.sig", "syncthing.exe.sig":
l.Debugln("reading signature")
l.Debugf("found signature %s", archivePath)
*signature, err = ioutil.ReadAll(filedata)
if err != nil {
return err

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-BEP" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-BEP" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-bep \- Block Exchange Protocol v1
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-CONFIG" "5" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-CONFIG" "5" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-config \- Syncthing Configuration
.
@@ -598,6 +598,22 @@ the configuration and index.
.B releasesURL
The URL from which release information is loaded, for automatic upgrades.
.UNINDENT
.SH SYNCING CONFIGURATION FILES
.sp
Syncing configuration files between devices (such that multiple devices are
using the same configuration files) can cause issues. This is easy to do
accidentally if you sync your home folder between devices. A common symptom
of syncing configuration files is two devices ending up with the same Device ID.
.sp
If you want to use syncthing to backup your configuration files, it is recommended
that the files you are backing up are in a folder\-master to prevent other
devices from overwriting the per device configuration. The folder on the remote
device(s) should not be used as configuration for the remote devices.
.sp
If you\(aqd like to sync your home folder in non\-master mode, you may add the
folder that stores the configuration files to the ignore list\&.
If you\(aqd also like to backup your configuration files, add another folder in
master mode for just the configuration folder.
.SH AUTHOR
The Syncthing Authors
.SH COPYRIGHT

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-DEVICE-IDS" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-DEVICE-IDS" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-device-ids \- Understanding Device IDs
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-EVENT-API" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-EVENT-API" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-event-api \- Event API
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-FAQ" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-FAQ" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-faq \- Frequently Asked Questions
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-GLOBALDISCO" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-GLOBALDISCO" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-globaldisco \- Global Discovery Protocol v3
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-LOCALDISCO" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-LOCALDISCO" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-localdisco \- Local Discovery Protocol v3
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-NETWORKING" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-NETWORKING" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-networking \- Firewall Setup
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-REST-API" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-REST-API" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-rest-api \- REST API
.
@@ -83,30 +83,63 @@ the corresponding GET request. The configuration will be saved to disk and the
\fBconfigInSync\fP flag set to false. Restart Syncthing to activate.
.SS GET /rest/system/connections
.sp
Returns the list of current connections and some metadata associated
with the connection/peer.
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
Return format changed in 0.12.0.
.UNINDENT
.UNINDENT
.sp
Returns the list of configured devices and some metadata associated
with them. The list also contains the local device itself as not connected.
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
{
"connections": {
"SMAHWLH\-AP74FAB\-QWLDYGV\-Q65ASPL\-GAAR2TB\-KEF5FLB\-DRLZCPN\-DJBFZAG": {
"address": "172.21.20.78:22000",
"at": "2015\-03\-16T21:51:38.672758819+01:00",
"clientVersion": "v0.10.27",
"inBytesTotal": 415980,
"outBytesTotal": 396300
}
},
"total": {
"address": "",
"at": "2015\-03\-16T21:51:38.672868814+01:00",
"clientVersion": "",
"inBytesTotal": 415980,
"outBytesTotal": 396300
}
"total" : {
"paused" : false,
"clientVersion" : "",
"at" : "2015\-11\-07T17:29:47.691637262+01:00",
"connected" : false,
"inBytesTotal" : 1479,
"type" : "direct\-accept",
"outBytesTotal" : 1318,
"address" : ""
},
"connections" : {
"YZJBJFX\-RDBL7WY\-6ZGKJ2D\-4MJB4E7\-ZATSDUY\-LD6Y3L3\-MLFUYWE\-AEMXJAC" : {
"connected" : true,
"inBytesTotal" : 556,
"paused" : false,
"at" : "2015\-11\-07T17:29:47.691548971+01:00",
"clientVersion" : "v0.12.1",
"address" : "127.0.0.1:22002",
"type" : "direct\-dial",
"outBytesTotal" : 550
},
"DOVII4U\-SQEEESM\-VZ2CVTC\-CJM4YN5\-QNV7DCU\-5U3ASRL\-YVFG6TH\-W5DV5AA" : {
"outBytesTotal" : 0,
"type" : "direct\-accept",
"address" : "",
"at" : "0001\-01\-01T00:00:00Z",
"clientVersion" : "",
"paused" : false,
"inBytesTotal" : 0,
"connected" : false
},
"UYGDMA4\-TPHOFO5\-2VQYDCC\-7CWX7XW\-INZINQT\-LE4B42N\-4JUZTSM\-IWCSXA4" : {
"address" : "",
"type" : "direct\-accept",
"outBytesTotal" : 0,
"connected" : false,
"inBytesTotal" : 0,
"paused" : false,
"at" : "0001\-01\-01T00:00:00Z",
"clientVersion" : ""
}
}
}
.ft P
.fi
@@ -569,6 +602,13 @@ needed by this device in order for it to become in sync.
.fi
.UNINDENT
.UNINDENT
.sp
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.
.UNINDENT
.UNINDENT
.SS POST /rest/db/prio
.sp
Moves the file to the top of the download queue.
@@ -743,19 +783,55 @@ Returns the data sent in the anonymous usage report.
.nf
.ft C
{
"folderMaxFiles": 42106,
"folderMaxMiB": 12563,
"longVersion": "syncthing v0.10.27+5\-g36c93b7 (go1.4 darwin\-amd64 default) jb@syno 2015\-03\-16 20:43:34 UTC",
"memorySize": 16384,
"memoryUsageMiB": 41,
"numDevices": 10,
"numFolders": 4,
"platform": "darwin\-amd64",
"sha256Perf": 122.38,
"totFiles": 45180,
"totMiB": 18151,
"uniqueID": "6vulmdGw",
"version": "v0.10.27+5\-g36c93b7"
"folderMaxMiB" : 0,
"platform" : "linux\-amd64",
"totMiB" : 0,
"longVersion" : "syncthing v0.12.2 \e"Beryllium Bedbug\e" (go1.4.3 linux\-amd64 default) unknown\-user@build2.syncthing.net 2015\-11\-09 13:23:26 UTC",
"upgradeAllowedManual" : true,
"totFiles" : 3,
"folderUses" : {
"ignorePerms" : 0,
"autoNormalize" : 0,
"readonly" : 0,
"ignoreDelete" : 0
},
"memoryUsageMiB" : 13,
"version" : "v0.12.2",
"sha256Perf" : 27.28,
"numFolders" : 2,
"memorySize" : 1992,
"announce" : {
"defaultServersIP" : 0,
"otherServers" : 0,
"globalEnabled" : false,
"defaultServersDNS" : 1,
"localEnabled" : false
},
"usesRateLimit" : false,
"numCPU" : 2,
"uniqueID" : "",
"urVersion" : 2,
"rescanIntvs" : [
60,
60
],
"numDevices" : 2,
"folderMaxFiles" : 3,
"relays" : {
"defaultServers" : 1,
"enabled" : true,
"otherServers" : 0
},
"deviceUses" : {
"compressMetadata" : 1,
"customCertName" : 0,
"staticAddr" : 1,
"compressAlways" : 0,
"compressNever" : 1,
"introducer" : 0,
"dynamicAddr" : 1
},
"upgradeAllowedAuto" : false
}
.ft P
.fi

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-SECURITY" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-SECURITY" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-security \- Security Principles
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-STIGNORE" "5" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-STIGNORE" "5" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-stignore \- Prevent files from being synchronized to other nodes
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "TODO" "7" "November 04, 2015" "v0.12" "Syncthing"
.TH "TODO" "7" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
Todo \- Keep automatic backups of deleted files by other nodes
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING" "1" "November 04, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING" "1" "November 14, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing \- Syncthing
.

View File

@@ -32,6 +32,7 @@ var excludeCommits = stringSetFromStrings([]string{
"4b76ec40c07078beaa2c5e250ed7d9bd6276a718",
"32a76901a91ff0f663db6f0830e0aedec946e4d0",
"3626003f680bad3e63677982576d3a05421e88e9",
"342036408e65bd25bb6afbcc705e2e2c013bb01f",
})
func init() {

View File

@@ -47,7 +47,7 @@ func TestGetIndex(t *testing.T) {
p := startInstance(t, 2)
defer checkedStop(t, p)
// Check for explicint index.html
// Check for explicit index.html
res, err := http.Get("http://localhost:8082/index.html")
if err != nil {

View File

@@ -220,7 +220,7 @@ func alterFiles(dir string) error {
/*
This fails. Bug?
// Rename the file, while potentially moving it up in the directory hiearachy
// Rename the file, while potentially moving it up in the directory hierarchy
case r == 4 && comps > 2 && (info.Mode().IsRegular() || rand.Float64() < 0.2):
rpath := filepath.Dir(path)
if rand.Float64() < 0.2 {