util.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package model
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "runtime"
  7. "github.com/calmh/syncthing/protocol"
  8. "github.com/calmh/syncthing/scanner"
  9. )
  10. func Rename(from, to string) error {
  11. if runtime.GOOS == "windows" {
  12. err := os.Remove(to)
  13. if err != nil && !os.IsNotExist(err) {
  14. l.Warnln(err)
  15. }
  16. }
  17. return os.Rename(from, to)
  18. }
  19. func fileFromFileInfo(f protocol.FileInfo) scanner.File {
  20. var blocks = make([]scanner.Block, len(f.Blocks))
  21. var offset int64
  22. for i, b := range f.Blocks {
  23. blocks[i] = scanner.Block{
  24. Offset: offset,
  25. Size: b.Size,
  26. Hash: b.Hash,
  27. }
  28. offset += int64(b.Size)
  29. }
  30. return scanner.File{
  31. // Name is with native separator and normalization
  32. Name: filepath.FromSlash(f.Name),
  33. Size: offset,
  34. Flags: f.Flags &^ protocol.FlagInvalid,
  35. Modified: f.Modified,
  36. Version: f.Version,
  37. Blocks: blocks,
  38. Suppressed: f.Flags&protocol.FlagInvalid != 0,
  39. }
  40. }
  41. func fileInfoFromFile(f scanner.File) protocol.FileInfo {
  42. var blocks = make([]protocol.BlockInfo, len(f.Blocks))
  43. for i, b := range f.Blocks {
  44. blocks[i] = protocol.BlockInfo{
  45. Size: b.Size,
  46. Hash: b.Hash,
  47. }
  48. }
  49. pf := protocol.FileInfo{
  50. Name: filepath.ToSlash(f.Name),
  51. Flags: f.Flags,
  52. Modified: f.Modified,
  53. Version: f.Version,
  54. Blocks: blocks,
  55. }
  56. if f.Suppressed {
  57. pf.Flags |= protocol.FlagInvalid
  58. }
  59. return pf
  60. }
  61. func cmMap(cm protocol.ClusterConfigMessage) map[string]map[string]uint32 {
  62. m := make(map[string]map[string]uint32)
  63. for _, repo := range cm.Repositories {
  64. m[repo.ID] = make(map[string]uint32)
  65. for _, node := range repo.Nodes {
  66. m[repo.ID][node.ID] = node.Flags
  67. }
  68. }
  69. return m
  70. }
  71. type ClusterConfigMismatch error
  72. // compareClusterConfig returns nil for two equivalent configurations,
  73. // otherwise a decriptive error
  74. func compareClusterConfig(local, remote protocol.ClusterConfigMessage) error {
  75. lm := cmMap(local)
  76. rm := cmMap(remote)
  77. for repo, lnodes := range lm {
  78. _ = lnodes
  79. if rnodes, ok := rm[repo]; ok {
  80. for node, lflags := range lnodes {
  81. if rflags, ok := rnodes[node]; ok {
  82. if lflags&protocol.FlagShareBits != rflags&protocol.FlagShareBits {
  83. return ClusterConfigMismatch(fmt.Errorf("remote has different sharing flags for node %q in repository %q", node, repo))
  84. }
  85. }
  86. }
  87. } else {
  88. return ClusterConfigMismatch(fmt.Errorf("remote is missing repository %q", repo))
  89. }
  90. }
  91. for repo := range rm {
  92. if _, ok := lm[repo]; !ok {
  93. return ClusterConfigMismatch(fmt.Errorf("remote has extra repository %q", repo))
  94. }
  95. }
  96. return nil
  97. }