mirror of
https://github.com/syncthing/syncthing.git
synced 2026-01-03 11:29:10 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2df78a9313 | ||
|
|
d2d32f26c7 | ||
|
|
473df1bd19 | ||
|
|
880f417ae3 | ||
|
|
043fa7f489 | ||
|
|
9b0768a71b | ||
|
|
446b21c568 | ||
|
|
b3c2ffc96a | ||
|
|
b5f652a815 | ||
|
|
9ec7de643e | ||
|
|
2553ba0463 | ||
|
|
52ee7d5724 | ||
|
|
d4ef6a6285 | ||
|
|
56b7d3c28d | ||
|
|
ae94b726a7 | ||
|
|
a88e4db1ee | ||
|
|
0ebd4a6ba1 | ||
|
|
1448cfe66a | ||
|
|
d6c9afd07f | ||
|
|
799f55e7ae | ||
|
|
04a3db132f | ||
|
|
d06204959e |
2
auto/doc.go
Normal file
2
auto/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package auto contains auto generated files for web assets.
|
||||
package auto
|
||||
@@ -2324,171 +2324,172 @@ func init() {
|
||||
data, _ = ioutil.ReadAll(gr)
|
||||
Assets["angular.min.js"] = data
|
||||
gr, _ = gzip.NewReader(bytes.NewBuffer([]byte{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd5, 0x5b, 0x6d, 0x6f, 0xdb, 0x38,
|
||||
0x12, 0xfe, 0x9e, 0x5f, 0xc1, 0xed, 0xf6, 0x20, 0x39, 0x71, 0x6d, 0x77, 0x71, 0x58, 0x2c, 0x92,
|
||||
0x26, 0x40, 0x37, 0x7d, 0x41, 0xae, 0x2f, 0x59, 0xd4, 0xbd, 0xfd, 0x12, 0xe4, 0x03, 0x6d, 0xd1,
|
||||
0x36, 0x1b, 0x99, 0xd4, 0x91, 0x54, 0x12, 0x23, 0xf0, 0x7f, 0xbf, 0x21, 0x45, 0xc9, 0xa4, 0x44,
|
||||
0xcb, 0x56, 0x72, 0xdd, 0xde, 0x0a, 0x48, 0x62, 0x93, 0xc3, 0x79, 0x79, 0x38, 0x1c, 0x0e, 0x47,
|
||||
0xcc, 0xf0, 0xf0, 0x9b, 0x4c, 0x29, 0x53, 0x68, 0x22, 0xf8, 0x9d, 0x24, 0xe2, 0x18, 0x29, 0x91,
|
||||
0x93, 0x3e, 0x9a, 0x72, 0xa6, 0x28, 0xcb, 0x49, 0xf9, 0x3d, 0x4b, 0x73, 0xa9, 0x7f, 0x8a, 0xef,
|
||||
0xe8, 0x70, 0x78, 0x30, 0x3c, 0x9c, 0xa7, 0x7c, 0x82, 0x53, 0xf4, 0xfc, 0x18, 0xcd, 0x70, 0x2a,
|
||||
0x81, 0x08, 0xb3, 0x79, 0x9e, 0x62, 0x61, 0xbf, 0x6b, 0xa2, 0x83, 0x28, 0x87, 0x0f, 0x52, 0x09,
|
||||
0x3a, 0x55, 0xd1, 0xc9, 0xc1, 0xc1, 0x2d, 0x16, 0x48, 0xae, 0xd8, 0x54, 0x2d, 0x28, 0x9b, 0xa3,
|
||||
0xd3, 0x72, 0xc4, 0x60, 0xc9, 0x93, 0x3c, 0x25, 0x71, 0x54, 0xf5, 0x45, 0x7d, 0x74, 0x75, 0xdd,
|
||||
0x83, 0x11, 0x55, 0xcb, 0x40, 0xab, 0x24, 0x78, 0x9a, 0x12, 0x11, 0x47, 0xe3, 0xb2, 0xf5, 0x5c,
|
||||
0x89, 0x14, 0x68, 0x67, 0x39, 0x7c, 0xa7, 0x9c, 0xa1, 0xf8, 0xb9, 0x9c, 0xf2, 0x0c, 0x74, 0x79,
|
||||
0xbe, 0x50, 0x2a, 0xeb, 0xa1, 0x87, 0x03, 0x04, 0x8f, 0x16, 0x9b, 0x09, 0x72, 0xfb, 0x06, 0x2b,
|
||||
0x02, 0x52, 0x47, 0x7d, 0xd3, 0xaa, 0x1f, 0x10, 0x4c, 0xd2, 0xf7, 0x44, 0x5d, 0x7e, 0x80, 0x76,
|
||||
0x6d, 0x1a, 0x88, 0xd4, 0xed, 0x05, 0x1b, 0x2d, 0x93, 0x11, 0xc3, 0x59, 0x42, 0xff, 0xc3, 0xfa,
|
||||
0xa4, 0xd6, 0x39, 0xa3, 0xf3, 0x66, 0xfb, 0x72, 0x75, 0xf1, 0x06, 0x5a, 0xa3, 0xc8, 0x6b, 0x65,
|
||||
0x20, 0x49, 0x33, 0xb9, 0xba, 0x0e, 0x30, 0xb9, 0x60, 0xda, 0xa2, 0x4a, 0x05, 0xa7, 0x9f, 0x08,
|
||||
0xc1, 0x45, 0x60, 0x9c, 0x24, 0x84, 0xbd, 0xd5, 0x7d, 0x56, 0x92, 0xe9, 0x1b, 0x0e, 0xd1, 0x18,
|
||||
0xb0, 0x66, 0x73, 0x89, 0x26, 0x64, 0xc6, 0x05, 0x41, 0x13, 0xce, 0x53, 0x89, 0x52, 0xce, 0x6f,
|
||||
0xa0, 0x45, 0x29, 0x22, 0x7c, 0x1e, 0x4a, 0x19, 0x62, 0xe0, 0x5e, 0x21, 0xf2, 0x40, 0x93, 0x63,
|
||||
0x14, 0x7d, 0xa4, 0x52, 0x11, 0x06, 0xcc, 0x00, 0x5c, 0xd0, 0x7b, 0x0a, 0x93, 0x6a, 0x40, 0x47,
|
||||
0x7f, 0x08, 0xae, 0xf8, 0x94, 0xa7, 0xa8, 0xa0, 0x40, 0xaf, 0x93, 0x44, 0x10, 0x29, 0x89, 0x04,
|
||||
0x42, 0xb5, 0xca, 0xc0, 0x61, 0x22, 0x45, 0xee, 0x15, 0x7c, 0x83, 0x66, 0x85, 0x85, 0x2a, 0x3c,
|
||||
0x66, 0xdd, 0xaf, 0x09, 0x78, 0xff, 0xef, 0x0b, 0x3b, 0xd4, 0x91, 0x00, 0x8d, 0x35, 0xbe, 0x1d,
|
||||
0xb9, 0x7e, 0xc2, 0xf7, 0x63, 0xc2, 0x92, 0x0f, 0x93, 0xcc, 0x65, 0x7b, 0x99, 0xab, 0x39, 0xd7,
|
||||
0x0e, 0xf7, 0x45, 0xcf, 0xff, 0x47, 0xba, 0xa4, 0x0a, 0xc5, 0x1f, 0x7e, 0xcf, 0x64, 0x6f, 0xc3,
|
||||
0x9e, 0xe5, 0xcb, 0x09, 0x11, 0x3b, 0x05, 0x7c, 0x01, 0x96, 0x98, 0x5d, 0x30, 0x40, 0xf2, 0x16,
|
||||
0xa7, 0x63, 0x47, 0x48, 0xd1, 0x83, 0xca, 0x2e, 0x14, 0x3f, 0x8a, 0xbb, 0x75, 0xb8, 0xb0, 0x00,
|
||||
0xdb, 0xf9, 0x34, 0x19, 0x7f, 0x60, 0x81, 0x61, 0x11, 0xa5, 0x5f, 0xc8, 0x7f, 0x72, 0x20, 0x74,
|
||||
0x71, 0x02, 0xf4, 0x10, 0x60, 0x05, 0xa3, 0x59, 0x62, 0xe0, 0xda, 0x90, 0x74, 0x93, 0x01, 0x8c,
|
||||
0xce, 0x17, 0xb0, 0xb6, 0x49, 0x6d, 0x22, 0xb4, 0x80, 0x77, 0x34, 0x25, 0xa8, 0xe8, 0x2d, 0xe6,
|
||||
0x63, 0xef, 0x99, 0x68, 0x80, 0x85, 0x93, 0x4b, 0x96, 0xae, 0x3c, 0x88, 0x70, 0x82, 0x6c, 0x9b,
|
||||
0xe5, 0xa6, 0x17, 0xc0, 0x4e, 0x7d, 0x5f, 0xa7, 0x29, 0xbf, 0x7b, 0x43, 0x52, 0xa2, 0x88, 0xc3,
|
||||
0xcd, 0xb4, 0xa2, 0xaa, 0xb9, 0x0b, 0xc3, 0x77, 0x5c, 0x8f, 0x1d, 0xaf, 0x96, 0x10, 0x5b, 0x6f,
|
||||
0x5c, 0x04, 0x8a, 0x0e, 0xe4, 0xf4, 0x74, 0x61, 0xfb, 0xde, 0x44, 0xdc, 0xd7, 0x8c, 0xbd, 0x65,
|
||||
0x78, 0x92, 0x92, 0xc4, 0x5d, 0x3a, 0x45, 0x30, 0x86, 0x3e, 0x0e, 0xb1, 0xb0, 0xab, 0xbe, 0x1f,
|
||||
0xf9, 0x74, 0x0b, 0x5f, 0xd3, 0xd3, 0x8d, 0xed, 0xb5, 0x8d, 0x46, 0x55, 0x50, 0x2e, 0x83, 0xec,
|
||||
0x38, 0x9f, 0x4e, 0x09, 0x49, 0x48, 0x12, 0x97, 0x81, 0x59, 0x3f, 0x74, 0x86, 0xe2, 0x9f, 0x36,
|
||||
0x71, 0xd8, 0xed, 0x32, 0xb1, 0x2a, 0x8e, 0x7e, 0x66, 0x44, 0xdd, 0x71, 0x71, 0x63, 0xe2, 0x5d,
|
||||
0xd4, 0xd3, 0xbb, 0x05, 0x4e, 0xe3, 0x68, 0x41, 0x13, 0x12, 0xf5, 0x4e, 0x3c, 0xea, 0x40, 0x3c,
|
||||
0x2f, 0xbb, 0xd6, 0x07, 0xc5, 0xef, 0xb0, 0x6e, 0xef, 0x30, 0xf8, 0x65, 0x53, 0xb1, 0x47, 0xe8,
|
||||
0xf5, 0x30, 0xc1, 0xd3, 0x9b, 0x44, 0xf0, 0x0c, 0x50, 0x02, 0x70, 0x14, 0x9d, 0x02, 0x4e, 0x37,
|
||||
0x64, 0x35, 0xe1, 0x58, 0x24, 0x76, 0x6f, 0x5c, 0xb7, 0xa9, 0x6d, 0x28, 0x76, 0xe9, 0xad, 0xb7,
|
||||
0x93, 0x73, 0xbe, 0xcc, 0xb0, 0x20, 0x31, 0xee, 0xa3, 0x49, 0x5d, 0x71, 0x3c, 0xf8, 0x0c, 0x14,
|
||||
0x7a, 0x23, 0x3a, 0x3d, 0x75, 0x37, 0xa6, 0xba, 0x19, 0x82, 0xa8, 0x5c, 0x30, 0xf4, 0xe2, 0x65,
|
||||
0x5d, 0x60, 0xc9, 0x68, 0xd2, 0x8d, 0xd1, 0x56, 0x3e, 0x95, 0x42, 0xaf, 0x50, 0xc9, 0xb2, 0x93,
|
||||
0x2e, 0xb6, 0xb3, 0x62, 0x73, 0x56, 0xb1, 0x39, 0x71, 0x01, 0x32, 0xfb, 0xfe, 0x60, 0x4e, 0x54,
|
||||
0x1c, 0x0d, 0xb5, 0x73, 0x0e, 0x6f, 0x89, 0x90, 0x00, 0x18, 0x4c, 0x8f, 0xd4, 0xee, 0x27, 0x65,
|
||||
0xbc, 0x49, 0x16, 0x12, 0xac, 0xb0, 0xab, 0x84, 0x35, 0xcf, 0x0e, 0x81, 0xa9, 0xd0, 0x04, 0x96,
|
||||
0xbd, 0x9d, 0xb1, 0x06, 0x7f, 0xb9, 0x82, 0xfd, 0x6a, 0xd9, 0x85, 0x7d, 0x31, 0xc2, 0xe3, 0xee,
|
||||
0xf4, 0xda, 0xec, 0x41, 0xf7, 0x99, 0xcf, 0x27, 0x9b, 0xb8, 0xd7, 0x90, 0x5d, 0x24, 0x0f, 0x7b,
|
||||
0xc9, 0x76, 0x24, 0x54, 0x79, 0x8b, 0x2f, 0xbf, 0x41, 0x31, 0xb8, 0xcc, 0x4c, 0xe6, 0x33, 0xa8,
|
||||
0x92, 0x01, 0x74, 0xda, 0x4a, 0x61, 0xf7, 0xec, 0xc1, 0x37, 0xd8, 0x6c, 0x63, 0x70, 0x7a, 0xbd,
|
||||
0x38, 0x3d, 0xf6, 0x3a, 0x0f, 0x2b, 0xf3, 0x20, 0x9f, 0xd1, 0x17, 0x92, 0x71, 0x49, 0x15, 0x17,
|
||||
0x94, 0xc8, 0xab, 0xd1, 0xb5, 0x99, 0x59, 0xe9, 0xeb, 0x66, 0x06, 0x0e, 0x24, 0x17, 0x2a, 0x76,
|
||||
0x9c, 0xbf, 0x17, 0x34, 0xa0, 0x14, 0xc2, 0x7c, 0x36, 0xee, 0xb2, 0xdb, 0x02, 0xe6, 0x50, 0x27,
|
||||
0x9c, 0x8f, 0x43, 0xb4, 0x4a, 0xe2, 0xcc, 0xdc, 0xb9, 0x6d, 0x4d, 0x0d, 0xd6, 0x3d, 0x3f, 0xd1,
|
||||
0x14, 0x64, 0x06, 0x4a, 0x2c, 0xf4, 0xea, 0xaf, 0x04, 0x7a, 0xae, 0xf3, 0x04, 0xb7, 0xdb, 0xed,
|
||||
0x7a, 0xad, 0xb8, 0x98, 0xd8, 0xd4, 0x55, 0x90, 0x19, 0x14, 0x74, 0xb1, 0xc0, 0x66, 0xe0, 0x2a,
|
||||
0x52, 0x24, 0xbc, 0x71, 0x18, 0x05, 0x77, 0x7c, 0x19, 0xb0, 0xf7, 0x9f, 0xdd, 0x32, 0x93, 0xdf,
|
||||
0xdb, 0x96, 0xc2, 0x5d, 0xef, 0xc0, 0x0c, 0x7d, 0x70, 0x00, 0xa7, 0xba, 0x8b, 0x7b, 0x7d, 0x8f,
|
||||
0x42, 0x3f, 0x2a, 0x01, 0x82, 0x58, 0xd3, 0xbd, 0xa8, 0x0e, 0x19, 0x3d, 0x34, 0x44, 0x2f, 0x47,
|
||||
0xa3, 0x51, 0x93, 0x9a, 0x26, 0xb5, 0x35, 0xe1, 0x9c, 0x4b, 0x80, 0x47, 0xd0, 0x9b, 0x29, 0x83,
|
||||
0x34, 0x4a, 0x9f, 0x5b, 0x82, 0xbd, 0x3c, 0x57, 0x55, 0xb7, 0xd7, 0x0f, 0x07, 0x00, 0x14, 0xd3,
|
||||
0x04, 0x51, 0x86, 0x42, 0xd6, 0x19, 0x6d, 0xf4, 0xde, 0x6b, 0xdc, 0x75, 0x81, 0xe5, 0xe5, 0x1d,
|
||||
0x83, 0xec, 0x3e, 0x23, 0x42, 0xad, 0x60, 0x58, 0x2f, 0x44, 0xaf, 0x9f, 0xf2, 0x68, 0x78, 0xd2,
|
||||
0xe8, 0x5d, 0x37, 0xb1, 0x11, 0xab, 0x2d, 0x5c, 0xb4, 0xd0, 0x2b, 0x9a, 0x5c, 0x57, 0xc6, 0x7d,
|
||||
0xc2, 0x6a, 0x31, 0x58, 0xe2, 0xfb, 0x78, 0xd4, 0x47, 0xbf, 0xa1, 0xc3, 0x62, 0x46, 0x0c, 0xc5,
|
||||
0x05, 0xfb, 0x7d, 0xa5, 0x88, 0xfc, 0xca, 0x15, 0x64, 0x22, 0x2f, 0x02, 0x47, 0xb3, 0x06, 0x95,
|
||||
0x86, 0x5f, 0x25, 0xbd, 0xa6, 0x86, 0x9e, 0xe4, 0x0a, 0xb8, 0xed, 0xa2, 0x21, 0x1b, 0xde, 0x47,
|
||||
0xb6, 0x47, 0xb6, 0x55, 0xf8, 0x1a, 0x4d, 0xb1, 0x9a, 0x2e, 0x50, 0x4c, 0xb6, 0x41, 0xdb, 0x00,
|
||||
0x65, 0xb4, 0xaf, 0x09, 0x01, 0xc2, 0xe6, 0x6c, 0x78, 0xee, 0x74, 0x74, 0x5a, 0x13, 0xd7, 0xe4,
|
||||
0xe0, 0x3b, 0x98, 0x3b, 0xa0, 0x68, 0xf2, 0x47, 0xac, 0x43, 0xce, 0xe9, 0x1f, 0xa0, 0x3b, 0x44,
|
||||
0x1d, 0x06, 0xb1, 0xa1, 0xd3, 0x42, 0xa5, 0x7d, 0xc4, 0xf0, 0xb2, 0xe6, 0x95, 0xc5, 0x12, 0x30,
|
||||
0xf8, 0x20, 0x0a, 0x99, 0x87, 0x71, 0xf5, 0x94, 0xb0, 0xb9, 0x5a, 0x40, 0xc3, 0xd1, 0x51, 0x68,
|
||||
0x22, 0x34, 0x17, 0x54, 0xda, 0x0a, 0x3b, 0x11, 0x7c, 0x1d, 0xc8, 0x2c, 0xa5, 0x5a, 0xb5, 0x7a,
|
||||
0xba, 0xb9, 0x99, 0x8c, 0xeb, 0xc1, 0x78, 0x01, 0x5b, 0xd3, 0xe7, 0x62, 0xb0, 0xe6, 0x71, 0xa5,
|
||||
0x7f, 0x59, 0x61, 0xe0, 0x3a, 0x2f, 0xaf, 0xdb, 0xe0, 0x32, 0x8a, 0x99, 0xbd, 0x6d, 0x63, 0x69,
|
||||
0x3d, 0xad, 0x2b, 0x9f, 0x22, 0x9b, 0xda, 0x88, 0xd3, 0x09, 0x55, 0xf5, 0x6d, 0x9b, 0x6b, 0x05,
|
||||
0x72, 0xab, 0xb0, 0x26, 0x21, 0x09, 0x67, 0x1d, 0x24, 0xec, 0x25, 0xc0, 0xd2, 0xd6, 0xbc, 0xb6,
|
||||
0x9e, 0x15, 0x97, 0x9b, 0x39, 0xb8, 0x42, 0x37, 0xe7, 0x29, 0x8a, 0x26, 0x5d, 0xf7, 0xac, 0xaa,
|
||||
0xd4, 0x12, 0x96, 0xb4, 0xf6, 0x77, 0x6c, 0x9d, 0x5a, 0x8c, 0x21, 0xbd, 0xcf, 0xa5, 0xb7, 0x69,
|
||||
0x9b, 0xd4, 0x64, 0x36, 0x77, 0x45, 0x68, 0xef, 0xd4, 0xeb, 0xc0, 0x4b, 0x7a, 0xaa, 0xf8, 0x61,
|
||||
0x07, 0xd8, 0x5c, 0xd6, 0x71, 0x12, 0x3d, 0x09, 0x9a, 0xb0, 0xae, 0x6d, 0xd9, 0x3e, 0xd0, 0x19,
|
||||
0x10, 0x9c, 0x4d, 0x4d, 0xa6, 0x0a, 0xb9, 0x39, 0xec, 0x37, 0xa1, 0xa9, 0xb1, 0x50, 0x47, 0x17,
|
||||
0x0c, 0xe9, 0x54, 0x24, 0xaa, 0x41, 0x8e, 0x88, 0x2e, 0xd5, 0x6d, 0x1f, 0xa6, 0xc7, 0xe8, 0x5a,
|
||||
0x40, 0x1c, 0xa1, 0x23, 0x54, 0x17, 0x7b, 0x84, 0xa2, 0x7f, 0xf4, 0xea, 0x1c, 0x9d, 0xdc, 0xbd,
|
||||
0x9e, 0xbc, 0x47, 0x6f, 0xa8, 0xb4, 0xb6, 0xc3, 0xea, 0xde, 0x0a, 0xeb, 0xc5, 0xd4, 0x24, 0xdf,
|
||||
0x7f, 0x03, 0x50, 0xf9, 0x4d, 0x57, 0x3c, 0x6d, 0xa2, 0xd7, 0x05, 0xb4, 0x25, 0xec, 0xb6, 0x72,
|
||||
0x3b, 0x5a, 0xe7, 0x29, 0x96, 0x7f, 0x13, 0x1f, 0xb4, 0xcb, 0xb1, 0x2b, 0x66, 0x99, 0xa0, 0x4b,
|
||||
0x2c, 0x56, 0x5d, 0x30, 0xa3, 0x6c, 0xc6, 0xb7, 0x43, 0xa6, 0x0f, 0x2a, 0x7f, 0x31, 0x62, 0x56,
|
||||
0x31, 0x03, 0x9a, 0x3d, 0x27, 0xb5, 0x9c, 0x72, 0xa3, 0x38, 0x67, 0x37, 0x90, 0x0e, 0xc2, 0x79,
|
||||
0xb7, 0xa0, 0xed, 0xb5, 0xcc, 0xbf, 0x33, 0x05, 0x3f, 0xcc, 0xa4, 0x5a, 0x50, 0x88, 0xda, 0x6c,
|
||||
0xdb, 0x6e, 0xca, 0x9f, 0x64, 0xe7, 0xb4, 0x68, 0x65, 0x7c, 0x4d, 0xf7, 0x2c, 0x4c, 0xf8, 0x67,
|
||||
0xfb, 0x90, 0x7e, 0xdf, 0x13, 0x9e, 0x94, 0x12, 0xa6, 0xfe, 0xdc, 0x2e, 0xbb, 0x31, 0xef, 0x56,
|
||||
0xcf, 0x96, 0x79, 0xb7, 0xa9, 0xc6, 0xfe, 0x68, 0x05, 0xf6, 0x6e, 0x2b, 0xd6, 0x25, 0x69, 0xd1,
|
||||
0xce, 0x87, 0x00, 0x36, 0xd7, 0x89, 0x54, 0x42, 0x27, 0xcd, 0xbf, 0x86, 0xb7, 0x48, 0x89, 0x6f,
|
||||
0xc9, 0x78, 0xf3, 0x8e, 0x61, 0xcb, 0xc9, 0x36, 0x78, 0x84, 0xae, 0xd5, 0xc0, 0xf6, 0xa8, 0x3a,
|
||||
0xec, 0xa8, 0x4d, 0x8c, 0x95, 0x28, 0xb3, 0xb8, 0xbe, 0x2e, 0xd5, 0xe1, 0xcc, 0x49, 0x0a, 0xee,
|
||||
0x41, 0xa1, 0xd2, 0xc8, 0xfb, 0x81, 0x82, 0x70, 0x03, 0xe7, 0xca, 0x40, 0x8a, 0x91, 0x71, 0x59,
|
||||
0xaf, 0xbd, 0xf4, 0xd1, 0xbf, 0xc6, 0x97, 0x9f, 0x07, 0xd2, 0xbc, 0x76, 0xa1, 0xb3, 0x55, 0xec,
|
||||
0x29, 0xd1, 0xeb, 0xa3, 0x87, 0x05, 0xc1, 0x09, 0x4c, 0xe6, 0x31, 0x7a, 0x88, 0xce, 0xe1, 0xe8,
|
||||
0x04, 0x7e, 0xf0, 0xe2, 0xeb, 0x2a, 0x23, 0xd1, 0x31, 0x8a, 0x70, 0x06, 0x1a, 0xc1, 0xa1, 0x00,
|
||||
0x94, 0x18, 0x7e, 0x93, 0x9c, 0x45, 0x6b, 0x4f, 0x66, 0x1c, 0xfd, 0x5c, 0xbe, 0xa2, 0xf9, 0xaa,
|
||||
0xeb, 0xb2, 0xa0, 0xf7, 0x94, 0xa7, 0x29, 0xce, 0x24, 0xf1, 0xab, 0x9f, 0xeb, 0x7a, 0x31, 0xc1,
|
||||
0x14, 0x65, 0x77, 0x14, 0x13, 0x5c, 0x63, 0xec, 0x08, 0x37, 0xbd, 0xdd, 0xf5, 0x7e, 0xaa, 0x26,
|
||||
0x93, 0x24, 0x54, 0x69, 0xbf, 0xd8, 0xe5, 0x91, 0x25, 0xdb, 0x5c, 0x08, 0x40, 0xc2, 0x8e, 0xb0,
|
||||
0x74, 0x0d, 0xe1, 0x9a, 0x29, 0x58, 0xff, 0xf6, 0x1e, 0xa6, 0xb0, 0x78, 0x61, 0xe8, 0x97, 0x74,
|
||||
0x9b, 0xcc, 0x06, 0xd5, 0xfb, 0xa8, 0xa2, 0x5c, 0x55, 0xba, 0x6c, 0xd5, 0xec, 0x15, 0xa7, 0x5c,
|
||||
0xa4, 0x4b, 0x03, 0x1e, 0x55, 0xc7, 0xad, 0x81, 0x01, 0x41, 0xbb, 0x81, 0xc5, 0x4e, 0x10, 0x1e,
|
||||
0x8a, 0x65, 0x05, 0xd2, 0x40, 0x8e, 0x6b, 0x06, 0xb4, 0x24, 0x2b, 0x38, 0x4c, 0x80, 0x02, 0xeb,
|
||||
0x3d, 0x20, 0xaa, 0x2f, 0x9d, 0xff, 0xb1, 0x6d, 0x89, 0x79, 0x1f, 0xd2, 0x6a, 0x9e, 0xa9, 0x9b,
|
||||
0x90, 0xbb, 0xcf, 0xd5, 0x1b, 0xcf, 0x3e, 0xa2, 0x6e, 0x19, 0x33, 0xa4, 0x51, 0xa3, 0x9a, 0x6f,
|
||||
0x4a, 0x13, 0x61, 0x23, 0xc3, 0x51, 0xcc, 0x0d, 0x5c, 0xd5, 0xc7, 0xfa, 0x01, 0xd0, 0xad, 0x0f,
|
||||
0xb6, 0x1d, 0x04, 0xb5, 0x74, 0x97, 0xd6, 0x9c, 0x04, 0x8b, 0xed, 0xe6, 0xa7, 0xcd, 0x76, 0xe3,
|
||||
0x3a, 0x5e, 0xb8, 0xa4, 0xad, 0x9f, 0x12, 0x8a, 0x41, 0x96, 0xcb, 0x45, 0x9d, 0x6b, 0xed, 0xc8,
|
||||
0x13, 0x4c, 0x6a, 0xea, 0x45, 0x4d, 0xcb, 0x6f, 0x5b, 0x78, 0x0c, 0xd6, 0x52, 0xbd, 0x71, 0x1d,
|
||||
0x83, 0xef, 0x5f, 0x1c, 0xfb, 0x02, 0xbb, 0xc8, 0x6e, 0x77, 0x2b, 0xd6, 0x79, 0x1f, 0x25, 0x9c,
|
||||
0x91, 0x9a, 0xbb, 0xed, 0x65, 0xe3, 0x5e, 0x3e, 0x69, 0xa5, 0xa0, 0x90, 0x03, 0x34, 0xa8, 0x36,
|
||||
0x31, 0x27, 0x14, 0x87, 0x1e, 0xb9, 0x1f, 0x55, 0x42, 0xb4, 0x9d, 0x4d, 0x33, 0xbe, 0x83, 0xbb,
|
||||
0xeb, 0xec, 0xca, 0xdf, 0xf8, 0x43, 0x3e, 0x5e, 0x1b, 0x1c, 0x8a, 0xe9, 0x35, 0xcd, 0xfd, 0x48,
|
||||
0x5e, 0x3e, 0x13, 0x41, 0xf0, 0xcd, 0x1e, 0x4b, 0xa2, 0x28, 0x5c, 0x02, 0xa7, 0x2d, 0x67, 0x79,
|
||||
0xb6, 0x59, 0x70, 0xe5, 0x26, 0x14, 0x8c, 0x0f, 0x1e, 0x79, 0xcb, 0xbb, 0x85, 0xfd, 0x56, 0x98,
|
||||
0xcb, 0xad, 0xf1, 0xde, 0xe6, 0x87, 0x2d, 0x20, 0xae, 0x16, 0x44, 0x94, 0x2a, 0xb6, 0x2f, 0xa1,
|
||||
0x2a, 0x5c, 0xf7, 0x11, 0x3b, 0x79, 0x7a, 0x14, 0x65, 0x35, 0x4c, 0xc0, 0x33, 0x4e, 0x1a, 0x7e,
|
||||
0xc7, 0x02, 0x81, 0x35, 0x94, 0xc7, 0x1b, 0x86, 0xce, 0xb4, 0xb6, 0x44, 0xce, 0xf2, 0x93, 0x93,
|
||||
0xb7, 0xca, 0x20, 0x34, 0x6a, 0x41, 0xe5, 0xce, 0xd8, 0xf2, 0x43, 0xc0, 0xd8, 0x71, 0xa8, 0x71,
|
||||
0xac, 0xbb, 0x62, 0x5b, 0x2b, 0x8b, 0xeb, 0x60, 0xa6, 0xa6, 0xcb, 0x5c, 0x3a, 0x29, 0x6e, 0x35,
|
||||
0xba, 0x71, 0xef, 0xa8, 0x32, 0xdd, 0x40, 0xd2, 0x30, 0xbf, 0xa0, 0x6f, 0xb3, 0xdf, 0x70, 0xdd,
|
||||
0x60, 0x50, 0x0c, 0x08, 0x82, 0x40, 0x06, 0x5f, 0xa9, 0xa9, 0x3a, 0xd6, 0xef, 0x3a, 0x85, 0x50,
|
||||
0xb0, 0x82, 0x8d, 0x4f, 0xd4, 0xdf, 0x06, 0xb6, 0xf8, 0x44, 0x31, 0xac, 0x72, 0x0a, 0xfd, 0xc7,
|
||||
0x05, 0x69, 0x9a, 0x12, 0x2c, 0xde, 0x96, 0x18, 0xb4, 0x66, 0x71, 0xee, 0x4d, 0x2c, 0xdf, 0xb6,
|
||||
0x10, 0x34, 0xa6, 0x12, 0x6c, 0xec, 0x0b, 0x3a, 0xe4, 0x0c, 0x42, 0x0a, 0x4b, 0xd2, 0x55, 0x73,
|
||||
0xb9, 0x42, 0x90, 0x70, 0x85, 0xb7, 0x4c, 0xc5, 0x4e, 0x4f, 0x34, 0x07, 0x5d, 0x77, 0x1b, 0x0b,
|
||||
0xfb, 0xa3, 0x34, 0x19, 0x34, 0xfc, 0x86, 0x03, 0x45, 0x96, 0xe2, 0x29, 0x89, 0xa7, 0xd5, 0x1e,
|
||||
0xd0, 0xaf, 0x9f, 0x44, 0x75, 0x5f, 0xcf, 0x8b, 0xb1, 0x35, 0xc0, 0x81, 0xcf, 0x96, 0xc3, 0x8a,
|
||||
0x29, 0x88, 0x95, 0x2f, 0xf2, 0xe0, 0xc0, 0x53, 0x5e, 0x6f, 0x8a, 0x7d, 0x8a, 0xbe, 0x79, 0xa3,
|
||||
0x36, 0x02, 0x3a, 0xb3, 0x11, 0x56, 0xc8, 0x24, 0x64, 0x4a, 0x97, 0xb0, 0x0d, 0x02, 0x1a, 0x29,
|
||||
0xac, 0xd4, 0x7c, 0xe9, 0xde, 0xfa, 0x4b, 0xe8, 0x9c, 0x2a, 0xa9, 0xaf, 0xb3, 0x4c, 0xcb, 0x88,
|
||||
0xac, 0x3d, 0x4c, 0x5f, 0x9e, 0xd2, 0x2b, 0xcc, 0xab, 0x56, 0xf9, 0x45, 0x69, 0xbb, 0x49, 0x14,
|
||||
0x0c, 0xca, 0x97, 0x44, 0xb3, 0x94, 0x73, 0x11, 0x9b, 0x8f, 0x29, 0x9f, 0x17, 0x1f, 0xf0, 0xc4,
|
||||
0x88, 0xee, 0xe9, 0xf7, 0x3e, 0x55, 0xcf, 0xcb, 0x51, 0x09, 0x86, 0x96, 0x5c, 0x7b, 0xc7, 0x04,
|
||||
0x3a, 0x82, 0x1b, 0x14, 0x9c, 0x2d, 0x95, 0x95, 0x5d, 0xa8, 0xb9, 0x76, 0xaf, 0x3d, 0xce, 0x68,
|
||||
0xaa, 0xf4, 0x95, 0x47, 0x86, 0x81, 0x02, 0xfb, 0x97, 0x1d, 0x4b, 0xed, 0xed, 0xe8, 0x4d, 0x07,
|
||||
0x65, 0x59, 0xae, 0xfa, 0x80, 0x40, 0x4a, 0x93, 0x80, 0x89, 0xa6, 0x7b, 0xa0, 0xf8, 0x3b, 0x7a,
|
||||
0x4f, 0x92, 0xb8, 0x02, 0xd0, 0x1b, 0xb5, 0xd9, 0x4b, 0xd6, 0xfe, 0x3d, 0xcc, 0x52, 0xa1, 0x09,
|
||||
0x65, 0xba, 0x28, 0xb7, 0xbf, 0x3e, 0xf5, 0xc2, 0x84, 0x69, 0x34, 0xd3, 0x90, 0xb3, 0x84, 0xcc,
|
||||
0x28, 0x23, 0x49, 0x38, 0xb3, 0x47, 0xd1, 0x08, 0x05, 0x2b, 0x4a, 0x1b, 0x2e, 0x67, 0xe0, 0x1c,
|
||||
0xbf, 0xfc, 0x13, 0x1d, 0xba, 0x7f, 0x1a, 0x49, 0x8e, 0xa1, 0x1c, 0x9e, 0x06, 0x48, 0x4f, 0x42,
|
||||
0x52, 0xdb, 0x51, 0xfa, 0x05, 0x26, 0xfc, 0x08, 0x45, 0xe8, 0x3d, 0xed, 0xa2, 0xda, 0x3e, 0x3a,
|
||||
0x3d, 0x41, 0x99, 0x4f, 0xfb, 0x29, 0xd3, 0xaa, 0xc5, 0x13, 0xc4, 0x7f, 0x08, 0x8b, 0xb7, 0x3c,
|
||||
0xcc, 0x12, 0x10, 0x1c, 0x26, 0xbb, 0xf4, 0x07, 0x3d, 0x26, 0xda, 0xe5, 0x67, 0x4b, 0xa2, 0xaf,
|
||||
0x0f, 0xff, 0x1f, 0xf9, 0xd9, 0x68, 0x64, 0x26, 0xaa, 0xfa, 0xd3, 0x82, 0x66, 0x9d, 0xf4, 0x29,
|
||||
0x7e, 0xd6, 0x45, 0xb3, 0x7d, 0x54, 0x7a, 0x8a, 0x9b, 0xed, 0xa5, 0x4b, 0xab, 0x12, 0x4f, 0x90,
|
||||
0x7e, 0xf3, 0x1d, 0x9c, 0x4c, 0xea, 0xb7, 0x9b, 0x8f, 0xf4, 0x31, 0x4f, 0xf9, 0x60, 0x51, 0x74,
|
||||
0x8b, 0x50, 0x9c, 0xde, 0xe1, 0x95, 0xfc, 0x5c, 0xde, 0x77, 0xfd, 0xfe, 0xfe, 0x3d, 0x6a, 0x01,
|
||||
0xce, 0x70, 0xd9, 0xa6, 0x71, 0x42, 0x85, 0xae, 0x83, 0xdf, 0x92, 0x38, 0xe2, 0xa6, 0xac, 0xfa,
|
||||
0x36, 0xd1, 0xc7, 0x9f, 0x36, 0xa5, 0x5d, 0x7c, 0x8a, 0x7f, 0x00, 0x80, 0x33, 0xcb, 0x79, 0xd4,
|
||||
0x77, 0x9a, 0x4d, 0x52, 0x61, 0xff, 0xc3, 0xa0, 0x6a, 0x56, 0x02, 0x33, 0x39, 0x4d, 0xf3, 0xa4,
|
||||
0xd1, 0x63, 0xb2, 0x81, 0xe3, 0x9a, 0x65, 0xb6, 0x40, 0x0a, 0xbc, 0x4f, 0xed, 0x47, 0x47, 0x84,
|
||||
0x73, 0xcf, 0x55, 0x91, 0x25, 0x88, 0x53, 0xfa, 0xea, 0xea, 0xab, 0x02, 0x30, 0x7d, 0x91, 0xf5,
|
||||
0xf4, 0x99, 0xbe, 0x56, 0xfe, 0x0c, 0xb1, 0xf9, 0x0b, 0x73, 0xaf, 0xe8, 0xf4, 0x99, 0x5f, 0x3c,
|
||||
0xbe, 0xb2, 0x3c, 0x07, 0x34, 0xb9, 0x7e, 0x76, 0xf6, 0x6a, 0x68, 0x46, 0x9e, 0x59, 0x09, 0x16,
|
||||
0xa6, 0xff, 0x02, 0xb3, 0x47, 0x5e, 0x2c, 0x43, 0x31, 0x00, 0x00,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd5, 0x1b, 0xdb, 0x6e, 0xdb, 0x38,
|
||||
0xf6, 0x3d, 0x5f, 0xc1, 0xe9, 0x74, 0x21, 0x39, 0x71, 0x6d, 0x77, 0xb0, 0x58, 0x2c, 0x92, 0x26,
|
||||
0x40, 0x9b, 0x5e, 0x90, 0xed, 0x25, 0x83, 0xba, 0x3b, 0x2f, 0x41, 0x1e, 0x68, 0x89, 0xb6, 0xd9,
|
||||
0xc8, 0xa4, 0x96, 0xa4, 0x93, 0x18, 0x81, 0xff, 0x7d, 0x0f, 0x29, 0x4a, 0x26, 0x25, 0x5a, 0xb6,
|
||||
0x92, 0xed, 0x74, 0xc7, 0x40, 0x5b, 0x9b, 0x3c, 0x3c, 0x37, 0x1e, 0x9e, 0x1b, 0xd9, 0xe1, 0xe1,
|
||||
0x77, 0x99, 0x51, 0xa6, 0xd0, 0x44, 0xf0, 0x3b, 0x49, 0xc4, 0x31, 0x52, 0x62, 0x49, 0xfa, 0x28,
|
||||
0xe1, 0x4c, 0x51, 0xb6, 0x24, 0xe5, 0xef, 0x3c, 0x5b, 0x4a, 0xfd, 0xa7, 0xf8, 0x8d, 0x0e, 0x87,
|
||||
0x07, 0xc3, 0xc3, 0x59, 0xc6, 0x27, 0x38, 0x43, 0xcf, 0x8f, 0xd1, 0x14, 0x67, 0x12, 0x80, 0x30,
|
||||
0x9b, 0x2d, 0x33, 0x2c, 0xec, 0x6f, 0x0d, 0x74, 0x10, 0x2d, 0xe1, 0x8b, 0x54, 0x82, 0x26, 0x2a,
|
||||
0x3a, 0x39, 0x38, 0xb8, 0xc5, 0x02, 0xc9, 0x15, 0x4b, 0xd4, 0x9c, 0xb2, 0x19, 0x3a, 0x2d, 0x57,
|
||||
0x0c, 0x16, 0x3c, 0x5d, 0x66, 0x24, 0x8e, 0xaa, 0xb9, 0xa8, 0x8f, 0xae, 0xae, 0x7b, 0xb0, 0xa2,
|
||||
0x1a, 0x19, 0x68, 0x96, 0x04, 0xcf, 0x32, 0x22, 0xe2, 0x68, 0x5c, 0x8e, 0x9e, 0x2b, 0x91, 0x01,
|
||||
0xec, 0x74, 0x09, 0xbf, 0x29, 0x67, 0x28, 0x7e, 0x2e, 0x13, 0x9e, 0x03, 0x2f, 0xcf, 0xe7, 0x4a,
|
||||
0xe5, 0x3d, 0xf4, 0x70, 0x80, 0xe0, 0xa3, 0xc9, 0xe6, 0x82, 0xdc, 0xbe, 0xc5, 0x8a, 0x00, 0xd5,
|
||||
0x51, 0xdf, 0x8c, 0xea, 0x0f, 0x10, 0x26, 0xd9, 0x07, 0xa2, 0x2e, 0x3f, 0xc2, 0xb8, 0x16, 0x0d,
|
||||
0x48, 0xea, 0xf1, 0x02, 0x8d, 0xa6, 0xc9, 0x88, 0xc1, 0x2c, 0x61, 0xfe, 0x61, 0x7d, 0x52, 0x9b,
|
||||
0x9c, 0xd2, 0x59, 0x73, 0x7c, 0xb1, 0xba, 0x78, 0x0b, 0xa3, 0x51, 0xe4, 0x8d, 0x32, 0xa0, 0xa4,
|
||||
0x91, 0x5c, 0x5d, 0x07, 0x90, 0x5c, 0x30, 0x2d, 0x51, 0xc5, 0x82, 0x33, 0x4f, 0x84, 0xe0, 0x22,
|
||||
0xb0, 0x4e, 0x12, 0xc2, 0xde, 0xe9, 0x39, 0x4b, 0xc9, 0xcc, 0x0d, 0x87, 0x68, 0x0c, 0xba, 0x66,
|
||||
0x33, 0x89, 0x26, 0x64, 0xca, 0x05, 0x41, 0x13, 0xce, 0x33, 0x89, 0x32, 0xce, 0x6f, 0x60, 0x44,
|
||||
0x29, 0x22, 0x7c, 0x1c, 0x4a, 0x19, 0x60, 0xc0, 0x5e, 0x69, 0xe4, 0x81, 0xa6, 0xc7, 0x28, 0xfa,
|
||||
0x44, 0xa5, 0x22, 0x0c, 0x90, 0x81, 0x72, 0x81, 0xef, 0x04, 0x36, 0xd5, 0x28, 0x1d, 0xfd, 0x2e,
|
||||
0xb8, 0xe2, 0x09, 0xcf, 0x50, 0x01, 0x81, 0x5e, 0xa7, 0xa9, 0x20, 0x52, 0x12, 0x09, 0x80, 0x6a,
|
||||
0x95, 0x83, 0xc1, 0x44, 0x8a, 0xdc, 0x2b, 0xf8, 0x05, 0xc3, 0x0a, 0x0b, 0x55, 0x58, 0xcc, 0xba,
|
||||
0x5f, 0x23, 0xf0, 0xe1, 0xdf, 0x17, 0x76, 0xa9, 0x43, 0x01, 0x06, 0x6b, 0x78, 0x3b, 0x62, 0xfd,
|
||||
0x8c, 0xef, 0xc7, 0x84, 0xa5, 0x1f, 0x27, 0xb9, 0x8b, 0xf6, 0x72, 0xa9, 0x66, 0x5c, 0x1b, 0xdc,
|
||||
0x57, 0xbd, 0xff, 0x9f, 0xe8, 0x82, 0x2a, 0x14, 0x7f, 0x7c, 0x93, 0xcb, 0xde, 0x06, 0x3d, 0x5b,
|
||||
0x2e, 0x26, 0x44, 0xec, 0x24, 0xf0, 0x15, 0x50, 0x62, 0x76, 0xc1, 0x40, 0x93, 0xb7, 0x38, 0x1b,
|
||||
0x3b, 0x44, 0x8a, 0x19, 0x54, 0x4e, 0xa1, 0xf8, 0x51, 0xd8, 0xad, 0xc1, 0x85, 0x09, 0xd8, 0xc9,
|
||||
0xa7, 0xd1, 0xf8, 0x1d, 0x0b, 0x0c, 0x87, 0x28, 0xfb, 0x4a, 0xfe, 0xb3, 0x04, 0x40, 0x57, 0x4f,
|
||||
0xa0, 0x3d, 0x04, 0xba, 0x82, 0xd5, 0x2c, 0x35, 0xea, 0xda, 0x80, 0x74, 0xa3, 0x01, 0x88, 0xce,
|
||||
0xe7, 0x70, 0xb6, 0x49, 0x6d, 0x23, 0x34, 0x81, 0xf7, 0x34, 0x23, 0xa8, 0x98, 0x2d, 0xf6, 0x63,
|
||||
0xef, 0x9d, 0x68, 0x28, 0x0b, 0xa7, 0x97, 0x2c, 0x5b, 0x79, 0x2a, 0xc2, 0x29, 0xb2, 0x63, 0x16,
|
||||
0x9b, 0x3e, 0x00, 0x3b, 0xf9, 0x7d, 0x9d, 0x65, 0xfc, 0xee, 0x2d, 0xc9, 0x88, 0x22, 0x0e, 0x36,
|
||||
0x33, 0x8a, 0xaa, 0xe1, 0x2e, 0x08, 0xdf, 0x73, 0xbd, 0x76, 0xbc, 0x5a, 0x80, 0x6f, 0xbd, 0x71,
|
||||
0x35, 0x50, 0x4c, 0x20, 0x67, 0xa6, 0x0b, 0xda, 0x0f, 0xc6, 0xe3, 0xbe, 0x66, 0xec, 0x1d, 0xc3,
|
||||
0x93, 0x8c, 0xa4, 0xee, 0xd1, 0x29, 0x9c, 0x31, 0xcc, 0x71, 0xf0, 0x85, 0x5d, 0xf9, 0xfd, 0xc4,
|
||||
0x93, 0x2d, 0x78, 0xcd, 0xcc, 0x63, 0xd1, 0x8e, 0xf5, 0xdc, 0x9b, 0x22, 0xb2, 0xb8, 0x8e, 0x44,
|
||||
0x0f, 0xa3, 0xcd, 0xb8, 0x8b, 0xd2, 0xe2, 0xb8, 0xb6, 0x1e, 0xad, 0x72, 0xec, 0xa5, 0xa3, 0x1e,
|
||||
0x2f, 0x93, 0x84, 0x90, 0x94, 0xa4, 0x71, 0xe9, 0xdc, 0xf5, 0x87, 0x4e, 0x51, 0xfc, 0xcb, 0xc6,
|
||||
0x97, 0xbb, 0x53, 0xc6, 0xdf, 0xc5, 0xd1, 0xaf, 0x8c, 0xa8, 0x3b, 0x2e, 0x6e, 0x8c, 0xcf, 0x8c,
|
||||
0x7a, 0x3a, 0xe2, 0xe0, 0x2c, 0x8e, 0xe6, 0x34, 0x25, 0x51, 0xef, 0xc4, 0x83, 0x0e, 0xc4, 0x84,
|
||||
0x72, 0x6a, 0x7d, 0x50, 0xfc, 0x1d, 0xe6, 0xed, 0x3d, 0x06, 0xdb, 0x6e, 0x32, 0xf6, 0x08, 0xbe,
|
||||
0x1e, 0x26, 0x38, 0xb9, 0x49, 0x05, 0xcf, 0x41, 0x2d, 0xa0, 0x60, 0x45, 0x13, 0x50, 0xd3, 0x0d,
|
||||
0x59, 0x4d, 0x38, 0x16, 0xa9, 0x8d, 0xaf, 0xeb, 0x36, 0xb6, 0x0d, 0xc4, 0x2e, 0xbe, 0x75, 0x48,
|
||||
0x3a, 0xe7, 0x8b, 0x1c, 0x0b, 0x12, 0xe3, 0x3e, 0x9a, 0xd4, 0x19, 0xc7, 0x83, 0x2f, 0x00, 0xa1,
|
||||
0x83, 0xd9, 0xe9, 0xa9, 0x1b, 0xdc, 0xea, 0x62, 0x08, 0xa2, 0x96, 0x82, 0xa1, 0x17, 0x2f, 0xeb,
|
||||
0x04, 0x4b, 0x44, 0x93, 0x6e, 0x88, 0xb6, 0xe2, 0xa9, 0x18, 0x7a, 0x85, 0x4a, 0x94, 0x9d, 0x78,
|
||||
0xb1, 0x93, 0x15, 0x9a, 0xb3, 0x0a, 0xcd, 0x89, 0xab, 0x20, 0x93, 0x3b, 0x0c, 0x66, 0x44, 0xc5,
|
||||
0xd1, 0x50, 0x1b, 0xf8, 0xf0, 0x96, 0x08, 0x09, 0x0a, 0x83, 0xed, 0x91, 0xda, 0xfc, 0xa4, 0x8c,
|
||||
0x37, 0x09, 0x47, 0x8a, 0x15, 0x76, 0x99, 0xb0, 0xe2, 0xd9, 0x25, 0xb0, 0x15, 0x1a, 0xc0, 0xa2,
|
||||
0xb7, 0x3b, 0xd6, 0xc0, 0x2f, 0x57, 0x10, 0xf3, 0x16, 0x5d, 0xd0, 0x17, 0x2b, 0x3c, 0xec, 0xce,
|
||||
0xac, 0xcd, 0x40, 0xf4, 0x9c, 0xf9, 0x7e, 0xb2, 0xf1, 0x9d, 0x0d, 0xda, 0x45, 0x02, 0xb2, 0x17,
|
||||
0x6d, 0x87, 0x42, 0x95, 0xfb, 0xf8, 0xf4, 0x1b, 0x10, 0x83, 0xcb, 0xdc, 0x64, 0x4f, 0x83, 0x2a,
|
||||
0xa1, 0x40, 0xa7, 0xad, 0x10, 0x36, 0xee, 0x0f, 0xbe, 0x43, 0xc0, 0x8e, 0xc1, 0xe8, 0xf5, 0xe1,
|
||||
0xf4, 0xd0, 0xeb, 0x5c, 0xae, 0xcc, 0xa5, 0x7c, 0x44, 0x5f, 0x49, 0xce, 0x25, 0x55, 0x5c, 0x50,
|
||||
0x22, 0xaf, 0x46, 0xd7, 0x66, 0x67, 0xa5, 0xcf, 0x9b, 0x59, 0x38, 0x90, 0x5c, 0xa8, 0xd8, 0x31,
|
||||
0xfe, 0x5e, 0x50, 0x80, 0x92, 0x08, 0xf3, 0xd1, 0xb8, 0xc7, 0x6e, 0x8b, 0x32, 0x87, 0x3a, 0x69,
|
||||
0x7d, 0x9c, 0x46, 0xab, 0x44, 0xd0, 0xec, 0x9d, 0x3b, 0xd6, 0xe4, 0x60, 0xdd, 0xf3, 0x93, 0x55,
|
||||
0x41, 0xa6, 0xc0, 0xc4, 0x5c, 0x9f, 0xfe, 0x8a, 0xa0, 0x67, 0x3a, 0x4f, 0x30, 0xbb, 0xdd, 0xa6,
|
||||
0xd7, 0xaa, 0x17, 0xe3, 0x9b, 0xba, 0x12, 0x32, 0x8b, 0x82, 0x26, 0x16, 0x08, 0x06, 0x2e, 0x23,
|
||||
0x45, 0xd2, 0x1c, 0x87, 0xb5, 0xe0, 0xae, 0x2f, 0x1d, 0xf6, 0xfe, 0xbb, 0x5b, 0x56, 0x03, 0x7b,
|
||||
0xcb, 0x52, 0x98, 0xeb, 0x1d, 0x88, 0xa1, 0x8b, 0x0f, 0x30, 0xaa, 0xbb, 0xb8, 0xd7, 0xf7, 0x20,
|
||||
0xf4, 0x47, 0xa5, 0x00, 0x10, 0x6b, 0xb8, 0x17, 0x55, 0xa1, 0xd2, 0x43, 0x43, 0xf4, 0x72, 0x34,
|
||||
0x1a, 0x35, 0xa1, 0x69, 0x5a, 0x3b, 0x13, 0x4e, 0x6d, 0x03, 0x38, 0x82, 0xd6, 0x4c, 0x19, 0xa4,
|
||||
0x62, 0xba, 0xf6, 0x09, 0xce, 0xf2, 0xa5, 0xaa, 0xa6, 0xbd, 0x79, 0x28, 0x22, 0x50, 0x4c, 0x53,
|
||||
0x44, 0x19, 0x0a, 0x49, 0x67, 0xb8, 0xd1, 0xb1, 0xd7, 0x98, 0xeb, 0x1c, 0xcb, 0xcb, 0x3b, 0x06,
|
||||
0x15, 0x42, 0x4e, 0x84, 0x5a, 0xc1, 0xb2, 0x5e, 0x08, 0x5e, 0x7f, 0xca, 0xf2, 0xf2, 0xa4, 0x31,
|
||||
0xbb, 0x6e, 0xea, 0x46, 0xac, 0xb6, 0x60, 0xd1, 0x44, 0xaf, 0x68, 0x7a, 0x5d, 0x09, 0xf7, 0x19,
|
||||
0xab, 0xf9, 0x60, 0x81, 0xef, 0xe3, 0x51, 0x1f, 0xfd, 0x13, 0x1d, 0x16, 0x3b, 0x62, 0x20, 0x2e,
|
||||
0xd8, 0x9b, 0x95, 0x22, 0xf2, 0x1b, 0x57, 0x90, 0xcd, 0xbc, 0x08, 0x94, 0x77, 0x0d, 0x28, 0xad,
|
||||
0x7e, 0x95, 0xf6, 0x9a, 0x1c, 0x7a, 0x94, 0x2b, 0xc5, 0x6d, 0x27, 0x0d, 0x19, 0xf5, 0x3e, 0xb4,
|
||||
0x3d, 0xb0, 0xad, 0xc4, 0xd7, 0x28, 0xc1, 0x2a, 0x99, 0xa3, 0x98, 0x6c, 0x53, 0x6d, 0x43, 0x29,
|
||||
0xa3, 0x7d, 0x45, 0x08, 0x00, 0x36, 0x77, 0xc3, 0x33, 0xa7, 0xa3, 0xd3, 0x1a, 0xb9, 0x26, 0x06,
|
||||
0xdf, 0xc0, 0xdc, 0x05, 0xc5, 0x90, 0xbf, 0x62, 0x1d, 0x32, 0x4e, 0xbf, 0x08, 0xef, 0xe0, 0x75,
|
||||
0x18, 0xf8, 0x86, 0x4e, 0x07, 0x95, 0xf6, 0x11, 0xc3, 0x8b, 0x9a, 0x55, 0x16, 0x47, 0xc0, 0xe8,
|
||||
0x07, 0x51, 0xc8, 0x3c, 0x8c, 0xa9, 0x67, 0x84, 0xcd, 0xd4, 0x1c, 0x06, 0x8e, 0x8e, 0x42, 0x1b,
|
||||
0xa1, 0xb1, 0xa0, 0x52, 0x56, 0x88, 0x44, 0xf0, 0x73, 0x20, 0xf3, 0x8c, 0x6a, 0xd6, 0xea, 0xe9,
|
||||
0xe6, 0x66, 0x33, 0xae, 0x07, 0xe3, 0x39, 0x84, 0xa6, 0x2f, 0xc5, 0x62, 0x8d, 0xe3, 0x4a, 0xff,
|
||||
0x65, 0x89, 0x81, 0xe9, 0xbc, 0xbc, 0x6e, 0x53, 0x97, 0x61, 0xcc, 0xc4, 0xb6, 0x8d, 0xa4, 0xf5,
|
||||
0xb4, 0xae, 0xfc, 0x14, 0xd9, 0xd4, 0x86, 0x9c, 0x4e, 0xa8, 0xaa, 0x5f, 0xdb, 0x4c, 0x2b, 0x90,
|
||||
0x5b, 0x85, 0x39, 0x09, 0x51, 0x38, 0xeb, 0x40, 0x61, 0x2f, 0x02, 0x16, 0xb6, 0x66, 0xb5, 0xf5,
|
||||
0xac, 0xb8, 0x0c, 0xe6, 0x60, 0x0a, 0xdd, 0x8c, 0xa7, 0x68, 0xbc, 0x74, 0x8d, 0x59, 0x55, 0xbb,
|
||||
0x26, 0x4c, 0x69, 0xed, 0x47, 0x6c, 0x9d, 0x5a, 0x40, 0x31, 0xa4, 0x96, 0xd2, 0x0b, 0xda, 0x26,
|
||||
0x35, 0x99, 0xce, 0x5c, 0x12, 0xda, 0x3a, 0xf5, 0x39, 0xf0, 0x92, 0x9e, 0xca, 0x7f, 0xd8, 0x05,
|
||||
0x36, 0x97, 0x75, 0x8c, 0x44, 0x6f, 0x82, 0x06, 0xac, 0x73, 0x5b, 0x8e, 0x0f, 0x74, 0x06, 0x04,
|
||||
0xf5, 0xad, 0xc9, 0x54, 0x21, 0x37, 0x87, 0x78, 0x13, 0xda, 0x1a, 0xab, 0xea, 0xe8, 0x82, 0x21,
|
||||
0x9d, 0x8a, 0x44, 0x35, 0x95, 0x23, 0xa2, 0xdb, 0x7d, 0xdb, 0x97, 0xe9, 0x35, 0xba, 0x9f, 0x10,
|
||||
0x47, 0xe8, 0x08, 0xd5, 0xc9, 0x1e, 0xa1, 0xe8, 0x6f, 0xbd, 0x3a, 0x46, 0x27, 0x77, 0xaf, 0x27,
|
||||
0xef, 0xd1, 0x5b, 0x2a, 0xad, 0xec, 0x70, 0xba, 0xb7, 0xaa, 0xf5, 0x22, 0x31, 0xc9, 0xf7, 0x5f,
|
||||
0x40, 0xa9, 0xfc, 0xa6, 0xab, 0x3e, 0x6d, 0xa2, 0xd7, 0x45, 0x69, 0x0b, 0x88, 0xb6, 0x72, 0xbb,
|
||||
0xb6, 0xce, 0x33, 0x2c, 0xff, 0x22, 0x36, 0x68, 0x8f, 0x63, 0x57, 0x9d, 0xe5, 0x82, 0x2e, 0xb0,
|
||||
0x58, 0x75, 0xd1, 0x19, 0x65, 0x53, 0xbe, 0x5d, 0x65, 0xba, 0x50, 0xf9, 0x93, 0x35, 0x66, 0x19,
|
||||
0x33, 0x4a, 0xb3, 0x75, 0x52, 0x4b, 0x95, 0x1b, 0xc5, 0x4b, 0x76, 0x03, 0xe9, 0x20, 0xd4, 0xbb,
|
||||
0x05, 0x6c, 0xaf, 0x65, 0xff, 0x9d, 0x2d, 0xf8, 0x69, 0x22, 0xd5, 0x9c, 0x42, 0xd4, 0x26, 0xdb,
|
||||
0x76, 0x51, 0xfe, 0x20, 0x3b, 0xb7, 0x45, 0x33, 0xe3, 0x73, 0xba, 0x67, 0x63, 0xc2, 0xaf, 0xed,
|
||||
0x43, 0xfc, 0xfd, 0x48, 0xf5, 0x64, 0x94, 0x30, 0xf5, 0xc7, 0x76, 0xda, 0x8d, 0x7d, 0xb7, 0x7c,
|
||||
0xb6, 0xec, 0xbb, 0x4d, 0x35, 0xf6, 0xd7, 0x56, 0x20, 0x76, 0x5b, 0xb2, 0x2e, 0x48, 0x0b, 0x77,
|
||||
0xbe, 0x0a, 0x20, 0xb8, 0x4e, 0xa4, 0x12, 0x3a, 0x69, 0xfe, 0x47, 0x38, 0x44, 0x4a, 0x7c, 0x4b,
|
||||
0xc6, 0x9b, 0x7b, 0x8a, 0x2d, 0x95, 0x6d, 0xb0, 0x84, 0xae, 0xf5, 0xc0, 0xf6, 0xe8, 0x3a, 0xec,
|
||||
0xe8, 0x4d, 0x8c, 0x95, 0x28, 0xb3, 0xb8, 0xbe, 0x6e, 0xd5, 0xe1, 0xdc, 0x49, 0x0a, 0xee, 0x81,
|
||||
0xa1, 0x52, 0xc8, 0xfb, 0x81, 0x02, 0x77, 0x03, 0x75, 0x65, 0x20, 0xc5, 0xc8, 0xb9, 0xac, 0xf7,
|
||||
0x5e, 0xfa, 0xe8, 0x5f, 0xe3, 0xcb, 0x2f, 0x03, 0x69, 0xae, 0x6e, 0xe8, 0x74, 0x15, 0x7b, 0x4c,
|
||||
0xf4, 0xfa, 0xe8, 0x61, 0x4e, 0x70, 0x0a, 0x9b, 0x79, 0x8c, 0x1e, 0xa2, 0x73, 0x28, 0x9d, 0xc0,
|
||||
0x0e, 0x5e, 0x7c, 0x5b, 0xe5, 0x24, 0x3a, 0x46, 0x11, 0xce, 0x81, 0x23, 0x28, 0x0a, 0x80, 0x89,
|
||||
0xe1, 0x77, 0xc9, 0x59, 0xb4, 0xf6, 0x68, 0xc6, 0xd1, 0xaf, 0xe5, 0x35, 0xcf, 0x37, 0xdd, 0xdb,
|
||||
0x05, 0xbe, 0x13, 0x9e, 0x65, 0x38, 0x97, 0xc4, 0xef, 0x7e, 0xae, 0xeb, 0xcd, 0x04, 0xd3, 0xd8,
|
||||
0xdd, 0xd1, 0x4c, 0x70, 0x85, 0xb1, 0x2b, 0xdc, 0xf4, 0x76, 0xd7, 0x1d, 0x57, 0x8d, 0x26, 0x49,
|
||||
0xa9, 0xd2, 0x76, 0xb1, 0xcb, 0x22, 0x4b, 0xb4, 0x4b, 0x21, 0x40, 0x13, 0x76, 0x85, 0x85, 0x6b,
|
||||
0x10, 0xd7, 0x48, 0x41, 0xfa, 0x77, 0xf7, 0xb0, 0x85, 0xc5, 0xa5, 0xa3, 0xdf, 0xd2, 0x6d, 0x22,
|
||||
0x1b, 0x54, 0x77, 0x5a, 0x45, 0xbb, 0xaa, 0x34, 0xd9, 0x6a, 0xd8, 0x6b, 0x4e, 0xb9, 0x9a, 0x2e,
|
||||
0x05, 0x78, 0x54, 0x1f, 0xb7, 0xa6, 0x0c, 0x70, 0xda, 0x0d, 0x5d, 0xec, 0x54, 0xc2, 0x43, 0x71,
|
||||
0xac, 0x80, 0x1a, 0xd0, 0x71, 0xc5, 0x80, 0x91, 0x74, 0x05, 0xc5, 0x04, 0x30, 0xb0, 0xde, 0x43,
|
||||
0x45, 0xf5, 0xa3, 0xf3, 0x3f, 0x96, 0x2d, 0x35, 0x77, 0x2a, 0xad, 0xe2, 0x99, 0xbe, 0x09, 0xb9,
|
||||
0xfb, 0x52, 0xdd, 0x9a, 0xf6, 0x11, 0x75, 0xdb, 0x98, 0x21, 0x8e, 0x1a, 0xdd, 0x7c, 0xd3, 0x9a,
|
||||
0x08, 0x0b, 0x19, 0xf6, 0x62, 0xae, 0xe3, 0xaa, 0xbe, 0xd6, 0x0b, 0x40, 0xb7, 0x3f, 0xd8, 0x56,
|
||||
0x08, 0x6a, 0xea, 0x2e, 0xac, 0xa9, 0x04, 0x8b, 0x70, 0xf3, 0xcb, 0x26, 0xdc, 0xb8, 0x86, 0x17,
|
||||
0x6e, 0x69, 0xeb, 0x4f, 0xa9, 0x8a, 0x41, 0xbe, 0x94, 0xf3, 0x3a, 0xd6, 0x5a, 0xc9, 0x13, 0x4c,
|
||||
0x6a, 0xea, 0x4d, 0x4d, 0x8b, 0x6f, 0x9b, 0x7b, 0x0c, 0xf6, 0x52, 0xbd, 0x75, 0x1d, 0x9d, 0xef,
|
||||
0x9f, 0xec, 0xfb, 0x02, 0x51, 0x64, 0xb7, 0xb9, 0x15, 0xe7, 0xbc, 0x8f, 0x52, 0xce, 0x48, 0xcd,
|
||||
0xdc, 0xf6, 0x92, 0x71, 0x2f, 0x9b, 0xb4, 0x54, 0x50, 0xc8, 0x00, 0x1a, 0x50, 0x1b, 0x9f, 0x13,
|
||||
0xf2, 0x43, 0x8f, 0x8c, 0x47, 0x15, 0x11, 0x2d, 0x67, 0x53, 0x8c, 0x1f, 0x60, 0xee, 0x3a, 0xbb,
|
||||
0xf2, 0x03, 0x7f, 0xc8, 0xc6, 0x6b, 0x8b, 0x43, 0x3e, 0xbd, 0xc6, 0xb9, 0xef, 0xc9, 0xcb, 0xcf,
|
||||
0x44, 0x10, 0x7c, 0xb3, 0xc7, 0x91, 0x28, 0x1a, 0x97, 0x80, 0x69, 0x4b, 0x2d, 0xcf, 0x36, 0x07,
|
||||
0xae, 0x0c, 0x42, 0x41, 0xff, 0xe0, 0x81, 0xb7, 0xdc, 0x2d, 0xec, 0x77, 0xc2, 0x5c, 0x6c, 0x8d,
|
||||
0x7b, 0x9b, 0x9f, 0x76, 0x80, 0xb8, 0x9a, 0x13, 0x51, 0xb2, 0xd8, 0x7e, 0x84, 0x2a, 0x77, 0xdd,
|
||||
0x47, 0xec, 0xe4, 0xe9, 0x5e, 0x94, 0xd5, 0x74, 0x02, 0x96, 0x71, 0xd2, 0xb0, 0x3b, 0x16, 0x70,
|
||||
0xac, 0xa1, 0x3c, 0xde, 0x20, 0x74, 0xb6, 0xb5, 0xc5, 0x73, 0x96, 0xdf, 0x9c, 0xbc, 0x55, 0x06,
|
||||
0x55, 0xa3, 0xe6, 0x54, 0xee, 0xf4, 0x2d, 0x3f, 0x45, 0x19, 0x3b, 0x8a, 0x1a, 0x47, 0xba, 0x2b,
|
||||
0xb6, 0xb5, 0xb3, 0xb8, 0x0e, 0x66, 0x6a, 0xba, 0xcd, 0xa5, 0x93, 0xe2, 0x56, 0xa1, 0x1b, 0x6f,
|
||||
0x97, 0x2a, 0xd1, 0x8d, 0x4a, 0x1a, 0xe2, 0x17, 0xf0, 0x6d, 0xf2, 0x1b, 0xac, 0x1b, 0x1d, 0x14,
|
||||
0x0b, 0x82, 0x4a, 0x20, 0x83, 0x6f, 0xd4, 0x74, 0x1d, 0xeb, 0xef, 0xa5, 0x42, 0x5a, 0xb0, 0x84,
|
||||
0x8d, 0x4d, 0xd4, 0x6f, 0x03, 0x5b, 0x6c, 0xa2, 0x58, 0x16, 0x34, 0x8a, 0x24, 0x23, 0x58, 0xbc,
|
||||
0x2b, 0xe5, 0x6f, 0xcd, 0xe0, 0xdc, 0x97, 0x5c, 0xbe, 0x5c, 0x21, 0xb5, 0x98, 0x2e, 0xb0, 0x91,
|
||||
0x2d, 0x48, 0x77, 0x0a, 0xee, 0x84, 0xa5, 0xd9, 0xaa, 0x79, 0x54, 0xc1, 0x41, 0xb8, 0xc4, 0x5b,
|
||||
0xb6, 0x61, 0xa7, 0x15, 0x9a, 0x22, 0xd7, 0x0d, 0x61, 0x61, 0x5b, 0x94, 0x26, 0x7b, 0x86, 0xbf,
|
||||
0xa1, 0x98, 0xc8, 0x33, 0x9c, 0x90, 0x38, 0xa9, 0xfc, 0x7f, 0xbf, 0x5e, 0x85, 0xea, 0xb9, 0x9e,
|
||||
0xe7, 0x5f, 0x6b, 0xca, 0x06, 0x3c, 0x5b, 0x0a, 0x15, 0xd3, 0x0c, 0x2b, 0x2f, 0xf1, 0xa0, 0xd8,
|
||||
0x29, 0x9f, 0x47, 0xc5, 0x3e, 0x44, 0xdf, 0xdc, 0xa6, 0x8d, 0x00, 0xce, 0x04, 0xc1, 0x4a, 0x33,
|
||||
0x29, 0x49, 0xe8, 0x02, 0x42, 0x20, 0x68, 0x23, 0x83, 0x53, 0xba, 0x5c, 0xb8, 0xaf, 0x06, 0x53,
|
||||
0x3a, 0xa3, 0x4a, 0xea, 0xa7, 0x2b, 0x49, 0xe9, 0x8d, 0xb5, 0x75, 0xe9, 0xc7, 0x57, 0xfa, 0x74,
|
||||
0x79, 0x9d, 0x2a, 0xbf, 0x21, 0x6d, 0x03, 0x44, 0x81, 0xa0, 0xbc, 0x20, 0x9a, 0x66, 0x9c, 0x8b,
|
||||
0xd8, 0x7c, 0xcd, 0xf8, 0xac, 0xf8, 0x82, 0x27, 0x86, 0x74, 0x4f, 0xdf, 0xf9, 0x54, 0x33, 0x2f,
|
||||
0x47, 0xa5, 0x32, 0x34, 0xe5, 0xda, 0xfd, 0x12, 0xf0, 0x08, 0x66, 0x50, 0x60, 0xb6, 0x50, 0x96,
|
||||
0x76, 0xc1, 0xe6, 0xda, 0x7d, 0x36, 0x39, 0xa5, 0x99, 0xd2, 0x4f, 0x26, 0x19, 0x06, 0x08, 0xec,
|
||||
0x3f, 0x96, 0x2c, 0xb9, 0xb7, 0xab, 0x37, 0x13, 0x94, 0xe5, 0x4b, 0xd5, 0x07, 0x0d, 0x64, 0x34,
|
||||
0x0d, 0x88, 0x68, 0xa6, 0x07, 0x8a, 0xbf, 0xa7, 0xf7, 0x24, 0x8d, 0x2b, 0x05, 0x7a, 0xab, 0x36,
|
||||
0x71, 0x64, 0xed, 0xbf, 0xe3, 0x2c, 0x19, 0x9a, 0x50, 0xa6, 0x1b, 0x72, 0xfb, 0xf3, 0x53, 0x6f,
|
||||
0x4a, 0x98, 0x41, 0xb3, 0x0d, 0x4b, 0x96, 0x92, 0x29, 0x65, 0x24, 0x0d, 0x67, 0xf5, 0x28, 0x1a,
|
||||
0xa1, 0x60, 0x37, 0x69, 0x83, 0xe5, 0x0c, 0x8c, 0xe3, 0xb7, 0xbf, 0xa3, 0x43, 0xf7, 0x9f, 0x46,
|
||||
0x82, 0x63, 0x20, 0x87, 0xa7, 0x01, 0xd0, 0x93, 0x10, 0xd5, 0x76, 0x2d, 0xfd, 0x06, 0x1b, 0x7e,
|
||||
0x84, 0x22, 0xf4, 0x81, 0x76, 0x61, 0x6d, 0x1f, 0x9e, 0x9e, 0xc0, 0xcc, 0xe7, 0xfd, 0x98, 0x69,
|
||||
0xe5, 0xe2, 0x09, 0xe4, 0x3f, 0x86, 0xc9, 0x5b, 0x1c, 0xe6, 0x08, 0x08, 0x0e, 0x9b, 0x5d, 0xda,
|
||||
0x83, 0x5e, 0x13, 0xed, 0xb2, 0xb3, 0x05, 0xd1, 0xcf, 0x8f, 0xff, 0x8f, 0xec, 0x6c, 0x34, 0x32,
|
||||
0x1b, 0x55, 0xfd, 0xd3, 0xa2, 0xcd, 0x3a, 0xe8, 0x53, 0xec, 0xac, 0x0b, 0x67, 0xfb, 0xb0, 0xf4,
|
||||
0x14, 0x33, 0xdb, 0x8b, 0x97, 0x56, 0x26, 0x9e, 0x40, 0xfd, 0xe6, 0x07, 0x18, 0x99, 0xd4, 0x37,
|
||||
0x9b, 0x8f, 0xb4, 0x31, 0x8f, 0xf9, 0x60, 0x43, 0x74, 0x0b, 0x51, 0x9c, 0xdd, 0xe1, 0x95, 0xfc,
|
||||
0x52, 0xbe, 0x97, 0xfd, 0xf1, 0xf6, 0x3d, 0x6a, 0x51, 0x9c, 0xc1, 0xb2, 0x8d, 0xe3, 0x94, 0x0a,
|
||||
0xdd, 0x03, 0xbf, 0x25, 0x71, 0xc4, 0x4d, 0x4b, 0xf5, 0x5d, 0xaa, 0x4b, 0x9f, 0x36, 0xa6, 0x5d,
|
||||
0xfd, 0x14, 0xff, 0x81, 0x00, 0xea, 0x95, 0xf3, 0xa8, 0xef, 0x0c, 0x9b, 0xa4, 0xc2, 0xfe, 0x0f,
|
||||
0x85, 0x6a, 0x58, 0x09, 0xcc, 0x64, 0x92, 0x2d, 0xd3, 0xc6, 0x8c, 0xc9, 0x06, 0x8e, 0x6b, 0x92,
|
||||
0xd9, 0xe6, 0x28, 0xe0, 0x3e, 0xb5, 0x5f, 0x1d, 0x12, 0xce, 0x83, 0x56, 0x45, 0x16, 0x40, 0x4e,
|
||||
0xe9, 0x77, 0xaa, 0xaf, 0x0a, 0x85, 0xe9, 0x57, 0xab, 0xa7, 0xcf, 0xf4, 0xb3, 0xf4, 0x67, 0x88,
|
||||
0xcd, 0x5e, 0x98, 0x37, 0x45, 0xa7, 0xcf, 0xfc, 0xc6, 0xf1, 0x95, 0xc5, 0x39, 0xa0, 0xe9, 0xf5,
|
||||
0xb3, 0xb3, 0x57, 0x43, 0xb3, 0xf2, 0xcc, 0x52, 0xb0, 0x6a, 0xfa, 0x2f, 0x74, 0x32, 0xb7, 0xe7,
|
||||
0x83, 0x31, 0x00, 0x00,
|
||||
}))
|
||||
data, _ = ioutil.ReadAll(gr)
|
||||
Assets["app.js"] = data
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package buffers manages a set of reusable byte buffers.
|
||||
package buffers
|
||||
|
||||
const (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package cid provides a manager for mappings between node ID:s and connection ID:s.
|
||||
package cid
|
||||
|
||||
type Map struct {
|
||||
|
||||
@@ -44,9 +44,10 @@ type OptionsConfiguration struct {
|
||||
RescanIntervalS int `xml:"rescanIntervalS" default:"60" ini:"rescan-interval"`
|
||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60" ini:"reconnection-interval"`
|
||||
MaxChangeKbps int `xml:"maxChangeKbps" default:"1000" ini:"max-change-bw"`
|
||||
StartBrowser bool `xml:"startBrowser" default:"true"`
|
||||
}
|
||||
|
||||
func setDefaults(data interface{}, setEmptySlices bool) error {
|
||||
func setDefaults(data interface{}) error {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
|
||||
@@ -56,21 +57,10 @@ func setDefaults(data interface{}, setEmptySlices bool) error {
|
||||
|
||||
v := tag.Get("default")
|
||||
if len(v) > 0 {
|
||||
if f.Kind().String() == "slice" && f.Len() != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch f.Interface().(type) {
|
||||
case string:
|
||||
f.SetString(v)
|
||||
|
||||
case []string:
|
||||
if setEmptySlices {
|
||||
rv := reflect.MakeSlice(reflect.TypeOf([]string{}), 1, 1)
|
||||
rv.Index(0).SetString(v)
|
||||
f.Set(rv)
|
||||
}
|
||||
|
||||
case int:
|
||||
i, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
@@ -81,6 +71,11 @@ func setDefaults(data interface{}, setEmptySlices bool) error {
|
||||
case bool:
|
||||
f.SetBool(v == "true")
|
||||
|
||||
case []string:
|
||||
// We don't do anything with string slices here. Any default
|
||||
// we set will be appended to by the XML decoder, so we fill
|
||||
// those after decoding.
|
||||
|
||||
default:
|
||||
panic(f.Type())
|
||||
}
|
||||
@@ -89,6 +84,30 @@ func setDefaults(data interface{}, setEmptySlices bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillNilSlices sets default value on slices that are still nil.
|
||||
func fillNilSlices(data interface{}) error {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
tag := t.Field(i).Tag
|
||||
|
||||
v := tag.Get("default")
|
||||
if len(v) > 0 {
|
||||
switch f.Interface().(type) {
|
||||
case []string:
|
||||
if f.IsNil() {
|
||||
rv := reflect.MakeSlice(reflect.TypeOf([]string{}), 1, 1)
|
||||
rv.Index(0).SetString(v)
|
||||
f.Set(rv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readConfigINI(m map[string]string, data interface{}) error {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
@@ -152,15 +171,15 @@ func uniqueStrings(ss []string) []string {
|
||||
func readConfigXML(rd io.Reader) (Configuration, error) {
|
||||
var cfg Configuration
|
||||
|
||||
setDefaults(&cfg, false)
|
||||
setDefaults(&cfg.Options, false)
|
||||
setDefaults(&cfg)
|
||||
setDefaults(&cfg.Options)
|
||||
|
||||
var err error
|
||||
if rd != nil {
|
||||
err = xml.NewDecoder(rd).Decode(&cfg)
|
||||
}
|
||||
|
||||
setDefaults(&cfg.Options, true)
|
||||
fillNilSlices(&cfg.Options)
|
||||
|
||||
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
||||
return cfg, err
|
||||
|
||||
116
cmd/syncthing/config_test.go
Normal file
116
cmd/syncthing/config_test.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultValues(t *testing.T) {
|
||||
expected := OptionsConfiguration{
|
||||
ListenAddress: []string{":22000"},
|
||||
ReadOnly: false,
|
||||
AllowDelete: true,
|
||||
FollowSymlinks: true,
|
||||
GUIEnabled: true,
|
||||
GUIAddress: "127.0.0.1:8080",
|
||||
GlobalAnnServer: "announce.syncthing.net:22025",
|
||||
GlobalAnnEnabled: true,
|
||||
LocalAnnEnabled: true,
|
||||
ParallelRequests: 16,
|
||||
MaxSendKbps: 0,
|
||||
RescanIntervalS: 60,
|
||||
ReconnectIntervalS: 60,
|
||||
MaxChangeKbps: 1000,
|
||||
StartBrowser: true,
|
||||
}
|
||||
|
||||
cfg, err := readConfigXML(bytes.NewReader(nil))
|
||||
if err != io.EOF {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg.Options, expected) {
|
||||
t.Errorf("Default config differs;\n E: %#v\n A: %#v", expected, cfg.Options)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoListenAddress(t *testing.T) {
|
||||
data := []byte(`<configuration version="1">
|
||||
<repository directory="~/Sync">
|
||||
<node id="..." name="...">
|
||||
<address>dynamic</address>
|
||||
</node>
|
||||
</repository>
|
||||
<options>
|
||||
<listenAddress></listenAddress>
|
||||
</options>
|
||||
</configuration>
|
||||
`)
|
||||
|
||||
cfg, err := readConfigXML(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expected := []string{""}
|
||||
if !reflect.DeepEqual(cfg.Options.ListenAddress, expected) {
|
||||
t.Errorf("Unexpected ListenAddress %#v", cfg.Options.ListenAddress)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverriddenValues(t *testing.T) {
|
||||
data := []byte(`<configuration version="1">
|
||||
<repository directory="~/Sync">
|
||||
<node id="..." name="...">
|
||||
<address>dynamic</address>
|
||||
</node>
|
||||
</repository>
|
||||
<options>
|
||||
<listenAddress>:23000</listenAddress>
|
||||
<readOnly>true</readOnly>
|
||||
<allowDelete>false</allowDelete>
|
||||
<followSymlinks>false</followSymlinks>
|
||||
<guiEnabled>false</guiEnabled>
|
||||
<guiAddress>125.2.2.2:8080</guiAddress>
|
||||
<globalAnnounceServer>syncthing.nym.se:22025</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>false</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<parallelRequests>32</parallelRequests>
|
||||
<maxSendKbps>1234</maxSendKbps>
|
||||
<rescanIntervalS>600</rescanIntervalS>
|
||||
<reconnectionIntervalS>6000</reconnectionIntervalS>
|
||||
<maxChangeKbps>2345</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
</options>
|
||||
</configuration>
|
||||
`)
|
||||
|
||||
expected := OptionsConfiguration{
|
||||
ListenAddress: []string{":23000"},
|
||||
ReadOnly: true,
|
||||
AllowDelete: false,
|
||||
FollowSymlinks: false,
|
||||
GUIEnabled: false,
|
||||
GUIAddress: "125.2.2.2:8080",
|
||||
GlobalAnnServer: "syncthing.nym.se:22025",
|
||||
GlobalAnnEnabled: false,
|
||||
LocalAnnEnabled: false,
|
||||
ParallelRequests: 32,
|
||||
MaxSendKbps: 1234,
|
||||
RescanIntervalS: 600,
|
||||
ReconnectIntervalS: 6000,
|
||||
MaxChangeKbps: 2345,
|
||||
StartBrowser: false,
|
||||
}
|
||||
|
||||
cfg, err := readConfigXML(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg.Options, expected) {
|
||||
t.Errorf("Overridden config differs;\n E: %#v\n A: %#v", expected, cfg.Options)
|
||||
}
|
||||
}
|
||||
15
cmd/syncthing/debug.go
Normal file
15
cmd/syncthing/debug.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
dlog = log.New(os.Stderr, "main: ", log.Lmicroseconds|log.Lshortfile)
|
||||
debugNet = strings.Contains(os.Getenv("STTRACE"), "net")
|
||||
debugIdx = strings.Contains(os.Getenv("STTRACE"), "idx")
|
||||
debugNeed = strings.Contains(os.Getenv("STTRACE"), "need")
|
||||
debugPull = strings.Contains(os.Getenv("STTRACE"), "pull")
|
||||
)
|
||||
@@ -4,13 +4,13 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/buffers"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
type fileMonitor struct {
|
||||
@@ -18,18 +18,18 @@ type fileMonitor struct {
|
||||
path string // full path
|
||||
writeDone sync.WaitGroup
|
||||
model *Model
|
||||
global File
|
||||
localBlocks []Block
|
||||
global scanner.File
|
||||
localBlocks []scanner.Block
|
||||
copyError error
|
||||
writeError error
|
||||
}
|
||||
|
||||
func (m *fileMonitor) FileBegins(cc <-chan content) error {
|
||||
if m.model.trace["file"] {
|
||||
log.Printf("FILE: FileBegins: " + m.name)
|
||||
if debugPull {
|
||||
dlog.Println("file begins:", m.name)
|
||||
}
|
||||
|
||||
tmp := tempName(m.path, m.global.Modified)
|
||||
tmp := defTempNamer.TempName(m.path)
|
||||
|
||||
dir := path.Dir(tmp)
|
||||
_, err := os.Stat(dir)
|
||||
@@ -109,13 +109,13 @@ func (m *fileMonitor) copyRemoteBlocks(cc <-chan content, outFile *os.File, writ
|
||||
}
|
||||
|
||||
func (m *fileMonitor) FileDone() error {
|
||||
if m.model.trace["file"] {
|
||||
log.Printf("FILE: FileDone: " + m.name)
|
||||
if debugPull {
|
||||
dlog.Println("file done:", m.name)
|
||||
}
|
||||
|
||||
m.writeDone.Wait()
|
||||
|
||||
tmp := tempName(m.path, m.global.Modified)
|
||||
tmp := defTempNamer.TempName(m.path)
|
||||
defer os.Remove(tmp)
|
||||
|
||||
if m.copyError != nil {
|
||||
@@ -149,14 +149,14 @@ func (m *fileMonitor) FileDone() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func hashCheck(name string, correct []Block) error {
|
||||
func hashCheck(name string, correct []scanner.Block) error {
|
||||
rf, err := os.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rf.Close()
|
||||
|
||||
current, err := Blocks(rf, BlockSize)
|
||||
current, err := scanner.Blocks(rf, BlockSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
type Monitor interface {
|
||||
@@ -23,7 +25,7 @@ type FileQueue struct {
|
||||
|
||||
type queuedFile struct {
|
||||
name string
|
||||
blocks []Block
|
||||
blocks []scanner.Block
|
||||
activeBlocks []bool
|
||||
given int
|
||||
remaining int
|
||||
@@ -54,7 +56,7 @@ func (l queuedFileList) Less(a, b int) bool {
|
||||
|
||||
type queuedBlock struct {
|
||||
name string
|
||||
block Block
|
||||
block scanner.Block
|
||||
index int
|
||||
}
|
||||
|
||||
@@ -65,7 +67,7 @@ func NewFileQueue() *FileQueue {
|
||||
}
|
||||
}
|
||||
|
||||
func (q *FileQueue) Add(name string, blocks []Block, monitor Monitor) {
|
||||
func (q *FileQueue) Add(name string, blocks []scanner.Block, monitor Monitor) {
|
||||
q.fmut.Lock()
|
||||
defer q.fmut.Unlock()
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
func TestFileQueueAdd(t *testing.T) {
|
||||
@@ -17,8 +19,8 @@ func TestFileQueueAddSorting(t *testing.T) {
|
||||
q.SetAvailable("zzz", []string{"nodeID"})
|
||||
q.SetAvailable("aaa", []string{"nodeID"})
|
||||
|
||||
q.Add("zzz", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
q.Add("aaa", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
q.Add("zzz", []scanner.Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
q.Add("aaa", []scanner.Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
b, _ := q.Get("nodeID")
|
||||
if b.name != "aaa" {
|
||||
t.Errorf("Incorrectly sorted get: %+v", b)
|
||||
@@ -28,12 +30,12 @@ func TestFileQueueAddSorting(t *testing.T) {
|
||||
q.SetAvailable("zzz", []string{"nodeID"})
|
||||
q.SetAvailable("aaa", []string{"nodeID"})
|
||||
|
||||
q.Add("zzz", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
q.Add("zzz", []scanner.Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
b, _ = q.Get("nodeID") // Start on zzzz
|
||||
if b.name != "zzz" {
|
||||
t.Errorf("Incorrectly sorted get: %+v", b)
|
||||
}
|
||||
q.Add("aaa", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
q.Add("aaa", []scanner.Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil)
|
||||
b, _ = q.Get("nodeID")
|
||||
if b.name != "zzz" {
|
||||
// Continue rather than starting a new file
|
||||
@@ -56,12 +58,12 @@ func TestFileQueueGet(t *testing.T) {
|
||||
q.SetAvailable("foo", []string{"nodeID"})
|
||||
q.SetAvailable("bar", []string{"nodeID"})
|
||||
|
||||
q.Add("foo", []Block{
|
||||
q.Add("foo", []scanner.Block{
|
||||
{Offset: 0, Size: 128, Hash: []byte("some foo hash bytes")},
|
||||
{Offset: 128, Size: 128, Hash: []byte("some other foo hash bytes")},
|
||||
{Offset: 256, Size: 128, Hash: []byte("more foo hash bytes")},
|
||||
}, nil)
|
||||
q.Add("bar", []Block{
|
||||
q.Add("bar", []scanner.Block{
|
||||
{Offset: 0, Size: 128, Hash: []byte("some bar hash bytes")},
|
||||
{Offset: 128, Size: 128, Hash: []byte("some other bar hash bytes")},
|
||||
}, nil)
|
||||
@@ -70,7 +72,7 @@ func TestFileQueueGet(t *testing.T) {
|
||||
|
||||
expected := queuedBlock{
|
||||
name: "bar",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 0,
|
||||
Size: 128,
|
||||
Hash: []byte("some bar hash bytes"),
|
||||
@@ -89,7 +91,7 @@ func TestFileQueueGet(t *testing.T) {
|
||||
|
||||
expected = queuedBlock{
|
||||
name: "bar",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 128,
|
||||
Size: 128,
|
||||
Hash: []byte("some other bar hash bytes"),
|
||||
@@ -109,7 +111,7 @@ func TestFileQueueGet(t *testing.T) {
|
||||
|
||||
expected = queuedBlock{
|
||||
name: "foo",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 0,
|
||||
Size: 128,
|
||||
Hash: []byte("some foo hash bytes"),
|
||||
@@ -150,7 +152,7 @@ func TestFileQueueDone(t *testing.T) {
|
||||
}()
|
||||
|
||||
q := FileQueue{resolver: fakeResolver{}}
|
||||
q.Add("foo", []Block{
|
||||
q.Add("foo", []scanner.Block{
|
||||
{Offset: 0, Length: 128, Hash: []byte("some foo hash bytes")},
|
||||
{Offset: 128, Length: 128, Hash: []byte("some other foo hash bytes")},
|
||||
}, ch)
|
||||
@@ -181,19 +183,19 @@ func TestFileQueueGetNodeIDs(t *testing.T) {
|
||||
q.SetAvailable("a-foo", []string{"nodeID", "a"})
|
||||
q.SetAvailable("b-bar", []string{"nodeID", "b"})
|
||||
|
||||
q.Add("a-foo", []Block{
|
||||
q.Add("a-foo", []scanner.Block{
|
||||
{Offset: 0, Size: 128, Hash: []byte("some foo hash bytes")},
|
||||
{Offset: 128, Size: 128, Hash: []byte("some other foo hash bytes")},
|
||||
{Offset: 256, Size: 128, Hash: []byte("more foo hash bytes")},
|
||||
}, nil)
|
||||
q.Add("b-bar", []Block{
|
||||
q.Add("b-bar", []scanner.Block{
|
||||
{Offset: 0, Size: 128, Hash: []byte("some bar hash bytes")},
|
||||
{Offset: 128, Size: 128, Hash: []byte("some other bar hash bytes")},
|
||||
}, nil)
|
||||
|
||||
expected := queuedBlock{
|
||||
name: "b-bar",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 0,
|
||||
Size: 128,
|
||||
Hash: []byte("some bar hash bytes"),
|
||||
@@ -209,7 +211,7 @@ func TestFileQueueGetNodeIDs(t *testing.T) {
|
||||
|
||||
expected = queuedBlock{
|
||||
name: "a-foo",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 0,
|
||||
Size: 128,
|
||||
Hash: []byte("some foo hash bytes"),
|
||||
@@ -225,7 +227,7 @@ func TestFileQueueGetNodeIDs(t *testing.T) {
|
||||
|
||||
expected = queuedBlock{
|
||||
name: "a-foo",
|
||||
block: Block{
|
||||
block: scanner.Block{
|
||||
Offset: 128,
|
||||
Size: 128,
|
||||
Hash: []byte("some other foo hash bytes"),
|
||||
@@ -246,9 +248,9 @@ func TestFileQueueThreadHandling(t *testing.T) {
|
||||
|
||||
const n = 100
|
||||
var total int
|
||||
var blocks []Block
|
||||
var blocks []scanner.Block
|
||||
for i := 1; i <= n; i++ {
|
||||
blocks = append(blocks, Block{Offset: int64(i), Size: 1})
|
||||
blocks = append(blocks, scanner.Block{Offset: int64(i), Size: 1})
|
||||
total += i
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
"github.com/codegangsta/martini"
|
||||
)
|
||||
|
||||
@@ -107,7 +108,7 @@ func restPostRestart(req *http.Request) {
|
||||
restart()
|
||||
}
|
||||
|
||||
type guiFile File
|
||||
type guiFile scanner.File
|
||||
|
||||
func (f guiFile) MarshalJSON() ([]byte, error) {
|
||||
type t struct {
|
||||
@@ -116,7 +117,7 @@ func (f guiFile) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
return json.Marshal(t{
|
||||
Name: f.Name,
|
||||
Size: File(f).Size,
|
||||
Size: scanner.File(f).Size,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
92
cmd/syncthing/gui_solaris.go
Normal file
92
cmd/syncthing/gui_solaris.go
Normal file
@@ -0,0 +1,92 @@
|
||||
//+build solaris
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type id_t int32
|
||||
type ulong_t uint32
|
||||
|
||||
type timestruc_t struct {
|
||||
Tv_sec int64
|
||||
Tv_nsec int64
|
||||
}
|
||||
|
||||
func (tv timestruc_t) Nano() int64 {
|
||||
return tv.Tv_sec*1e9 + tv.Tv_nsec
|
||||
}
|
||||
|
||||
type prusage_t struct {
|
||||
Pr_lwpid id_t /* lwp id. 0: process or defunct */
|
||||
Pr_count int32 /* number of contributing lwps */
|
||||
Pr_tstamp timestruc_t /* real time stamp, time of read() */
|
||||
Pr_create timestruc_t /* process/lwp creation time stamp */
|
||||
Pr_term timestruc_t /* process/lwp termination time stamp */
|
||||
Pr_rtime timestruc_t /* total lwp real (elapsed) time */
|
||||
Pr_utime timestruc_t /* user level CPU time */
|
||||
Pr_stime timestruc_t /* system call CPU time */
|
||||
Pr_ttime timestruc_t /* other system trap CPU time */
|
||||
Pr_tftime timestruc_t /* text page fault sleep time */
|
||||
Pr_dftime timestruc_t /* data page fault sleep time */
|
||||
Pr_kftime timestruc_t /* kernel page fault sleep time */
|
||||
Pr_ltime timestruc_t /* user lock wait sleep time */
|
||||
Pr_slptime timestruc_t /* all other sleep time */
|
||||
Pr_wtime timestruc_t /* wait-cpu (latency) time */
|
||||
Pr_stoptime timestruc_t /* stopped time */
|
||||
Pr_minf ulong_t /* minor page faults */
|
||||
Pr_majf ulong_t /* major page faults */
|
||||
Pr_nswap ulong_t /* swaps */
|
||||
Pr_inblk ulong_t /* input blocks */
|
||||
Pr_oublk ulong_t /* output blocks */
|
||||
Pr_msnd ulong_t /* messages sent */
|
||||
Pr_mrcv ulong_t /* messages received */
|
||||
Pr_sigs ulong_t /* signals received */
|
||||
Pr_vctx ulong_t /* voluntary context switches */
|
||||
Pr_ictx ulong_t /* involuntary context switches */
|
||||
Pr_sysc ulong_t /* system calls */
|
||||
Pr_ioch ulong_t /* chars read and written */
|
||||
|
||||
}
|
||||
|
||||
func solarisPrusage(pid int, rusage *prusage_t) error {
|
||||
fd, err := os.Open(fmt.Sprintf("/proc/%d/usage", pid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(fd, binary.LittleEndian, rusage)
|
||||
fd.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func init() {
|
||||
go trackCPUUsage()
|
||||
}
|
||||
|
||||
func trackCPUUsage() {
|
||||
var prevUsage int64
|
||||
var prevTime = time.Now().UnixNano()
|
||||
var rusage prusage_t
|
||||
var pid = os.Getpid()
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
err := solarisPrusage(pid, &rusage)
|
||||
if err != nil {
|
||||
warnln(err)
|
||||
continue
|
||||
}
|
||||
curTime := time.Now().UnixNano()
|
||||
timeDiff := curTime - prevTime
|
||||
curUsage := rusage.Pr_utime.Nano() + rusage.Pr_stime.Nano()
|
||||
usageDiff := curUsage - prevUsage
|
||||
cpuUsageLock.Lock()
|
||||
cpuUsagePercent = 100 * float64(usageDiff) / float64(timeDiff)
|
||||
cpuUsageLock.Unlock()
|
||||
prevTime = curTime
|
||||
prevUsage = curUsage
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,6 @@ func init() {
|
||||
logger = log.New(os.Stderr, "", log.Flags())
|
||||
}
|
||||
|
||||
func debugln(vals ...interface{}) {
|
||||
s := fmt.Sprintln(vals...)
|
||||
logger.Output(2, "DEBUG: "+s)
|
||||
}
|
||||
|
||||
func debugf(format string, vals ...interface{}) {
|
||||
s := fmt.Sprintf(format, vals...)
|
||||
logger.Output(2, "DEBUG: "+s)
|
||||
}
|
||||
|
||||
func infoln(vals ...interface{}) {
|
||||
s := fmt.Sprintln(vals...)
|
||||
logger.Output(2, "INFO: "+s)
|
||||
|
||||
@@ -21,8 +21,11 @@ import (
|
||||
"github.com/calmh/ini"
|
||||
"github.com/calmh/syncthing/discover"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
const BlockSize = 128 * 1024
|
||||
|
||||
var cfg Configuration
|
||||
var Version = "unknown-dev"
|
||||
|
||||
@@ -31,26 +34,42 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
showVersion bool
|
||||
confDir string
|
||||
trace string
|
||||
profiler string
|
||||
verbose bool
|
||||
startupDelay int
|
||||
showVersion bool
|
||||
confDir string
|
||||
verbose bool
|
||||
)
|
||||
|
||||
const (
|
||||
usage = "syncthing [options]"
|
||||
extraUsage = `The following enviroment variables are interpreted by syncthing:
|
||||
|
||||
STNORESTART Do not attempt to restart when requested to, instead just exit.
|
||||
Set this variable when running under a service manager such as
|
||||
runit, launchd, etc.
|
||||
|
||||
STPROFILER Set to a listen address such as "127.0.0.1:9090" to start the
|
||||
profiler with HTTP access.
|
||||
|
||||
STTRACE A comma separated string of facilities to trace. The valid
|
||||
facility strings:
|
||||
- "scanner" (the file change scanner)
|
||||
- "discover" (the node discovery package)
|
||||
- "net" (connecting and disconnecting, network messages)
|
||||
- "idx" (index sending and receiving)
|
||||
- "need" (file need calculations)
|
||||
- "pull" (file pull activity)`
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory")
|
||||
flag.StringVar(&trace, "debug.trace", "", "(connect,net,idx,file,pull)")
|
||||
flag.StringVar(&profiler, "debug.profiler", "", "(addr)")
|
||||
flag.BoolVar(&showVersion, "version", false, "Show version")
|
||||
flag.BoolVar(&verbose, "v", false, "Be more verbose")
|
||||
flag.IntVar(&startupDelay, "delay", 0, "Startup delay (s)")
|
||||
flag.Usage = usageFor(flag.CommandLine, "syncthing [options]")
|
||||
flag.Usage = usageFor(flag.CommandLine, usage, extraUsage)
|
||||
flag.Parse()
|
||||
|
||||
if startupDelay > 0 {
|
||||
time.Sleep(time.Duration(startupDelay) * time.Second)
|
||||
if len(os.Getenv("STRESTART")) > 0 {
|
||||
// Give the parent process time to exit and release sockets etc.
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
if showVersion {
|
||||
@@ -66,10 +85,6 @@ func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
}
|
||||
|
||||
if len(trace) > 0 {
|
||||
log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||
logger.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||
}
|
||||
confDir = expandTilde(confDir)
|
||||
|
||||
// Ensure that our home directory exists and that we have a certificate and key.
|
||||
@@ -154,11 +169,12 @@ func main() {
|
||||
|
||||
var dir = expandTilde(cfg.Repositories[0].Directory)
|
||||
|
||||
if len(profiler) > 0 {
|
||||
if profiler := os.Getenv("STPROFILER"); len(profiler) > 0 {
|
||||
go func() {
|
||||
dlog.Println("Starting profiler on", profiler)
|
||||
err := http.ListenAndServe(profiler, nil)
|
||||
if err != nil {
|
||||
warnln(err)
|
||||
dlog.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -178,9 +194,6 @@ func main() {
|
||||
|
||||
ensureDir(dir, -1)
|
||||
m := NewModel(dir, cfg.Options.MaxChangeKbps*1000)
|
||||
for _, t := range strings.Split(trace, ",") {
|
||||
m.Trace(t)
|
||||
}
|
||||
if cfg.Options.MaxSendKbps > 0 {
|
||||
m.LimitRate(cfg.Options.MaxSendKbps)
|
||||
}
|
||||
@@ -206,7 +219,9 @@ func main() {
|
||||
|
||||
infof("Starting web GUI on http://%s:%d/", hostShow, addr.Port)
|
||||
startGUI(cfg.Options.GUIAddress, m)
|
||||
openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port))
|
||||
if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
|
||||
openURL(fmt.Sprintf("http://%s:%d", hostOpen, addr.Port))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +232,18 @@ func main() {
|
||||
infoln("Populating repository index")
|
||||
}
|
||||
loadIndex(m)
|
||||
updateLocalModel(m)
|
||||
|
||||
sup := &suppressor{threshold: int64(cfg.Options.MaxChangeKbps)}
|
||||
w := &scanner.Walker{
|
||||
Dir: m.dir,
|
||||
IgnoreFile: ".stignore",
|
||||
FollowSymlinks: cfg.Options.FollowSymlinks,
|
||||
BlockSize: BlockSize,
|
||||
TempNamer: defTempNamer,
|
||||
Suppressor: sup,
|
||||
CurrentFiler: m,
|
||||
}
|
||||
updateLocalModel(m, w)
|
||||
|
||||
connOpts := map[string]string{
|
||||
"clientId": "syncthing",
|
||||
@@ -263,7 +289,7 @@ func main() {
|
||||
for {
|
||||
time.Sleep(td)
|
||||
if m.LocalAge() > (td / 2).Seconds() {
|
||||
updateLocalModel(m)
|
||||
updateLocalModel(m, w)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -278,24 +304,23 @@ func main() {
|
||||
|
||||
func restart() {
|
||||
infoln("Restarting")
|
||||
args := os.Args
|
||||
doAppend := true
|
||||
for _, arg := range args {
|
||||
if arg == "-delay" {
|
||||
doAppend = false
|
||||
break
|
||||
}
|
||||
if os.Getenv("SMF_FMRI") != "" || os.Getenv("STNORESTART") != "" {
|
||||
// Solaris SMF
|
||||
infoln("Service manager detected; exit instead of restart")
|
||||
os.Exit(0)
|
||||
}
|
||||
if doAppend {
|
||||
args = append(args, "-delay", "2")
|
||||
|
||||
env := os.Environ()
|
||||
if len(os.Getenv("STRESTART")) == 0 {
|
||||
env = append(env, "STRESTART=1")
|
||||
}
|
||||
pgm, err := exec.LookPath(os.Args[0])
|
||||
if err != nil {
|
||||
warnln(err)
|
||||
return
|
||||
}
|
||||
proc, err := os.StartProcess(pgm, args, &os.ProcAttr{
|
||||
Env: os.Environ(),
|
||||
proc, err := os.StartProcess(pgm, os.Args, &os.ProcAttr{
|
||||
Env: env,
|
||||
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -378,8 +403,8 @@ func printStatsLoop(m *Model) {
|
||||
}
|
||||
|
||||
func listen(myID string, addr string, m *Model, tlsCfg *tls.Config, connOpts map[string]string) {
|
||||
if strings.Contains(trace, "connect") {
|
||||
debugln("NET: Listening on", addr)
|
||||
if debugNet {
|
||||
dlog.Println("listening on", addr)
|
||||
}
|
||||
l, err := tls.Listen("tcp", addr, tlsCfg)
|
||||
fatalErr(err)
|
||||
@@ -392,8 +417,8 @@ listen:
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(trace, "connect") {
|
||||
debugln("NET: Connect from", conn.RemoteAddr())
|
||||
if debugNet {
|
||||
dlog.Println("connect from", conn.RemoteAddr())
|
||||
}
|
||||
|
||||
tc := conn.(*tls.Conn)
|
||||
@@ -474,13 +499,13 @@ func connect(myID string, disc *discover.Discoverer, m *Model, tlsCfg *tls.Confi
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(trace, "connect") {
|
||||
debugln("NET: Dial", nodeCfg.NodeID, addr)
|
||||
if debugNet {
|
||||
dlog.Println("dial", nodeCfg.NodeID, addr)
|
||||
}
|
||||
conn, err := tls.Dial("tcp", addr, tlsCfg)
|
||||
if err != nil {
|
||||
if strings.Contains(trace, "connect") {
|
||||
debugln("NET:", err)
|
||||
if debugNet {
|
||||
dlog.Println(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -502,8 +527,8 @@ func connect(myID string, disc *discover.Discoverer, m *Model, tlsCfg *tls.Confi
|
||||
}
|
||||
}
|
||||
|
||||
func updateLocalModel(m *Model) {
|
||||
files, _ := m.Walk(cfg.Options.FollowSymlinks)
|
||||
func updateLocalModel(m *Model, w *scanner.Walker) {
|
||||
files, _ := w.Walk()
|
||||
m.ReplaceLocal(files)
|
||||
saveIndex(m)
|
||||
}
|
||||
|
||||
@@ -13,16 +13,17 @@ import (
|
||||
|
||||
"github.com/calmh/syncthing/buffers"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
dir string
|
||||
|
||||
global map[string]File // the latest version of each file as it exists in the cluster
|
||||
gmut sync.RWMutex // protects global
|
||||
local map[string]File // the files we currently have locally on disk
|
||||
lmut sync.RWMutex // protects local
|
||||
remote map[string]map[string]File
|
||||
global map[string]scanner.File // the latest version of each file as it exists in the cluster
|
||||
gmut sync.RWMutex // protects global
|
||||
local map[string]scanner.File // the files we currently have locally on disk
|
||||
lmut sync.RWMutex // protects local
|
||||
remote map[string]map[string]scanner.File
|
||||
rmut sync.RWMutex // protects remote
|
||||
protoConn map[string]Connection
|
||||
rawConn map[string]io.Closer
|
||||
@@ -31,7 +32,7 @@ type Model struct {
|
||||
// Queue for files to fetch. fq can call back into the model, so we must ensure
|
||||
// to hold no locks when calling methods on fq.
|
||||
fq *FileQueue
|
||||
dq chan File // queue for files to delete
|
||||
dq chan scanner.File // queue for files to delete
|
||||
|
||||
updatedLocal int64 // timestamp of last update to local
|
||||
updateGlobal int64 // timestamp of last update to remote
|
||||
@@ -43,8 +44,6 @@ type Model struct {
|
||||
delete bool
|
||||
initmut sync.Mutex // protects rwRunning and delete
|
||||
|
||||
trace map[string]bool
|
||||
|
||||
sup suppressor
|
||||
|
||||
parallelRequests int
|
||||
@@ -77,16 +76,15 @@ var (
|
||||
func NewModel(dir string, maxChangeBw int) *Model {
|
||||
m := &Model{
|
||||
dir: dir,
|
||||
global: make(map[string]File),
|
||||
local: make(map[string]File),
|
||||
remote: make(map[string]map[string]File),
|
||||
global: make(map[string]scanner.File),
|
||||
local: make(map[string]scanner.File),
|
||||
remote: make(map[string]map[string]scanner.File),
|
||||
protoConn: make(map[string]Connection),
|
||||
rawConn: make(map[string]io.Closer),
|
||||
lastIdxBcast: time.Now(),
|
||||
trace: make(map[string]bool),
|
||||
sup: suppressor{threshold: int64(maxChangeBw)},
|
||||
fq: NewFileQueue(),
|
||||
dq: make(chan File),
|
||||
dq: make(chan scanner.File),
|
||||
}
|
||||
|
||||
go m.broadcastIndexLoop()
|
||||
@@ -108,11 +106,6 @@ func (m *Model) LimitRate(kbps int) {
|
||||
}()
|
||||
}
|
||||
|
||||
// Trace enables trace logging of the given facility. This is a debugging function; grep for m.trace.
|
||||
func (m *Model) Trace(t string) {
|
||||
m.trace[t] = true
|
||||
}
|
||||
|
||||
// StartRW starts read/write processing on the current model. When in
|
||||
// read/write mode the model will attempt to keep in sync with the cluster by
|
||||
// pulling needed files from peer nodes.
|
||||
@@ -128,7 +121,6 @@ func (m *Model) StartRW(del bool, threads int) {
|
||||
m.delete = del
|
||||
m.parallelRequests = threads
|
||||
|
||||
go m.cleanTempFiles()
|
||||
if del {
|
||||
go m.deleteLoop()
|
||||
}
|
||||
@@ -170,7 +162,9 @@ func (m *Model) ConnectionStats() map[string]ConnectionInfo {
|
||||
|
||||
var tot int64
|
||||
for _, f := range m.global {
|
||||
tot += f.Size
|
||||
if f.Flags&protocol.FlagDeleted == 0 {
|
||||
tot += f.Size
|
||||
}
|
||||
}
|
||||
|
||||
var res = make(map[string]ConnectionInfo)
|
||||
@@ -186,7 +180,7 @@ func (m *Model) ConnectionStats() map[string]ConnectionInfo {
|
||||
|
||||
var have int64
|
||||
for _, f := range m.remote[node] {
|
||||
if f.Equals(m.global[f.Name]) {
|
||||
if f.Equals(m.global[f.Name]) && f.Flags&protocol.FlagDeleted == 0 {
|
||||
have += f.Size
|
||||
}
|
||||
}
|
||||
@@ -249,8 +243,10 @@ func (m *Model) InSyncSize() (files, bytes int64) {
|
||||
|
||||
for n, f := range m.local {
|
||||
if gf, ok := m.global[n]; ok && f.Equals(gf) {
|
||||
files++
|
||||
bytes += f.Size
|
||||
if f.Flags&protocol.FlagDeleted == 0 {
|
||||
files++
|
||||
bytes += f.Size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +256,7 @@ func (m *Model) InSyncSize() (files, bytes int64) {
|
||||
}
|
||||
|
||||
// NeedFiles returns the list of currently needed files and the total size.
|
||||
func (m *Model) NeedFiles() (files []File, bytes int64) {
|
||||
func (m *Model) NeedFiles() (files []scanner.File, bytes int64) {
|
||||
qf := m.fq.QueuedFiles()
|
||||
|
||||
m.gmut.RLock()
|
||||
@@ -278,7 +274,7 @@ func (m *Model) NeedFiles() (files []File, bytes int64) {
|
||||
// Index is called when a new node is connected and we receive their full index.
|
||||
// Implements the protocol.Model interface.
|
||||
func (m *Model) Index(nodeID string, fs []protocol.FileInfo) {
|
||||
var files = make([]File, len(fs))
|
||||
var files = make([]scanner.File, len(fs))
|
||||
for i := range fs {
|
||||
files[i] = fileFromFileInfo(fs[i])
|
||||
}
|
||||
@@ -286,11 +282,11 @@ func (m *Model) Index(nodeID string, fs []protocol.FileInfo) {
|
||||
m.imut.Lock()
|
||||
defer m.imut.Unlock()
|
||||
|
||||
if m.trace["net"] {
|
||||
debugf("NET IDX(in): %s: %d files", nodeID, len(fs))
|
||||
if debugNet {
|
||||
dlog.Printf("IDX(in): %s: %d files", nodeID, len(fs))
|
||||
}
|
||||
|
||||
repo := make(map[string]File)
|
||||
repo := make(map[string]scanner.File)
|
||||
for _, f := range files {
|
||||
m.indexUpdate(repo, f)
|
||||
}
|
||||
@@ -306,7 +302,7 @@ func (m *Model) Index(nodeID string, fs []protocol.FileInfo) {
|
||||
// IndexUpdate is called for incremental updates to connected nodes' indexes.
|
||||
// Implements the protocol.Model interface.
|
||||
func (m *Model) IndexUpdate(nodeID string, fs []protocol.FileInfo) {
|
||||
var files = make([]File, len(fs))
|
||||
var files = make([]scanner.File, len(fs))
|
||||
for i := range fs {
|
||||
files[i] = fileFromFileInfo(fs[i])
|
||||
}
|
||||
@@ -314,8 +310,8 @@ func (m *Model) IndexUpdate(nodeID string, fs []protocol.FileInfo) {
|
||||
m.imut.Lock()
|
||||
defer m.imut.Unlock()
|
||||
|
||||
if m.trace["net"] {
|
||||
debugf("NET IDXUP(in): %s: %d files", nodeID, len(files))
|
||||
if debugNet {
|
||||
dlog.Printf("IDXUP(in): %s: %d files", nodeID, len(files))
|
||||
}
|
||||
|
||||
m.rmut.Lock()
|
||||
@@ -335,13 +331,13 @@ func (m *Model) IndexUpdate(nodeID string, fs []protocol.FileInfo) {
|
||||
m.recomputeNeedForFiles(files)
|
||||
}
|
||||
|
||||
func (m *Model) indexUpdate(repo map[string]File, f File) {
|
||||
if m.trace["idx"] {
|
||||
func (m *Model) indexUpdate(repo map[string]scanner.File, f scanner.File) {
|
||||
if debugIdx {
|
||||
var flagComment string
|
||||
if f.Flags&protocol.FlagDeleted != 0 {
|
||||
flagComment = " (deleted)"
|
||||
}
|
||||
debugf("IDX(in): %q m=%d f=%o%s v=%d (%d blocks)", f.Name, f.Modified, f.Flags, flagComment, f.Version, len(f.Blocks))
|
||||
dlog.Printf("IDX(in): %q m=%d f=%o%s v=%d (%d blocks)", f.Name, f.Modified, f.Flags, flagComment, f.Version, len(f.Blocks))
|
||||
}
|
||||
|
||||
if extraFlags := f.Flags &^ (protocol.FlagInvalid | protocol.FlagDeleted | 0xfff); extraFlags != 0 {
|
||||
@@ -355,8 +351,8 @@ func (m *Model) indexUpdate(repo map[string]File, f File) {
|
||||
// Close removes the peer from the model and closes the underlying connection if possible.
|
||||
// Implements the protocol.Model interface.
|
||||
func (m *Model) Close(node string, err error) {
|
||||
if m.trace["net"] {
|
||||
debugf("NET: %s: %v", node, err)
|
||||
if debugNet {
|
||||
dlog.Printf("%s: %v", node, err)
|
||||
}
|
||||
if err == protocol.ErrClusterHash {
|
||||
warnf("Connection to %s closed due to mismatched cluster hash. Ensure that the configured cluster members are identical on both nodes.", node)
|
||||
@@ -401,12 +397,12 @@ func (m *Model) Request(nodeID, repo, name string, offset int64, size int) ([]by
|
||||
warnf("SECURITY (nonexistent file) REQ(in): %s: %q o=%d s=%d", nodeID, name, offset, size)
|
||||
return nil, ErrNoSuchFile
|
||||
}
|
||||
if lf.Flags&protocol.FlagInvalid != 0 {
|
||||
if lf.Suppressed {
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
|
||||
if m.trace["net"] && nodeID != "<local>" {
|
||||
debugf("NET REQ(in): %s: %q o=%d s=%d", nodeID, name, offset, size)
|
||||
if debugNet && nodeID != "<local>" {
|
||||
dlog.Printf("REQ(in): %s: %q o=%d s=%d", nodeID, name, offset, size)
|
||||
}
|
||||
fn := path.Join(m.dir, name)
|
||||
fd, err := os.Open(fn) // XXX: Inefficient, should cache fd?
|
||||
@@ -431,9 +427,9 @@ func (m *Model) Request(nodeID, repo, name string, offset int64, size int) ([]by
|
||||
}
|
||||
|
||||
// ReplaceLocal replaces the local repository index with the given list of files.
|
||||
func (m *Model) ReplaceLocal(fs []File) {
|
||||
func (m *Model) ReplaceLocal(fs []scanner.File) {
|
||||
var updated bool
|
||||
var newLocal = make(map[string]File)
|
||||
var newLocal = make(map[string]scanner.File)
|
||||
|
||||
m.lmut.RLock()
|
||||
for _, f := range fs {
|
||||
@@ -474,7 +470,7 @@ func (m *Model) ReplaceLocal(fs []File) {
|
||||
// the local index from a cache file at startup.
|
||||
func (m *Model) SeedLocal(fs []protocol.FileInfo) {
|
||||
m.lmut.Lock()
|
||||
m.local = make(map[string]File)
|
||||
m.local = make(map[string]scanner.File)
|
||||
for _, f := range fs {
|
||||
m.local[f.Name] = fileFromFileInfo(f)
|
||||
}
|
||||
@@ -484,6 +480,14 @@ func (m *Model) SeedLocal(fs []protocol.FileInfo) {
|
||||
m.recomputeNeedForGlobal()
|
||||
}
|
||||
|
||||
// Implements scanner.CurrentFiler
|
||||
func (m *Model) CurrentFile(file string) scanner.File {
|
||||
m.lmut.RLock()
|
||||
f := m.local[file]
|
||||
m.lmut.RUnlock()
|
||||
return f
|
||||
}
|
||||
|
||||
// ConnectedTo returns true if we are connected to the named node.
|
||||
func (m *Model) ConnectedTo(nodeID string) bool {
|
||||
m.pmut.RLock()
|
||||
@@ -509,6 +513,9 @@ func (m *Model) AddConnection(rawConn io.Closer, protoConn Connection) {
|
||||
|
||||
go func() {
|
||||
idx := m.ProtocolIndex()
|
||||
if debugNet {
|
||||
dlog.Printf("IDX(out/initial): %s: %d files", nodeID, len(idx))
|
||||
}
|
||||
protoConn.Index("default", idx)
|
||||
}()
|
||||
|
||||
@@ -522,14 +529,14 @@ func (m *Model) AddConnection(rawConn io.Closer, protoConn Connection) {
|
||||
for i := 0; i < m.parallelRequests; i++ {
|
||||
i := i
|
||||
go func() {
|
||||
if m.trace["pull"] {
|
||||
debugln("PULL: Starting", nodeID, i)
|
||||
if debugPull {
|
||||
dlog.Println("starting puller:", nodeID, i)
|
||||
}
|
||||
for {
|
||||
m.pmut.RLock()
|
||||
if _, ok := m.protoConn[nodeID]; !ok {
|
||||
if m.trace["pull"] {
|
||||
debugln("PULL: Exiting", nodeID, i)
|
||||
if debugPull {
|
||||
dlog.Println("stopping puller:", nodeID, i)
|
||||
}
|
||||
m.pmut.RUnlock()
|
||||
return
|
||||
@@ -538,8 +545,8 @@ func (m *Model) AddConnection(rawConn io.Closer, protoConn Connection) {
|
||||
|
||||
qb, ok := m.fq.Get(nodeID)
|
||||
if ok {
|
||||
if m.trace["pull"] {
|
||||
debugln("PULL: Request", nodeID, i, qb.name, qb.block.Offset)
|
||||
if debugPull {
|
||||
dlog.Println("request: out", nodeID, i, qb.name, qb.block.Offset)
|
||||
}
|
||||
data, _ := protoConn.Request("default", qb.name, qb.block.Offset, int(qb.block.Size))
|
||||
m.fq.Done(qb.name, qb.block.Offset, data)
|
||||
@@ -560,12 +567,12 @@ func (m *Model) ProtocolIndex() []protocol.FileInfo {
|
||||
|
||||
for _, f := range m.local {
|
||||
mf := fileInfoFromFile(f)
|
||||
if m.trace["idx"] {
|
||||
if debugIdx {
|
||||
var flagComment string
|
||||
if mf.Flags&protocol.FlagDeleted != 0 {
|
||||
flagComment = " (deleted)"
|
||||
}
|
||||
debugf("IDX(out): %q m=%d f=%o%s v=%d (%d blocks)", mf.Name, mf.Modified, mf.Flags, flagComment, mf.Version, len(mf.Blocks))
|
||||
dlog.Printf("IDX(out): %q m=%d f=%o%s v=%d (%d blocks)", mf.Name, mf.Modified, mf.Flags, flagComment, mf.Version, len(mf.Blocks))
|
||||
}
|
||||
index = append(index, mf)
|
||||
}
|
||||
@@ -583,8 +590,8 @@ func (m *Model) requestGlobal(nodeID, name string, offset int64, size int, hash
|
||||
return nil, fmt.Errorf("requestGlobal: no such node: %s", nodeID)
|
||||
}
|
||||
|
||||
if m.trace["net"] {
|
||||
debugf("NET REQ(out): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
|
||||
if debugNet {
|
||||
dlog.Printf("REQ(out): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
|
||||
}
|
||||
|
||||
return nc.Request("default", name, offset, size)
|
||||
@@ -611,8 +618,8 @@ func (m *Model) broadcastIndexLoop() {
|
||||
m.pmut.RLock()
|
||||
for _, node := range m.protoConn {
|
||||
node := node
|
||||
if m.trace["net"] {
|
||||
debugf("NET IDX(out/loop): %s: %d files", node.ID(), len(idx))
|
||||
if debugNet {
|
||||
dlog.Printf("IDX(out/loop): %s: %d files", node.ID(), len(idx))
|
||||
}
|
||||
go func() {
|
||||
node.Index("default", idx)
|
||||
@@ -628,7 +635,7 @@ func (m *Model) broadcastIndexLoop() {
|
||||
}
|
||||
|
||||
// markDeletedLocals sets the deleted flag on files that have gone missing locally.
|
||||
func (m *Model) markDeletedLocals(newLocal map[string]File) bool {
|
||||
func (m *Model) markDeletedLocals(newLocal map[string]scanner.File) bool {
|
||||
// For every file in the existing local table, check if they are also
|
||||
// present in the new local table. If they are not, check that we already
|
||||
// had the newest version available according to the global table and if so
|
||||
@@ -658,7 +665,7 @@ func (m *Model) markDeletedLocals(newLocal map[string]File) bool {
|
||||
return updated
|
||||
}
|
||||
|
||||
func (m *Model) updateLocal(f File) {
|
||||
func (m *Model) updateLocal(f scanner.File) {
|
||||
var updated bool
|
||||
|
||||
m.lmut.Lock()
|
||||
@@ -685,7 +692,7 @@ func (m *Model) updateLocal(f File) {
|
||||
/*
|
||||
XXX: Not done, needs elegant handling of availability
|
||||
|
||||
func (m *Model) recomputeGlobalFor(files []File) bool {
|
||||
func (m *Model) recomputeGlobalFor(files []scanner.File) bool {
|
||||
m.gmut.Lock()
|
||||
defer m.gmut.Unlock()
|
||||
|
||||
@@ -702,7 +709,7 @@ func (m *Model) recomputeGlobalFor(files []File) bool {
|
||||
*/
|
||||
|
||||
func (m *Model) recomputeGlobal() {
|
||||
var newGlobal = make(map[string]File)
|
||||
var newGlobal = make(map[string]scanner.File)
|
||||
|
||||
m.lmut.RLock()
|
||||
for n, f := range m.local {
|
||||
@@ -761,12 +768,12 @@ func (m *Model) recomputeGlobal() {
|
||||
|
||||
type addOrder struct {
|
||||
n string
|
||||
remote []Block
|
||||
remote []scanner.Block
|
||||
fm *fileMonitor
|
||||
}
|
||||
|
||||
func (m *Model) recomputeNeedForGlobal() {
|
||||
var toDelete []File
|
||||
var toDelete []scanner.File
|
||||
var toAdd []addOrder
|
||||
|
||||
m.gmut.RLock()
|
||||
@@ -785,8 +792,8 @@ func (m *Model) recomputeNeedForGlobal() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Model) recomputeNeedForFiles(files []File) {
|
||||
var toDelete []File
|
||||
func (m *Model) recomputeNeedForFiles(files []scanner.File) {
|
||||
var toDelete []scanner.File
|
||||
var toAdd []addOrder
|
||||
|
||||
m.gmut.RLock()
|
||||
@@ -805,13 +812,13 @@ func (m *Model) recomputeNeedForFiles(files []File) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Model) recomputeNeedForFile(gf File, toAdd []addOrder, toDelete []File) ([]addOrder, []File) {
|
||||
func (m *Model) recomputeNeedForFile(gf scanner.File, toAdd []addOrder, toDelete []scanner.File) ([]addOrder, []scanner.File) {
|
||||
m.lmut.RLock()
|
||||
lf, ok := m.local[gf.Name]
|
||||
m.lmut.RUnlock()
|
||||
|
||||
if !ok || gf.NewerThan(lf) {
|
||||
if gf.Flags&protocol.FlagInvalid != 0 {
|
||||
if gf.Suppressed {
|
||||
// Never attempt to sync invalid files
|
||||
return toAdd, toDelete
|
||||
}
|
||||
@@ -823,14 +830,14 @@ func (m *Model) recomputeNeedForFile(gf File, toAdd []addOrder, toDelete []File)
|
||||
// Don't have the file, so don't need to delete it
|
||||
return toAdd, toDelete
|
||||
}
|
||||
if m.trace["need"] {
|
||||
debugf("NEED: lf:%v gf:%v", lf, gf)
|
||||
if debugNeed {
|
||||
dlog.Printf("need: lf:%v gf:%v", lf, gf)
|
||||
}
|
||||
|
||||
if gf.Flags&protocol.FlagDeleted != 0 {
|
||||
toDelete = append(toDelete, gf)
|
||||
} else {
|
||||
local, remote := BlockDiff(lf.Blocks, gf.Blocks)
|
||||
local, remote := scanner.BlockDiff(lf.Blocks, gf.Blocks)
|
||||
fm := fileMonitor{
|
||||
name: gf.Name,
|
||||
path: path.Clean(path.Join(m.dir, gf.Name)),
|
||||
@@ -865,8 +872,8 @@ func (m *Model) WhoHas(name string) []string {
|
||||
|
||||
func (m *Model) deleteLoop() {
|
||||
for file := range m.dq {
|
||||
if m.trace["file"] {
|
||||
debugln("FILE: Delete", file.Name)
|
||||
if debugPull {
|
||||
dlog.Println("delete", file.Name)
|
||||
}
|
||||
path := path.Clean(path.Join(m.dir, file.Name))
|
||||
err := os.Remove(path)
|
||||
@@ -878,28 +885,29 @@ func (m *Model) deleteLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func fileFromFileInfo(f protocol.FileInfo) File {
|
||||
var blocks = make([]Block, len(f.Blocks))
|
||||
func fileFromFileInfo(f protocol.FileInfo) scanner.File {
|
||||
var blocks = make([]scanner.Block, len(f.Blocks))
|
||||
var offset int64
|
||||
for i, b := range f.Blocks {
|
||||
blocks[i] = Block{
|
||||
blocks[i] = scanner.Block{
|
||||
Offset: offset,
|
||||
Size: b.Size,
|
||||
Hash: b.Hash,
|
||||
}
|
||||
offset += int64(b.Size)
|
||||
}
|
||||
return File{
|
||||
Name: f.Name,
|
||||
Size: offset,
|
||||
Flags: f.Flags,
|
||||
Modified: f.Modified,
|
||||
Version: f.Version,
|
||||
Blocks: blocks,
|
||||
return scanner.File{
|
||||
Name: f.Name,
|
||||
Size: offset,
|
||||
Flags: f.Flags &^ protocol.FlagInvalid,
|
||||
Modified: f.Modified,
|
||||
Version: f.Version,
|
||||
Blocks: blocks,
|
||||
Suppressed: f.Flags&protocol.FlagInvalid != 0,
|
||||
}
|
||||
}
|
||||
|
||||
func fileInfoFromFile(f File) protocol.FileInfo {
|
||||
func fileInfoFromFile(f scanner.File) protocol.FileInfo {
|
||||
var blocks = make([]protocol.BlockInfo, len(f.Blocks))
|
||||
for i, b := range f.Blocks {
|
||||
blocks[i] = protocol.BlockInfo{
|
||||
@@ -907,11 +915,15 @@ func fileInfoFromFile(f File) protocol.FileInfo {
|
||||
Hash: b.Hash,
|
||||
}
|
||||
}
|
||||
return protocol.FileInfo{
|
||||
pf := protocol.FileInfo{
|
||||
Name: f.Name,
|
||||
Flags: f.Flags,
|
||||
Modified: f.Modified,
|
||||
Version: f.Version,
|
||||
Blocks: blocks,
|
||||
}
|
||||
if f.Suppressed {
|
||||
pf.Flags |= protocol.FlagInvalid
|
||||
}
|
||||
return pf
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
)
|
||||
|
||||
func TestNewModel(t *testing.T) {
|
||||
@@ -27,27 +28,27 @@ func TestNewModel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var testDataExpected = map[string]File{
|
||||
"foo": File{
|
||||
var testDataExpected = map[string]scanner.File{
|
||||
"foo": scanner.File{
|
||||
Name: "foo",
|
||||
Flags: 0,
|
||||
Modified: 0,
|
||||
Size: 7,
|
||||
Blocks: []Block{{Offset: 0x0, Size: 0x7, Hash: []uint8{0xae, 0xc0, 0x70, 0x64, 0x5f, 0xe5, 0x3e, 0xe3, 0xb3, 0x76, 0x30, 0x59, 0x37, 0x61, 0x34, 0xf0, 0x58, 0xcc, 0x33, 0x72, 0x47, 0xc9, 0x78, 0xad, 0xd1, 0x78, 0xb6, 0xcc, 0xdf, 0xb0, 0x1, 0x9f}}},
|
||||
Blocks: []scanner.Block{{Offset: 0x0, Size: 0x7, Hash: []uint8{0xae, 0xc0, 0x70, 0x64, 0x5f, 0xe5, 0x3e, 0xe3, 0xb3, 0x76, 0x30, 0x59, 0x37, 0x61, 0x34, 0xf0, 0x58, 0xcc, 0x33, 0x72, 0x47, 0xc9, 0x78, 0xad, 0xd1, 0x78, 0xb6, 0xcc, 0xdf, 0xb0, 0x1, 0x9f}}},
|
||||
},
|
||||
"empty": File{
|
||||
"empty": scanner.File{
|
||||
Name: "empty",
|
||||
Flags: 0,
|
||||
Modified: 0,
|
||||
Size: 0,
|
||||
Blocks: []Block{{Offset: 0x0, Size: 0x0, Hash: []uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}},
|
||||
Blocks: []scanner.Block{{Offset: 0x0, Size: 0x0, Hash: []uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}},
|
||||
},
|
||||
"bar": File{
|
||||
"bar": scanner.File{
|
||||
Name: "bar",
|
||||
Flags: 0,
|
||||
Modified: 0,
|
||||
Size: 10,
|
||||
Blocks: []Block{{Offset: 0x0, Size: 0xa, Hash: []uint8{0x2f, 0x72, 0xcc, 0x11, 0xa6, 0xfc, 0xd0, 0x27, 0x1e, 0xce, 0xf8, 0xc6, 0x10, 0x56, 0xee, 0x1e, 0xb1, 0x24, 0x3b, 0xe3, 0x80, 0x5b, 0xf9, 0xa9, 0xdf, 0x98, 0xf9, 0x2f, 0x76, 0x36, 0xb0, 0x5c}}},
|
||||
Blocks: []scanner.Block{{Offset: 0x0, Size: 0xa, Hash: []uint8{0x2f, 0x72, 0xcc, 0x11, 0xa6, 0xfc, 0xd0, 0x27, 0x1e, 0xce, 0xf8, 0xc6, 0x10, 0x56, 0xee, 0x1e, 0xb1, 0x24, 0x3b, 0xe3, 0x80, 0x5b, 0xf9, 0xa9, 0xdf, 0x98, 0xf9, 0x2f, 0x76, 0x36, 0xb0, 0x5c}}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -63,7 +64,8 @@ func init() {
|
||||
|
||||
func TestUpdateLocal(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
if fs, _ := m.NeedFiles(); len(fs) > 0 {
|
||||
@@ -105,7 +107,8 @@ func TestUpdateLocal(t *testing.T) {
|
||||
|
||||
func TestRemoteUpdateExisting(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
newFile := protocol.FileInfo{
|
||||
@@ -122,7 +125,8 @@ func TestRemoteUpdateExisting(t *testing.T) {
|
||||
|
||||
func TestRemoteAddNew(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
newFile := protocol.FileInfo{
|
||||
@@ -139,7 +143,8 @@ func TestRemoteAddNew(t *testing.T) {
|
||||
|
||||
func TestRemoteUpdateOld(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
oldTimeStamp := int64(1234)
|
||||
@@ -157,7 +162,8 @@ func TestRemoteUpdateOld(t *testing.T) {
|
||||
|
||||
func TestRemoteIndexUpdate(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
foo := protocol.FileInfo{
|
||||
@@ -190,7 +196,8 @@ func TestRemoteIndexUpdate(t *testing.T) {
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
if l1, l2 := len(m.local), len(fs); l1 != l2 {
|
||||
@@ -201,10 +208,10 @@ func TestDelete(t *testing.T) {
|
||||
}
|
||||
|
||||
ot := time.Now().Unix()
|
||||
newFile := File{
|
||||
newFile := scanner.File{
|
||||
Name: "a new file",
|
||||
Modified: ot,
|
||||
Blocks: []Block{{0, 100, []byte("some hash bytes")}},
|
||||
Blocks: []scanner.Block{{0, 100, []byte("some hash bytes")}},
|
||||
}
|
||||
m.updateLocal(newFile)
|
||||
|
||||
@@ -292,7 +299,8 @@ func TestDelete(t *testing.T) {
|
||||
|
||||
func TestForgetNode(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
if l1, l2 := len(m.local), len(fs); l1 != l2 {
|
||||
@@ -345,7 +353,8 @@ func TestForgetNode(t *testing.T) {
|
||||
|
||||
func TestRequest(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
bs, err := m.Request("some node", "default", "foo", 0, 6)
|
||||
@@ -367,7 +376,8 @@ func TestRequest(t *testing.T) {
|
||||
|
||||
func TestIgnoreWithUnknownFlags(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
valid := protocol.FileInfo{
|
||||
@@ -410,7 +420,8 @@ func genFiles(n int) []protocol.FileInfo {
|
||||
|
||||
func BenchmarkIndex10000(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
files := genFiles(10000)
|
||||
|
||||
@@ -422,7 +433,8 @@ func BenchmarkIndex10000(b *testing.B) {
|
||||
|
||||
func BenchmarkIndex00100(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
files := genFiles(100)
|
||||
|
||||
@@ -434,7 +446,8 @@ func BenchmarkIndex00100(b *testing.B) {
|
||||
|
||||
func BenchmarkIndexUpdate10000f10000(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
files := genFiles(10000)
|
||||
m.Index("42", files)
|
||||
@@ -447,7 +460,8 @@ func BenchmarkIndexUpdate10000f10000(b *testing.B) {
|
||||
|
||||
func BenchmarkIndexUpdate10000f00100(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
files := genFiles(10000)
|
||||
m.Index("42", files)
|
||||
@@ -461,7 +475,8 @@ func BenchmarkIndexUpdate10000f00100(b *testing.B) {
|
||||
|
||||
func BenchmarkIndexUpdate10000f00001(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
files := genFiles(10000)
|
||||
m.Index("42", files)
|
||||
@@ -506,7 +521,8 @@ func (FakeConnection) Statistics() protocol.Statistics {
|
||||
|
||||
func BenchmarkRequest(b *testing.B) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
fs, _ := m.Walk(false)
|
||||
w := scanner.Walker{Dir: "testdata", IgnoreFile: ".stignore", BlockSize: 128 * 1024}
|
||||
fs, _ := w.Walk()
|
||||
m.ReplaceLocal(fs)
|
||||
|
||||
const n = 1000
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -51,6 +52,11 @@ func (h *changeHistory) append(size int64, t time.Time) {
|
||||
h.changes = append(h.changes, c)
|
||||
}
|
||||
|
||||
func (s *suppressor) Suppress(name string, fi os.FileInfo) bool {
|
||||
sup, _ := s.suppress(name, fi.Size(), time.Now())
|
||||
return sup
|
||||
}
|
||||
|
||||
func (s *suppressor) suppress(name string, size int64, t time.Time) (bool, bool) {
|
||||
s.Lock()
|
||||
|
||||
|
||||
28
cmd/syncthing/tempname.go
Normal file
28
cmd/syncthing/tempname.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tempNamer struct {
|
||||
prefix string
|
||||
}
|
||||
|
||||
var defTempNamer = tempNamer{".syncthing"}
|
||||
|
||||
func (t tempNamer) IsTemporary(name string) bool {
|
||||
if runtime.GOOS == "windows" {
|
||||
name = filepath.ToSlash(name)
|
||||
}
|
||||
return strings.HasPrefix(path.Base(name), t.prefix)
|
||||
}
|
||||
|
||||
func (t tempNamer) TempName(name string) string {
|
||||
tdir := path.Dir(name)
|
||||
tname := fmt.Sprintf("%s.%s", t.prefix, path.Base(name))
|
||||
return path.Join(tdir, tname)
|
||||
}
|
||||
@@ -22,18 +22,14 @@ func optionTable(w io.Writer, rows [][]string) {
|
||||
tw.Flush()
|
||||
}
|
||||
|
||||
func usageFor(fs *flag.FlagSet, usage string) func() {
|
||||
func usageFor(fs *flag.FlagSet, usage string, extra string) func() {
|
||||
return func() {
|
||||
var b bytes.Buffer
|
||||
b.WriteString("Usage:\n " + usage + "\n")
|
||||
|
||||
var options [][]string
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
var dash = "-"
|
||||
if len(f.Name) > 1 {
|
||||
dash = "--"
|
||||
}
|
||||
var opt = " " + dash + f.Name
|
||||
var opt = " -" + f.Name
|
||||
|
||||
if f.DefValue != "false" {
|
||||
opt += "=" + f.DefValue
|
||||
@@ -48,5 +44,9 @@ func usageFor(fs *flag.FlagSet, usage string) func() {
|
||||
}
|
||||
|
||||
fmt.Println(b.String())
|
||||
|
||||
if len(extra) > 0 {
|
||||
fmt.Println(extra)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
)
|
||||
|
||||
const BlockSize = 128 * 1024
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
Flags uint32
|
||||
Modified int64
|
||||
Version uint32
|
||||
Size int64
|
||||
Blocks []Block
|
||||
}
|
||||
|
||||
func (f File) String() string {
|
||||
return fmt.Sprintf("File{Name:%q, Flags:0x%x, Modified:%d, Version:%d, Size:%d, NumBlocks:%d}",
|
||||
f.Name, f.Flags, f.Modified, f.Version, f.Size, len(f.Blocks))
|
||||
}
|
||||
|
||||
func (f File) Equals(o File) bool {
|
||||
return f.Modified == o.Modified && f.Version == o.Version
|
||||
}
|
||||
|
||||
func (f File) NewerThan(o File) bool {
|
||||
return f.Modified > o.Modified || (f.Modified == o.Modified && f.Version > o.Version)
|
||||
}
|
||||
|
||||
func isTempName(name string) bool {
|
||||
return strings.HasPrefix(path.Base(name), ".syncthing.")
|
||||
}
|
||||
|
||||
func tempName(name string, modified int64) string {
|
||||
tdir := path.Dir(name)
|
||||
tname := fmt.Sprintf(".syncthing.%s.%d", path.Base(name), modified)
|
||||
return path.Join(tdir, tname)
|
||||
}
|
||||
|
||||
func (m *Model) loadIgnoreFiles(ign map[string][]string) filepath.WalkFunc {
|
||||
return func(p string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rn, err := filepath.Rel(m.dir, p)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pn, sn := path.Split(rn); sn == ".stignore" {
|
||||
pn := strings.Trim(pn, "/")
|
||||
bs, _ := ioutil.ReadFile(p)
|
||||
lines := bytes.Split(bs, []byte("\n"))
|
||||
var patterns []string
|
||||
for _, line := range lines {
|
||||
if len(line) > 0 {
|
||||
patterns = append(patterns, string(line))
|
||||
}
|
||||
}
|
||||
ign[pn] = patterns
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Model) walkAndHashFiles(res *[]File, ign map[string][]string) filepath.WalkFunc {
|
||||
return func(p string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: %q: %v", p, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if isTempName(p) {
|
||||
return nil
|
||||
}
|
||||
|
||||
rn, err := filepath.Rel(m.dir, p)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, sn := path.Split(rn); sn == ".stignore" {
|
||||
// We never sync the .stignore files
|
||||
return nil
|
||||
}
|
||||
|
||||
if ignoreFile(ign, rn) {
|
||||
if m.trace["file"] {
|
||||
log.Println("FILE: IGNORE:", rn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.Mode()&os.ModeType == 0 {
|
||||
modified := info.ModTime().Unix()
|
||||
|
||||
m.lmut.RLock()
|
||||
lf, ok := m.local[rn]
|
||||
m.lmut.RUnlock()
|
||||
|
||||
if ok && lf.Modified == modified {
|
||||
if nf := uint32(info.Mode()); nf != lf.Flags {
|
||||
lf.Flags = nf
|
||||
lf.Version++
|
||||
}
|
||||
*res = append(*res, lf)
|
||||
} else {
|
||||
if cur, prev := m.sup.suppress(rn, info.Size(), time.Now()); cur {
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: SUPPRESS: %q change bw over threshold", rn)
|
||||
}
|
||||
if !prev {
|
||||
log.Printf("INFO: Changes to %q are being temporarily suppressed because it changes too frequently.", rn)
|
||||
}
|
||||
|
||||
if ok {
|
||||
lf.Flags = protocol.FlagInvalid
|
||||
lf.Version++
|
||||
*res = append(*res, lf)
|
||||
}
|
||||
return nil
|
||||
} else if prev && !cur {
|
||||
log.Printf("INFO: Changes to %q are no longer suppressed.", rn)
|
||||
}
|
||||
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: Hash %q", p)
|
||||
}
|
||||
fd, err := os.Open(p)
|
||||
if err != nil {
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: %q: %v", p, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
blocks, err := Blocks(fd, BlockSize)
|
||||
if err != nil {
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: %q: %v", p, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
f := File{
|
||||
Name: rn,
|
||||
Size: info.Size(),
|
||||
Flags: uint32(info.Mode()),
|
||||
Modified: modified,
|
||||
Blocks: blocks,
|
||||
}
|
||||
*res = append(*res, f)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Walk returns the list of files found in the local repository by scanning the
|
||||
// file system. Files are blockwise hashed.
|
||||
func (m *Model) Walk(followSymlinks bool) (files []File, ignore map[string][]string) {
|
||||
ignore = make(map[string][]string)
|
||||
|
||||
hashFiles := m.walkAndHashFiles(&files, ignore)
|
||||
|
||||
filepath.Walk(m.dir, m.loadIgnoreFiles(ignore))
|
||||
filepath.Walk(m.dir, hashFiles)
|
||||
|
||||
if followSymlinks {
|
||||
d, err := os.Open(m.dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
fis, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, info := range fis {
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
dir := path.Join(m.dir, info.Name()) + "/"
|
||||
filepath.Walk(dir, m.loadIgnoreFiles(ignore))
|
||||
filepath.Walk(dir, hashFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Model) cleanTempFile(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode()&os.ModeType == 0 && isTempName(path) {
|
||||
if m.trace["file"] {
|
||||
log.Printf("FILE: Remove %q", path)
|
||||
}
|
||||
os.Remove(path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Model) cleanTempFiles() {
|
||||
filepath.Walk(m.dir, m.cleanTempFile)
|
||||
}
|
||||
|
||||
func ignoreFile(patterns map[string][]string, file string) bool {
|
||||
first, last := path.Split(file)
|
||||
for prefix, pats := range patterns {
|
||||
if len(prefix) == 0 || prefix == first || strings.HasPrefix(first, prefix+"/") {
|
||||
for _, pattern := range pats {
|
||||
if match, _ := path.Match(pattern, last); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
12
discover/debug.go
Normal file
12
discover/debug.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package discover
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
dlog = log.New(os.Stderr, "discover: ", log.Lmicroseconds|log.Lshortfile)
|
||||
debug = strings.Contains(os.Getenv("STTRACE"), "discover")
|
||||
)
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
|
||||
const (
|
||||
AnnouncementPort = 21025
|
||||
Debug = false
|
||||
)
|
||||
|
||||
type Discoverer struct {
|
||||
@@ -111,8 +110,8 @@ func (d *Discoverer) sendAnnouncements() {
|
||||
}
|
||||
}
|
||||
if len(srcAddr) == 0 {
|
||||
if Debug {
|
||||
log.Println("discover: debug: no source address found on interface", intf.Name)
|
||||
if debug {
|
||||
dlog.Println("no source address found on interface", intf.Name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -131,8 +130,8 @@ func (d *Discoverer) sendAnnouncements() {
|
||||
continue
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Println("discover: debug: send announcement from", conn.LocalAddr(), "to", remote, "on", intf.Name)
|
||||
if debug {
|
||||
dlog.Println("send announcement from", conn.LocalAddr(), "to", remote, "on", intf.Name)
|
||||
}
|
||||
|
||||
_, err = conn.WriteTo(buf, remote)
|
||||
@@ -140,8 +139,8 @@ func (d *Discoverer) sendAnnouncements() {
|
||||
// Some interfaces don't seem to support broadcast even though the flags claims they do, i.e. vmnet
|
||||
conn.Close()
|
||||
|
||||
if Debug {
|
||||
log.Println("discover/write: debug:", err)
|
||||
if debug {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
errCounter++
|
||||
@@ -173,8 +172,8 @@ func (d *Discoverer) sendExtAnnouncements() {
|
||||
var errCounter = 0
|
||||
|
||||
for errCounter < maxErrors {
|
||||
if Debug {
|
||||
log.Println("send announcement -> ", remote)
|
||||
if debug {
|
||||
dlog.Println("send announcement -> ", remote)
|
||||
}
|
||||
_, err = d.conn.WriteTo(buf, remote)
|
||||
if err != nil {
|
||||
@@ -200,8 +199,8 @@ func (d *Discoverer) recvAnnouncements() {
|
||||
continue
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Printf("read announcement:\n%s", hex.Dump(buf[:n]))
|
||||
if debug {
|
||||
dlog.Printf("read announcement:\n%s", hex.Dump(buf[:n]))
|
||||
}
|
||||
|
||||
var pkt AnnounceV2
|
||||
@@ -212,8 +211,8 @@ func (d *Discoverer) recvAnnouncements() {
|
||||
continue
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Printf("read announcement: %#v", pkt)
|
||||
if debug {
|
||||
dlog.Printf("parsed announcement: %#v", pkt)
|
||||
}
|
||||
|
||||
errCounter = 0
|
||||
@@ -229,8 +228,8 @@ func (d *Discoverer) recvAnnouncements() {
|
||||
}
|
||||
addrs = append(addrs, nodeAddr)
|
||||
}
|
||||
if Debug {
|
||||
log.Printf("register: %#v", addrs)
|
||||
if debug {
|
||||
dlog.Printf("register: %#v", addrs)
|
||||
}
|
||||
d.registryLock.Lock()
|
||||
_, seen := d.registry[pkt.NodeID]
|
||||
@@ -287,8 +286,8 @@ func (d *Discoverer) externalLookup(node string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Printf("read external:\n%s", hex.Dump(buf[:n]))
|
||||
if debug {
|
||||
dlog.Printf("read external:\n%s", hex.Dump(buf[:n]))
|
||||
}
|
||||
|
||||
var pkt AnnounceV2
|
||||
@@ -298,8 +297,8 @@ func (d *Discoverer) externalLookup(node string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Printf("read external: %#v", pkt)
|
||||
if debug {
|
||||
dlog.Printf("parsed external: %#v", pkt)
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
|
||||
2
discover/doc.go
Normal file
2
discover/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package discover implements the node discovery protocol.
|
||||
package discover
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package fileset provides a set type to track local/remote files with newness checks.
|
||||
package fileset
|
||||
|
||||
import "sync"
|
||||
|
||||
@@ -32,6 +32,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
||||
{id: 'FollowSymlinks', descr: 'Follow Symlinks', type: 'bool', restart: true},
|
||||
{id: 'GlobalAnnEnabled', descr: 'Global Announce', type: 'bool', restart: true},
|
||||
{id: 'LocalAnnEnabled', descr: 'Local Announce', type: 'bool', restart: true},
|
||||
{id: 'StartBrowser', descr: 'Start Browser', type: 'bool'},
|
||||
];
|
||||
|
||||
function modelGetSucceeded() {
|
||||
@@ -317,7 +318,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
||||
}
|
||||
return errors;
|
||||
};
|
||||
|
||||
|
||||
$scope.clearErrors = function () {
|
||||
$scope.seenError = $scope.errors[$scope.errors.length - 1].Time;
|
||||
};
|
||||
|
||||
7
integration/.gitignore
vendored
7
integration/.gitignore
vendored
@@ -1,5 +1,8 @@
|
||||
files-*
|
||||
conf-*
|
||||
s1
|
||||
s2
|
||||
s3
|
||||
md5-*
|
||||
genfiles
|
||||
md5r
|
||||
json
|
||||
*.idx.gz
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
mr "math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
func name() string {
|
||||
@@ -38,5 +39,10 @@ func main() {
|
||||
rand.Reader.Read(b)
|
||||
p1 := path.Join(p0, n)
|
||||
ioutil.WriteFile(p1, b, 0644)
|
||||
|
||||
os.Chmod(p1, os.FileMode(mr.Intn(0777)|0400))
|
||||
|
||||
t := time.Now().Add(-time.Duration(mr.Intn(30*86400)) * time.Second)
|
||||
os.Chtimes(p1, t, t)
|
||||
}
|
||||
}
|
||||
|
||||
23
integration/h1/cert.pem
Normal file
23
integration/h1/cert.pem
Normal file
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro
|
||||
aW5nMB4XDTE0MDMxNDA3MDA1M1oXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ
|
||||
c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArDOcd5ft
|
||||
R7SnalxF1ckU3lDQpgfMIPhFDU//4dvdSSFevrMuVDTbUYhyCfGtg/g+F5TmKhZg
|
||||
E2peYhllITupz5MP7OHGaO2GHf2XnUDD4QUO3E+KVAUw7dyFSwy09esqApVLzH3+
|
||||
ov+QXyyzmRWPsJe9u18BHU1Hob/RmBhS9m2CAJgzN6EJ8KGjApiW3iR8lD/hjVyi
|
||||
IVde8IRD6qYHEJYiPJuziTVcQpCblVYxTz3ScmmT190/O9UvViIpcOPQdwgOdewP
|
||||
NNMK35c9Edt0AH5flYp6jgrja9NkLQJ3+KOiro6yl9IUS5w87GMxI8qzI8SgCAZZ
|
||||
pYSoLbu1FJPvxV4p5eHwuprBCwmFYZWw6Y7rqH0sN52C+3TeObJCMNP9ilPadqRI
|
||||
+G0Q99TCaloeR022x33r/8D8SIn3FP35zrlFM+DvqlxoS6glbNb/Bj3p9vN0XONO
|
||||
RCuynOGe9F/4h/DaNnrbrRWqJOxBsZTsbbcJaKATfWU/Z9GcC+pUpPRhAgMBAAGj
|
||||
PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAFF8dklGoC43fMrUZfb4
|
||||
6areRWG8quO6cSX6ATzRQVJ8WJ5VcC7OJk8/FeiYA+wcvUJ/1Zm/VHMYugtOz5M8
|
||||
CrWAF1r9D3Xfe5D8qfrEOYG2XjxD2nFHCnkbY4fP+SMSuXaDs7ixQnzw0UFh1wsV
|
||||
9Jy/QrgXFAIFZtu1Nz+rrvoAgw24gkDhY3557MbmYfmfPsJ8cw+WJ845sxGMPFF2
|
||||
c+5EN0jiSm0AwZK11BMJda36ke829UZctDkopbGEg1peydDR5LiyhiTAPtWn7uT/
|
||||
PkzHYLuaECAkVbWC3bZLocMGOP6F1pG+BMr00NJgVy05ASQzi4FPjcZQNNY8s69R
|
||||
ZgoCIBaJZq3ti1EsZQ1H0Ynm2c2NMVKdj4czoy8a9ZC+DCuhG7EV5Foh20VhCWgA
|
||||
RfPhlHVJthuimsWBx39X85gjSBR017uk0AxOJa6pzh/b/RPCRtUfX8EArInS3XCf
|
||||
RvRtdrnBZNI3tiREopZGt0SzgDZUs4uDVBUX8HnHzyFJrg==
|
||||
-----END CERTIFICATE-----
|
||||
30
integration/h1/config.xml
Normal file
30
integration/h1/config.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<configuration version="1">
|
||||
<repository directory="s1">
|
||||
<node id="I6KAH7666SLLL5PFXSOAUFJCDZYAOMLEKCP2GB3BV5RQST3PSROA" name="s1">
|
||||
<address>127.0.0.1:22001</address>
|
||||
</node>
|
||||
<node id="JMFJCXBGZDE4BOCJE3VF65GYZNAIVJRET3J6HMRAUQIGJOFKNHMQ" name="s2">
|
||||
<address>127.0.0.1:22002</address>
|
||||
</node>
|
||||
<node id="373HSRPQLPNLIJYKZVQFP4PKZ6R2ZE6K3YD442UJHBGBQGWWXAHA" name="s3">
|
||||
<address>127.0.0.1:22003</address>
|
||||
</node>
|
||||
</repository>
|
||||
<options>
|
||||
<listenAddress>127.0.0.1:22001</listenAddress>
|
||||
<readOnly>false</readOnly>
|
||||
<allowDelete>true</allowDelete>
|
||||
<followSymlinks>true</followSymlinks>
|
||||
<guiEnabled>true</guiEnabled>
|
||||
<guiAddress>127.0.0.1:8081</guiAddress>
|
||||
<globalAnnounceServer>announce.syncthing.net:22025</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>false</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<parallelRequests>16</parallelRequests>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<rescanIntervalS>60</rescanIntervalS>
|
||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||
<maxChangeKbps>1000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
</options>
|
||||
</configuration>
|
||||
39
integration/h1/key.pem
Normal file
39
integration/h1/key.pem
Normal file
@@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
23
integration/h2/cert.pem
Normal file
23
integration/h2/cert.pem
Normal file
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro
|
||||
aW5nMB4XDTE0MDMxNDA3MDEwNFoXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ
|
||||
c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAsIV0syyR
|
||||
O56BvIOro4bIqB6iFJsNc4zX8MiM4QPTWgqGlYwsKSVmNppTdlACZCJIqyzoscrF
|
||||
qJPto8/e2Fc3oaTdEREGIs7cmc7LSXfot/mAgPpy71SVWtb7xNmXro2JJPZjRBCS
|
||||
pl1ulPug+/8w7fSKQdLMjh4Hp2YlwVBfVu0bYEEW+7Vl9PZVTv+NbTqXYvYVc9R6
|
||||
QFIbN/njWAuo2wpjJlY7vqNnSYZyskAaaAC17fFJkVQKKblTeTk1C9PxTmVTB1j9
|
||||
yOoD3+V/6IrTYKXdTHGJ1MqdieTHj1jHXe5TOeSB+Hjgq4tr25mPfQ4ixXqDqIcx
|
||||
5390DAjInuSKNUJ5pqiFrVe9eIDmySZCg5/JIL3c8phy6g1bxiJN14+Dn0om/0+9
|
||||
UrHK8LVzWMmtFRVycWVUYmARWFY3EE10k0RXU2HtzmjfnBkRrl13b0ExizlA1qJ3
|
||||
3ngxF5rNEDSMpwf4og5uYOjRUPYuvCL9XtQKr254NFO/sg/qqPV4hFWTAgMBAAGj
|
||||
PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAAZSU08zAzyuGqKqqU/c
|
||||
Pr+xML8oKiJqko5pb3ETDQC+uVw+qUHwiGYsvHI1cih4ix+tKvf+Yaiizp/35VkP
|
||||
qwls3a4ljq1Ww0Sf7J87QX0DumYpBGOfoCpmV4MacyjLhpLRKRGZHwIbOeFsmEu9
|
||||
oO38co+GvDy4CiAt3tuOdjBNs0gNOAdTTxqgm97raB9oXeg2i4Fb4MCT4UBUdXLM
|
||||
ZNLCifza+PWkBxmfBORvlKGeJBruLpXHBWnWEigZSLXIFjn3JJUy4fKd+/JMp063
|
||||
8Pjo6zUOckBCH8Lv90vzfrmdlQK555jWpcebN0l9neESEXw19l0OlqkJGVTr6JKq
|
||||
w5kjiL4eP7kpKKwCezhDSX3jf4P36wdF8MpOUBxVqfM+Oh5tHIcZctnurhYV7rXs
|
||||
jR70FMqWjHBmwemsXGrObNVt8c75yB+19U6DAulr2RhRw5GD74U1znP00eGZ8TJf
|
||||
RN1FYilUPCawMYeQoB8WIn9So7zIm0MfOl4KXNWDX02+Kw==
|
||||
-----END CERTIFICATE-----
|
||||
30
integration/h2/config.xml
Normal file
30
integration/h2/config.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<configuration version="1">
|
||||
<repository directory="s2">
|
||||
<node id="I6KAH7666SLLL5PFXSOAUFJCDZYAOMLEKCP2GB3BV5RQST3PSROA" name="s1">
|
||||
<address>127.0.0.1:22001</address>
|
||||
</node>
|
||||
<node id="JMFJCXBGZDE4BOCJE3VF65GYZNAIVJRET3J6HMRAUQIGJOFKNHMQ" name="s2">
|
||||
<address>127.0.0.1:22002</address>
|
||||
</node>
|
||||
<node id="373HSRPQLPNLIJYKZVQFP4PKZ6R2ZE6K3YD442UJHBGBQGWWXAHA" name="s3">
|
||||
<address>127.0.0.1:22003</address>
|
||||
</node>
|
||||
</repository>
|
||||
<options>
|
||||
<listenAddress>127.0.0.2:22002</listenAddress>
|
||||
<readOnly>false</readOnly>
|
||||
<allowDelete>true</allowDelete>
|
||||
<followSymlinks>true</followSymlinks>
|
||||
<guiEnabled>true</guiEnabled>
|
||||
<guiAddress>127.0.0.1:8082</guiAddress>
|
||||
<globalAnnounceServer>announce.syncthing.net:22025</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>false</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<parallelRequests>16</parallelRequests>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<rescanIntervalS>60</rescanIntervalS>
|
||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||
<maxChangeKbps>1000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
</options>
|
||||
</configuration>
|
||||
39
integration/h2/key.pem
Normal file
39
integration/h2/key.pem
Normal file
@@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
23
integration/h3/cert.pem
Normal file
23
integration/h3/cert.pem
Normal file
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro
|
||||
aW5nMB4XDTE0MDMxNDA3MDExMVoXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ
|
||||
c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAypziXAfA
|
||||
GG5mEwTIo+dUt3a4SxKnCVWfTXq7RF5ukCdz3jRRRoqy2ujbW5oe7qmqELTUzkJU
|
||||
eJkuCyvLIhVsKgt2r1peThy5+3/kUst9Faitnke1/jYtWwSf7WmK9TQBN/tFxdgR
|
||||
SM0LpdvsIJQqB5eodR51KrsjkJcKzEHeE2IQA8EKD1LcfXz8p22zdaZ4CNhz7mgF
|
||||
ghkRT6NINDZiMtm6R4qXqYyW1MNlYLw+DqXvE2eCQMQOcqI7SSZTeS3eSTP5NQum
|
||||
AmaLKn3JZQ9G6Ldn0VSWSPlXqVSaFTI9LnYICTDa4Nj4+L6idwzjmBkxPr8vBjlj
|
||||
15eo6xcU4fKqh2/xHIcZYpas1bwo5ljGdcfRm4L1zpxDY+nJFIgRv0Ndpltve+T8
|
||||
o3qiqFvIMiphFUtdb2pzgaTi8FW9SHMRFiuj6sNLI0Yb9u8BoN/QsWZnFh6fQoHW
|
||||
PKtkJrPZGw4GMMTHeEQe/eLW9VAH7ywPyc2hSzSri44aR44s4ErSV+XfAgMBAAGj
|
||||
PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAJshUcNfAveVE115S/NQ
|
||||
h+HfqahB3Gw69KmSWgFNXAEyXwOftmz9p2gL6DwfbU1SkbakU/YLJ3/mP4Q69EmX
|
||||
axzr108hUJ2qxH091IfKPCuTDtLsFY7g0PI+SBzADFSkoFe79aF/PSjaZk6fjvEl
|
||||
44PXzhxqqnSS+9lXQk+DIS6/jSVuX1XYvkkdHRXd9d7nw42sONDdSX8oQAUvGOeR
|
||||
CBleWB4AqS6HH2zFVIzRvjDsSg2wUXQjcqMqef7zBMpuWKTIQf+uaXWsEuPK2a3V
|
||||
IPwreWGwkxqGTToLagqOdAhgN+owvTJS9PaqxFqlxp8ypIYBnZ5VL5G5p115C17/
|
||||
xVENRxX0/oB99L5HGRhAuIGE4LhXq858DzmTZFcwm3fHragPKS/MMI71Z6U5RH2p
|
||||
VouosWzxAEx3Piq+ccenPLt6VPO5iFn+ppoBfwAFtNKyTrXcTQm33oJWFz+NSMAl
|
||||
vCq5H4c9x5CoWDpX2bdjpnZ3xcSj84fPYpkKBI52eZAvcw==
|
||||
-----END CERTIFICATE-----
|
||||
30
integration/h3/config.xml
Normal file
30
integration/h3/config.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<configuration version="1">
|
||||
<repository directory="s3">
|
||||
<node id="I6KAH7666SLLL5PFXSOAUFJCDZYAOMLEKCP2GB3BV5RQST3PSROA" name="s1">
|
||||
<address>127.0.0.1:22001</address>
|
||||
</node>
|
||||
<node id="JMFJCXBGZDE4BOCJE3VF65GYZNAIVJRET3J6HMRAUQIGJOFKNHMQ" name="s2">
|
||||
<address>127.0.0.1:22002</address>
|
||||
</node>
|
||||
<node id="373HSRPQLPNLIJYKZVQFP4PKZ6R2ZE6K3YD442UJHBGBQGWWXAHA" name="s3">
|
||||
<address>127.0.0.1:22003</address>
|
||||
</node>
|
||||
</repository>
|
||||
<options>
|
||||
<listenAddress>127.0.0.1:22003</listenAddress>
|
||||
<readOnly>false</readOnly>
|
||||
<allowDelete>true</allowDelete>
|
||||
<followSymlinks>true</followSymlinks>
|
||||
<guiEnabled>true</guiEnabled>
|
||||
<guiAddress>127.0.0.1:8083</guiAddress>
|
||||
<globalAnnounceServer>announce.syncthing.net:22025</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>false</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<parallelRequests>16</parallelRequests>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<rescanIntervalS>60</rescanIntervalS>
|
||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||
<maxChangeKbps>1000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
</options>
|
||||
</configuration>
|
||||
39
integration/h3/key.pem
Normal file
39
integration/h3/key.pem
Normal file
@@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
39
integration/json.go
Normal file
39
integration/json.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
flag.Parse()
|
||||
path := strings.Split(flag.Arg(0), "/")
|
||||
|
||||
var obj map[string]interface{}
|
||||
dec := json.NewDecoder(os.Stdin)
|
||||
dec.UseNumber()
|
||||
dec.Decode(&obj)
|
||||
|
||||
var v interface{} = obj
|
||||
for _, p := range path {
|
||||
switch tv := v.(type) {
|
||||
case map[string]interface{}:
|
||||
v = tv[p]
|
||||
case []interface{}:
|
||||
i, err := strconv.Atoi(p)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
v = tv[i]
|
||||
default:
|
||||
return // Silence is golden
|
||||
}
|
||||
}
|
||||
fmt.Println(v)
|
||||
}
|
||||
@@ -9,7 +9,10 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var long bool
|
||||
|
||||
func main() {
|
||||
flag.BoolVar(&long, "l", false, "Long output")
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
@@ -37,7 +40,12 @@ func walker(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s %s\n", sum, path)
|
||||
if long {
|
||||
fmt.Printf("%s %s 0%03o %d\n", sum, path, info.Mode(), info.ModTime().Unix())
|
||||
|
||||
} else {
|
||||
fmt.Printf("%s %s\n", sum, path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,74 +1,94 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf files-* conf-* md5-*
|
||||
export STNORESTART=1
|
||||
|
||||
extraopts=""
|
||||
p=$(pwd)
|
||||
id1=I6KAH7666SLLL5PFXSOAUFJCDZYAOMLEKCP2GB3BV5RQST3PSROA
|
||||
id2=JMFJCXBGZDE4BOCJE3VF65GYZNAIVJRET3J6HMRAUQIGJOFKNHMQ
|
||||
id3=373HSRPQLPNLIJYKZVQFP4PKZ6R2ZE6K3YD442UJHBGBQGWWXAHA
|
||||
|
||||
go build genfiles.go
|
||||
go build md5r.go
|
||||
go build json.go
|
||||
|
||||
echo "Setting up (keys)..."
|
||||
i1=$(syncthing --home conf-1 2>&1 | awk '/My ID/ {print $7}')
|
||||
echo $i1
|
||||
i2=$(syncthing --home conf-2 2>&1 | awk '/My ID/ {print $7}')
|
||||
echo $i2
|
||||
i3=$(syncthing --home conf-3 2>&1 | awk '/My ID/ {print $7}')
|
||||
echo $i3
|
||||
|
||||
echo "Setting up (files)..."
|
||||
for i in 1 2 3 ; do
|
||||
cat >conf-$i/syncthing.ini <<EOT
|
||||
[repository]
|
||||
dir = $p/files-$i
|
||||
|
||||
[nodes]
|
||||
$i1 = 127.0.0.1:22001
|
||||
$i2 = 127.0.0.1:22002
|
||||
$i3 = 127.0.0.1:22003
|
||||
|
||||
[settings]
|
||||
gui-enabled = false
|
||||
listen-address = :2200$i
|
||||
EOT
|
||||
|
||||
mkdir files-$i
|
||||
pushd files-$i >/dev/null
|
||||
../genfiles -maxexp 21 -files 400
|
||||
touch empty-$i
|
||||
../md5r > ../md5-$i
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
echo "Starting..."
|
||||
for i in 1 2 3 ; do
|
||||
sleep 1
|
||||
syncthing --home conf-$i $extraopts &
|
||||
done
|
||||
|
||||
cat md5-* | sort > md5-tot
|
||||
while true ; do
|
||||
read
|
||||
echo Verifying...
|
||||
|
||||
conv=0
|
||||
testConvergence() {
|
||||
echo "Starting..."
|
||||
for i in 1 2 3 ; do
|
||||
pushd files-$i >/dev/null
|
||||
../md5r | sort > ../md5-$i
|
||||
popd >/dev/null
|
||||
if ! cmp md5-$i md5-tot >/dev/null ; then
|
||||
echo $i unconverged
|
||||
else
|
||||
conv=$((conv + 1))
|
||||
echo $i converged
|
||||
sleep 1
|
||||
syncthing -home "h$i" &
|
||||
done
|
||||
|
||||
while true ; do
|
||||
sleep 5
|
||||
s1comp=$(curl -s "http://localhost:8082/rest/connections" | ./json "$id1/Completion")
|
||||
s2comp=$(curl -s "http://localhost:8083/rest/connections" | ./json "$id2/Completion")
|
||||
s3comp=$(curl -s "http://localhost:8081/rest/connections" | ./json "$id3/Completion")
|
||||
s1comp=${s1comp:-0}
|
||||
s2comp=${s2comp:-0}
|
||||
s3comp=${s3comp:-0}
|
||||
tot=$(($s1comp + $s2comp + $s3comp))
|
||||
echo $tot / 300
|
||||
if [[ $tot == 300 ]] ; then
|
||||
echo "Stopping..."
|
||||
pkill syncthing
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $conv == 3 ]] ; then
|
||||
kill %1
|
||||
kill %2
|
||||
kill %3
|
||||
exit
|
||||
fi
|
||||
echo "Verifying..."
|
||||
cat md5-* | sort | uniq > md5-tot
|
||||
|
||||
for i in 1 2 3 ; do
|
||||
pushd "s$i" >/dev/null
|
||||
../md5r -l | sort > ../md5-$i
|
||||
popd >/dev/null
|
||||
if ! cmp "md5-$i" md5-tot >/dev/null ; then
|
||||
echo "Fail: instance $i unconverged"
|
||||
diff -u md5-tot "md5-$i"
|
||||
exit
|
||||
else
|
||||
echo "OK: instance $i converged"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo "Setting up files..."
|
||||
for i in 1 2 3 ; do
|
||||
rm -f h$i/*.idx.gz
|
||||
rm -rf "s$i"
|
||||
mkdir "s$i"
|
||||
pushd "s$i" >/dev/null
|
||||
echo " $i: random nonoverlapping"
|
||||
../genfiles -maxexp 22 -files 600
|
||||
echo " $i: empty file"
|
||||
touch "empty-$i"
|
||||
echo " $i: common file"
|
||||
dd if=/dev/urandom of=common bs=1000 count=1000 2>/dev/null
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
# instance 1 common file should be the newest, the other should disappear
|
||||
sleep 2
|
||||
touch "s1/common"
|
||||
|
||||
echo "MD5-summing..."
|
||||
for i in 1 2 3 ; do
|
||||
pushd "s$i" >/dev/null
|
||||
../md5r -l > ../md5-$i
|
||||
popd >/dev/null
|
||||
done
|
||||
grep -v common md5-2 > t ; mv t md5-2
|
||||
grep -v common md5-3 > t ; mv t md5-3
|
||||
|
||||
testConvergence
|
||||
|
||||
echo "Add and remove random files..."
|
||||
for i in 1 2 3 ; do
|
||||
pushd "s$i" >/dev/null
|
||||
rm -rf */?[02468ace]
|
||||
../genfiles -maxexp 22 -files 600
|
||||
../md5r -l > ../md5-$i
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
testConvergence
|
||||
|
||||
|
||||
2
protocol/doc.go
Normal file
2
protocol/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package protocol implements the Block Exchange Protocol.
|
||||
package protocol
|
||||
@@ -26,8 +26,8 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
FlagDeleted = 1 << 12
|
||||
FlagInvalid = 1 << 13
|
||||
FlagDeleted uint32 = 1 << 12
|
||||
FlagInvalid = 1 << 13
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
12
scanner/debug.go
Normal file
12
scanner/debug.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
dlog = log.New(os.Stderr, "scanner: ", log.Lmicroseconds|log.Lshortfile)
|
||||
debug = strings.Contains(os.Getenv("STTRACE"), "scanner")
|
||||
)
|
||||
2
scanner/doc.go
Normal file
2
scanner/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package scanner implements a file system scanner and hasher.
|
||||
package scanner
|
||||
26
scanner/file.go
Normal file
26
scanner/file.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package scanner
|
||||
|
||||
import "fmt"
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
Flags uint32
|
||||
Modified int64
|
||||
Version uint32
|
||||
Size int64
|
||||
Blocks []Block
|
||||
Suppressed bool
|
||||
}
|
||||
|
||||
func (f File) String() string {
|
||||
return fmt.Sprintf("File{Name:%q, Flags:0x%x, Modified:%d, Version:%d, Size:%d, NumBlocks:%d}",
|
||||
f.Name, f.Flags, f.Modified, f.Version, f.Size, len(f.Blocks))
|
||||
}
|
||||
|
||||
func (f File) Equals(o File) bool {
|
||||
return f.Modified == o.Modified && f.Version == o.Version
|
||||
}
|
||||
|
||||
func (f File) NewerThan(o File) bool {
|
||||
return f.Modified > o.Modified || (f.Modified == o.Modified && f.Version > o.Version)
|
||||
}
|
||||
0
scanner/testdata/.foo/bar
vendored
Normal file
0
scanner/testdata/.foo/bar
vendored
Normal file
2
scanner/testdata/.stignore
vendored
Normal file
2
scanner/testdata/.stignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.*
|
||||
quux
|
||||
1
scanner/testdata/bar
vendored
Normal file
1
scanner/testdata/bar
vendored
Normal file
@@ -0,0 +1 @@
|
||||
foobarbaz
|
||||
1
scanner/testdata/baz/quux
vendored
Normal file
1
scanner/testdata/baz/quux
vendored
Normal file
@@ -0,0 +1 @@
|
||||
baazquux
|
||||
0
scanner/testdata/empty
vendored
Normal file
0
scanner/testdata/empty
vendored
Normal file
1
scanner/testdata/foo
vendored
Normal file
1
scanner/testdata/foo
vendored
Normal file
@@ -0,0 +1 @@
|
||||
foobar
|
||||
262
scanner/walk.go
Normal file
262
scanner/walk.go
Normal file
@@ -0,0 +1,262 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Walker struct {
|
||||
// Dir is the base directory for the walk
|
||||
Dir string
|
||||
// If FollowSymlinks is true, symbolic links directly under Dir will be followed.
|
||||
// Symbolic links at deeper levels are never followed regardless of this flag.
|
||||
FollowSymlinks bool
|
||||
// BlockSize controls the size of the block used when hashing.
|
||||
BlockSize int
|
||||
// If IgnoreFile is not empty, it is the name used for the file that holds ignore patterns.
|
||||
IgnoreFile string
|
||||
// If TempNamer is not nil, it is used to ignore tempory files when walking.
|
||||
TempNamer TempNamer
|
||||
// If CurrentFiler is not nil, it is queried for the current file before rescanning.
|
||||
CurrentFiler CurrentFiler
|
||||
// If Suppressor is not nil, it is queried for supression of modified files.
|
||||
// Suppressed files will be returned with empty metadata and the Suppressed flag set.
|
||||
// Requires CurrentFiler to be set.
|
||||
Suppressor Suppressor
|
||||
|
||||
suppressed map[string]bool // file name -> suppression status
|
||||
}
|
||||
|
||||
type TempNamer interface {
|
||||
// Temporary returns a temporary name for the filed referred to by path.
|
||||
TempName(path string) string
|
||||
// IsTemporary returns true if path refers to the name of temporary file.
|
||||
IsTemporary(path string) bool
|
||||
}
|
||||
|
||||
type Suppressor interface {
|
||||
// Supress returns true if the update to the named file should be ignored.
|
||||
Suppress(name string, fi os.FileInfo) bool
|
||||
}
|
||||
|
||||
type CurrentFiler interface {
|
||||
// CurrentFile returns the file as seen at last scan.
|
||||
CurrentFile(name string) File
|
||||
}
|
||||
|
||||
// Walk returns the list of files found in the local repository by scanning the
|
||||
// file system. Files are blockwise hashed.
|
||||
func (w *Walker) Walk() (files []File, ignore map[string][]string) {
|
||||
w.lazyInit()
|
||||
|
||||
if debug {
|
||||
dlog.Println("Walk", w.Dir, w.FollowSymlinks, w.BlockSize, w.IgnoreFile)
|
||||
}
|
||||
t0 := time.Now()
|
||||
|
||||
ignore = make(map[string][]string)
|
||||
hashFiles := w.walkAndHashFiles(&files, ignore)
|
||||
|
||||
filepath.Walk(w.Dir, w.loadIgnoreFiles(w.Dir, ignore))
|
||||
filepath.Walk(w.Dir, hashFiles)
|
||||
|
||||
if w.FollowSymlinks {
|
||||
d, err := os.Open(w.Dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
fis, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, info := range fis {
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
dir := path.Join(w.Dir, info.Name()) + "/"
|
||||
filepath.Walk(dir, w.loadIgnoreFiles(dir, ignore))
|
||||
filepath.Walk(dir, hashFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if debug {
|
||||
t1 := time.Now()
|
||||
d := t1.Sub(t0).Seconds()
|
||||
dlog.Printf("Walk in %.02f ms, %.0f files/s", d*1000, float64(len(files))/d)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CleanTempFiles removes all files that match the temporary filename pattern.
|
||||
func (w *Walker) CleanTempFiles() {
|
||||
filepath.Walk(w.Dir, w.cleanTempFile)
|
||||
}
|
||||
|
||||
func (w *Walker) lazyInit() {
|
||||
if w.suppressed == nil {
|
||||
w.suppressed = make(map[string]bool)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Walker) loadIgnoreFiles(dir string, ign map[string][]string) filepath.WalkFunc {
|
||||
return func(p string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rn, err := filepath.Rel(dir, p)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pn, sn := path.Split(rn); sn == w.IgnoreFile {
|
||||
pn := strings.Trim(pn, "/")
|
||||
bs, _ := ioutil.ReadFile(p)
|
||||
lines := bytes.Split(bs, []byte("\n"))
|
||||
var patterns []string
|
||||
for _, line := range lines {
|
||||
if len(line) > 0 {
|
||||
patterns = append(patterns, string(line))
|
||||
}
|
||||
}
|
||||
ign[pn] = patterns
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Walker) walkAndHashFiles(res *[]File, ign map[string][]string) filepath.WalkFunc {
|
||||
return func(p string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
if debug {
|
||||
dlog.Println("error:", p, info, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
rn, err := filepath.Rel(w.Dir, p)
|
||||
if err != nil {
|
||||
if debug {
|
||||
dlog.Println("rel error:", p, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if w.TempNamer != nil && w.TempNamer.IsTemporary(rn) {
|
||||
if debug {
|
||||
dlog.Println("temporary:", rn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, sn := path.Split(rn); sn == w.IgnoreFile {
|
||||
if debug {
|
||||
dlog.Println("ignorefile:", rn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if rn != "." && w.ignoreFile(ign, rn) {
|
||||
if debug {
|
||||
dlog.Println("ignored:", rn)
|
||||
}
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.Mode()&os.ModeType == 0 {
|
||||
if w.CurrentFiler != nil {
|
||||
cf := w.CurrentFiler.CurrentFile(rn)
|
||||
if cf.Modified == info.ModTime().Unix() {
|
||||
if debug {
|
||||
dlog.Println("unchanged:", rn)
|
||||
}
|
||||
*res = append(*res, cf)
|
||||
return nil
|
||||
}
|
||||
|
||||
if w.Suppressor != nil && w.Suppressor.Suppress(rn, info) {
|
||||
if debug {
|
||||
dlog.Println("suppressed:", rn)
|
||||
}
|
||||
if !w.suppressed[rn] {
|
||||
w.suppressed[rn] = true
|
||||
log.Printf("INFO: Changes to %q are being temporarily suppressed because it changes too frequently.", p)
|
||||
}
|
||||
cf.Suppressed = true
|
||||
*res = append(*res, cf)
|
||||
} else if w.suppressed[rn] {
|
||||
log.Printf("INFO: Changes to %q are no longer suppressed.", p)
|
||||
delete(w.suppressed, rn)
|
||||
}
|
||||
}
|
||||
|
||||
fd, err := os.Open(p)
|
||||
if err != nil {
|
||||
if debug {
|
||||
dlog.Println("open:", p, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
t0 := time.Now()
|
||||
blocks, err := Blocks(fd, w.BlockSize)
|
||||
if err != nil {
|
||||
if debug {
|
||||
dlog.Println("hash error:", rn, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if debug {
|
||||
t1 := time.Now()
|
||||
dlog.Println("hashed:", rn, ";", len(blocks), "blocks;", info.Size(), "bytes;", int(float64(info.Size())/1024/t1.Sub(t0).Seconds()), "KB/s")
|
||||
}
|
||||
f := File{
|
||||
Name: rn,
|
||||
Size: info.Size(),
|
||||
Flags: uint32(info.Mode()),
|
||||
Modified: info.ModTime().Unix(),
|
||||
Blocks: blocks,
|
||||
}
|
||||
*res = append(*res, f)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Walker) cleanTempFile(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode()&os.ModeType == 0 && w.TempNamer.IsTemporary(path) {
|
||||
os.Remove(path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Walker) ignoreFile(patterns map[string][]string, file string) bool {
|
||||
first, last := path.Split(file)
|
||||
for prefix, pats := range patterns {
|
||||
if len(prefix) == 0 || prefix == first || strings.HasPrefix(first, prefix+"/") {
|
||||
for _, pattern := range pats {
|
||||
if match, _ := path.Match(pattern, last); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -22,8 +22,12 @@ var correctIgnores = map[string][]string{
|
||||
}
|
||||
|
||||
func TestWalk(t *testing.T) {
|
||||
m := NewModel("testdata", 1e6)
|
||||
files, ignores := m.Walk(false)
|
||||
w := Walker{
|
||||
Dir: "testdata",
|
||||
BlockSize: 128 * 1024,
|
||||
IgnoreFile: ".stignore",
|
||||
}
|
||||
files, ignores := w.Walk()
|
||||
|
||||
if l1, l2 := len(files), len(testdata); l1 != l2 {
|
||||
t.Fatalf("Incorrect number of walked files %d != %d", l1, l2)
|
||||
@@ -75,8 +79,9 @@ func TestIgnore(t *testing.T) {
|
||||
{"foo/bazz/quux", false},
|
||||
}
|
||||
|
||||
w := Walker{}
|
||||
for i, tc := range tests {
|
||||
if r := ignoreFile(patterns, tc.f); r != tc.r {
|
||||
if r := w.ignoreFile(patterns, tc.f); r != tc.r {
|
||||
t.Errorf("Incorrect ignoreFile() #%d; E: %v, A: %v", i, tc.r, r)
|
||||
}
|
||||
}
|
||||
2
xdr/doc.go
Normal file
2
xdr/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package xdr implements an XDR (RFC 4506) encoder/decoder.
|
||||
package xdr
|
||||
Reference in New Issue
Block a user