forked from syncthing/syncthing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
143 lines (129 loc) · 3.34 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main
import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/calmh/syncthing/protocol"
"github.com/calmh/syncthing/scanner"
)
func MetricPrefix(n int64) string {
if n > 1e9 {
return fmt.Sprintf("%.02f G", float64(n)/1e9)
}
if n > 1e6 {
return fmt.Sprintf("%.02f M", float64(n)/1e6)
}
if n > 1e3 {
return fmt.Sprintf("%.01f k", float64(n)/1e3)
}
return fmt.Sprintf("%d ", n)
}
func BinaryPrefix(n int64) string {
if n > 1<<30 {
return fmt.Sprintf("%.02f Gi", float64(n)/(1<<30))
}
if n > 1<<20 {
return fmt.Sprintf("%.02f Mi", float64(n)/(1<<20))
}
if n > 1<<10 {
return fmt.Sprintf("%.01f Ki", float64(n)/(1<<10))
}
return fmt.Sprintf("%d ", n)
}
func Rename(from, to string) error {
if runtime.GOOS == "windows" {
err := os.Remove(to)
if err != nil && !os.IsNotExist(err) {
warnln(err)
}
}
return os.Rename(from, to)
}
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] = scanner.Block{
Offset: offset,
Size: b.Size,
Hash: b.Hash,
}
offset += int64(b.Size)
}
return scanner.File{
// Name is with native separator and normalization
Name: filepath.FromSlash(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 scanner.File) protocol.FileInfo {
var blocks = make([]protocol.BlockInfo, len(f.Blocks))
for i, b := range f.Blocks {
blocks[i] = protocol.BlockInfo{
Size: b.Size,
Hash: b.Hash,
}
}
pf := protocol.FileInfo{
Name: filepath.ToSlash(f.Name),
Flags: f.Flags,
Modified: f.Modified,
Version: f.Version,
Blocks: blocks,
}
if f.Suppressed {
pf.Flags |= protocol.FlagInvalid
}
return pf
}
func cmMap(cm protocol.ClusterConfigMessage) map[string]map[string]uint32 {
m := make(map[string]map[string]uint32)
for _, repo := range cm.Repositories {
m[repo.ID] = make(map[string]uint32)
for _, node := range repo.Nodes {
m[repo.ID][node.ID] = node.Flags
}
}
return m
}
type ClusterConfigMismatch error
// compareClusterConfig returns nil for two equivalent configurations,
// otherwise a decriptive error
func compareClusterConfig(local, remote protocol.ClusterConfigMessage) error {
lm := cmMap(local)
rm := cmMap(remote)
for repo, lnodes := range lm {
_ = lnodes
if rnodes, ok := rm[repo]; ok {
for node, lflags := range lnodes {
if rflags, ok := rnodes[node]; ok {
if lflags&protocol.FlagShareBits != rflags&protocol.FlagShareBits {
return ClusterConfigMismatch(fmt.Errorf("remote has different sharing flags for node %q in repository %q", node, repo))
}
} else {
return ClusterConfigMismatch(fmt.Errorf("remote is missing node %q in repository %q", node, repo))
}
}
} else {
return ClusterConfigMismatch(fmt.Errorf("remote is missing repository %q", repo))
}
}
for repo, rnodes := range rm {
if lnodes, ok := lm[repo]; ok {
for node := range rnodes {
if _, ok := lnodes[node]; !ok {
return ClusterConfigMismatch(fmt.Errorf("remote has extra node %q in repository %q", node, repo))
}
}
} else {
return ClusterConfigMismatch(fmt.Errorf("remote has extra repository %q", repo))
}
}
return nil
}