2016-07-04 10:40:29 +00:00
|
|
|
// Copyright (C) 2014 The Protocol Authors.
|
|
|
|
|
|
|
|
//go:generate go run ../../script/protofmt.go bep.proto
|
2016-11-03 22:06:51 +00:00
|
|
|
//go:generate protoc -I ../../../../../ -I ../../../../gogo/protobuf/protobuf -I . --gogofast_out=. bep.proto
|
2016-07-04 10:40:29 +00:00
|
|
|
|
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2016-07-23 12:46:31 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
2016-07-04 10:40:29 +00:00
|
|
|
"fmt"
|
2016-08-06 13:05:59 +00:00
|
|
|
"time"
|
2016-07-23 12:46:31 +00:00
|
|
|
|
|
|
|
"github.com/syncthing/syncthing/lib/rand"
|
2016-09-23 19:33:54 +00:00
|
|
|
"github.com/syncthing/syncthing/lib/sha256"
|
2016-07-04 10:40:29 +00:00
|
|
|
)
|
|
|
|
|
2016-09-02 06:45:46 +00:00
|
|
|
const (
|
|
|
|
SyntheticDirectorySize = 128
|
|
|
|
)
|
|
|
|
|
2016-07-04 10:40:29 +00:00
|
|
|
var (
|
|
|
|
sha256OfEmptyBlock = sha256.Sum256(make([]byte, BlockSize))
|
|
|
|
HelloMessageMagic = uint32(0x2EA7D90B)
|
|
|
|
)
|
|
|
|
|
|
|
|
func (m Hello) Magic() uint32 {
|
|
|
|
return HelloMessageMagic
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) String() string {
|
2016-12-09 18:02:18 +00:00
|
|
|
switch f.Type {
|
|
|
|
case FileInfoTypeDirectory:
|
|
|
|
return fmt.Sprintf("Directory{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Deleted:%v, Invalid:%v, NoPermissions:%v}",
|
|
|
|
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Deleted, f.Invalid, f.NoPermissions)
|
|
|
|
case FileInfoTypeFile:
|
|
|
|
return fmt.Sprintf("File{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}",
|
|
|
|
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks)
|
|
|
|
case FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile, FileInfoTypeSymlinkUnknown:
|
|
|
|
return fmt.Sprintf("Symlink{Name:%q, Type:%v, Sequence:%d, Version:%v, Deleted:%v, Invalid:%v, NoPermissions:%v, SymlinkTarget:%q}",
|
|
|
|
f.Name, f.Type, f.Sequence, f.Version, f.Deleted, f.Invalid, f.NoPermissions, f.SymlinkTarget)
|
|
|
|
default:
|
|
|
|
panic("mystery file type detected")
|
|
|
|
}
|
2016-07-04 10:40:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) IsDeleted() bool {
|
|
|
|
return f.Deleted
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) IsInvalid() bool {
|
|
|
|
return f.Invalid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) IsDirectory() bool {
|
|
|
|
return f.Type == FileInfoTypeDirectory
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) IsSymlink() bool {
|
|
|
|
switch f.Type {
|
|
|
|
case FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile, FileInfoTypeSymlinkUnknown:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) HasPermissionBits() bool {
|
|
|
|
return !f.NoPermissions
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) FileSize() int64 {
|
2016-09-02 06:45:46 +00:00
|
|
|
if f.Deleted {
|
|
|
|
return 0
|
|
|
|
}
|
2016-12-09 09:38:36 +00:00
|
|
|
if f.IsDirectory() || f.IsSymlink() {
|
2016-09-02 06:45:46 +00:00
|
|
|
return SyntheticDirectorySize
|
2016-07-04 10:40:29 +00:00
|
|
|
}
|
|
|
|
return f.Size
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f FileInfo) FileName() string {
|
|
|
|
return f.Name
|
|
|
|
}
|
|
|
|
|
2016-08-06 13:05:59 +00:00
|
|
|
func (f FileInfo) ModTime() time.Time {
|
|
|
|
return time.Unix(f.ModifiedS, int64(f.ModifiedNs))
|
|
|
|
}
|
|
|
|
|
2016-07-04 10:40:29 +00:00
|
|
|
// WinsConflict returns true if "f" is the one to choose when it is in
|
|
|
|
// conflict with "other".
|
|
|
|
func (f FileInfo) WinsConflict(other FileInfo) bool {
|
|
|
|
// If a modification is in conflict with a delete, we pick the
|
|
|
|
// modification.
|
|
|
|
if !f.IsDeleted() && other.IsDeleted() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if f.IsDeleted() && !other.IsDeleted() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// The one with the newer modification time wins.
|
2016-08-06 13:05:59 +00:00
|
|
|
if f.ModTime().After(other.ModTime()) {
|
2016-07-04 10:40:29 +00:00
|
|
|
return true
|
|
|
|
}
|
2016-08-06 13:05:59 +00:00
|
|
|
if f.ModTime().Before(other.ModTime()) {
|
2016-07-04 10:40:29 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// The modification times were equal. Use the device ID in the version
|
|
|
|
// vector as tie breaker.
|
|
|
|
return f.Version.Compare(other.Version) == ConcurrentGreater
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b BlockInfo) String() string {
|
2016-12-14 23:30:29 +00:00
|
|
|
return fmt.Sprintf("Block{%d/%d/%d/%x}", b.Offset, b.Size, b.WeakHash, b.Hash)
|
2016-07-04 10:40:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsEmpty returns true if the block is a full block of zeroes.
|
|
|
|
func (b BlockInfo) IsEmpty() bool {
|
|
|
|
return b.Size == BlockSize && bytes.Equal(b.Hash, sha256OfEmptyBlock[:])
|
|
|
|
}
|
2016-07-23 12:46:31 +00:00
|
|
|
|
|
|
|
type IndexID uint64
|
|
|
|
|
|
|
|
func (i IndexID) String() string {
|
|
|
|
return fmt.Sprintf("0x%16X", uint64(i))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i IndexID) Marshal() ([]byte, error) {
|
|
|
|
bs := make([]byte, 8)
|
|
|
|
binary.BigEndian.PutUint64(bs, uint64(i))
|
|
|
|
return bs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *IndexID) Unmarshal(bs []byte) error {
|
|
|
|
if len(bs) != 8 {
|
|
|
|
return errors.New("incorrect IndexID length")
|
|
|
|
}
|
|
|
|
*i = IndexID(binary.BigEndian.Uint64(bs))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewIndexID() IndexID {
|
|
|
|
return IndexID(rand.Int64())
|
|
|
|
}
|
2016-11-22 07:36:14 +00:00
|
|
|
|
|
|
|
func (f Folder) Description() string {
|
|
|
|
// used by logging stuff
|
2016-12-19 09:12:06 +00:00
|
|
|
if f.Label == "" {
|
|
|
|
return f.ID
|
|
|
|
}
|
2016-11-22 07:36:14 +00:00
|
|
|
return fmt.Sprintf("%q (%s)", f.Label, f.ID)
|
|
|
|
}
|