lib/protocol, lib/model: Implement high precision time stamps (fixes #3305)

This adds a new nanoseconds field to the FileInfo, populates it during
scans and sets the non-truncated time in Chtimes calls.

The actual file modification time is defined as modified_s seconds +
modified_ns nanoseconds. It's expected that the modified_ns field is <=
1e9 (that is, all whole seconds should go in the modified_s field) but
not really enforced. Given that it's an int32 the timestamp can be
adjusted += ~2.9 seconds by the modified_ns field...

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3431
This commit is contained in:
Jakob Borg 2016-08-06 13:05:59 +00:00 committed by Audrius Butkevicius
parent 0655991a19
commit ea87bcefd6
21 changed files with 321 additions and 240 deletions

View File

@ -40,7 +40,8 @@ func main() {
log.Println("Lstat:") log.Println("Lstat:")
log.Printf(" Size: %d bytes", fi.Size()) log.Printf(" Size: %d bytes", fi.Size())
log.Printf(" Mode: 0%o", fi.Mode()) log.Printf(" Mode: 0%o", fi.Mode())
log.Printf(" Time: %v (%d)", fi.ModTime(), fi.ModTime().Unix()) log.Printf(" Time: %v", fi.ModTime())
log.Printf(" %d.%09d", fi.ModTime().Unix(), fi.ModTime().Nanosecond())
log.Println() log.Println()
if !fi.Mode().IsDir() && !fi.Mode().IsRegular() { if !fi.Mode().IsDir() && !fi.Mode().IsRegular() {
@ -52,7 +53,8 @@ func main() {
log.Println("Stat:") log.Println("Stat:")
log.Printf(" Size: %d bytes", fi.Size()) log.Printf(" Size: %d bytes", fi.Size())
log.Printf(" Mode: 0%o", fi.Mode()) log.Printf(" Mode: 0%o", fi.Mode())
log.Printf(" Time: %v (%d)", fi.ModTime(), fi.ModTime().Unix()) log.Printf(" Time: %v", fi.ModTime())
log.Printf(" %d.%09d", fi.ModTime().Unix(), fi.ModTime().Nanosecond())
log.Println() log.Println()
} }

View File

@ -10,6 +10,7 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"log" "log"
"time"
"github.com/syncthing/syncthing/lib/db" "github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/protocol"
@ -53,7 +54,13 @@ func dump(ldb *db.Instance) {
fmt.Printf("[fstat] K:%x V:%x\n", it.Key(), it.Value()) fmt.Printf("[fstat] K:%x V:%x\n", it.Key(), it.Value())
case db.KeyTypeVirtualMtime: case db.KeyTypeVirtualMtime:
fmt.Printf("[mtime] K:%x V:%x\n", it.Key(), it.Value()) folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
val := it.Value()
var real, virt time.Time
real.UnmarshalBinary(val[:len(val)/2])
virt.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, real, virt)
case db.KeyTypeFolderIdx: case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(it.Key()[1:]) key := binary.BigEndian.Uint32(it.Key()[1:])

View File

@ -1233,7 +1233,7 @@ func (f jsonFileInfo) MarshalJSON() ([]byte, error) {
"deleted": f.Deleted, "deleted": f.Deleted,
"invalid": f.Invalid, "invalid": f.Invalid,
"noPermissions": f.NoPermissions, "noPermissions": f.NoPermissions,
"modified": time.Unix(f.Modified, 0), "modified": protocol.FileInfo(f).ModTime(),
"sequence": f.Sequence, "sequence": f.Sequence,
"numBlocks": len(f.Blocks), "numBlocks": len(f.Blocks),
"version": jsonVersionVector(f.Version), "version": jsonVersionVector(f.Version),
@ -1251,7 +1251,7 @@ func (f jsonDBFileInfo) MarshalJSON() ([]byte, error) {
"deleted": f.Deleted, "deleted": f.Deleted,
"invalid": f.Invalid, "invalid": f.Invalid,
"noPermissions": f.NoPermissions, "noPermissions": f.NoPermissions,
"modified": time.Unix(f.Modified, 0), "modified": db.FileInfoTruncated(f).ModTime(),
"sequence": f.Sequence, "sequence": f.Sequence,
}) })
} }

View File

@ -11,13 +11,14 @@ package db
import ( import (
"fmt" "fmt"
"time"
"github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/protocol"
) )
func (f FileInfoTruncated) String() string { func (f FileInfoTruncated) String() string {
return fmt.Sprintf("File{Name:%q, Permissions:0%o, Modified:%d, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v}", return fmt.Sprintf("File{Name:%q, Permissions:0%o, Modified:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v}",
f.Name, f.Permissions, f.Modified, f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions) f.Name, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions)
} }
func (f FileInfoTruncated) IsDeleted() bool { func (f FileInfoTruncated) IsDeleted() bool {
@ -55,3 +56,7 @@ func (f FileInfoTruncated) FileSize() int64 {
func (f FileInfoTruncated) FileName() string { func (f FileInfoTruncated) FileName() string {
return f.Name return f.Name
} }
func (f FileInfoTruncated) ModTime() time.Time {
return time.Unix(f.ModifiedS, int64(f.ModifiedNs))
}

View File

@ -56,7 +56,8 @@ type FileInfoTruncated struct {
Type protocol.FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type,omitempty"` Type protocol.FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"` Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
Modified int64 `protobuf:"varint,5,opt,name=modified,proto3" json:"modified,omitempty"` ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"` Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"`
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
@ -171,10 +172,10 @@ func (m *FileInfoTruncated) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintStructs(data, i, uint64(m.Permissions)) i = encodeVarintStructs(data, i, uint64(m.Permissions))
} }
if m.Modified != 0 { if m.ModifiedS != 0 {
data[i] = 0x28 data[i] = 0x28
i++ i++
i = encodeVarintStructs(data, i, uint64(m.Modified)) i = encodeVarintStructs(data, i, uint64(m.ModifiedS))
} }
if m.Deleted { if m.Deleted {
data[i] = 0x30 data[i] = 0x30
@ -219,6 +220,11 @@ func (m *FileInfoTruncated) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintStructs(data, i, uint64(m.Sequence)) i = encodeVarintStructs(data, i, uint64(m.Sequence))
} }
if m.ModifiedNs != 0 {
data[i] = 0x58
i++
i = encodeVarintStructs(data, i, uint64(m.ModifiedNs))
}
return i, nil return i, nil
} }
@ -289,8 +295,8 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
if m.Permissions != 0 { if m.Permissions != 0 {
n += 1 + sovStructs(uint64(m.Permissions)) n += 1 + sovStructs(uint64(m.Permissions))
} }
if m.Modified != 0 { if m.ModifiedS != 0 {
n += 1 + sovStructs(uint64(m.Modified)) n += 1 + sovStructs(uint64(m.ModifiedS))
} }
if m.Deleted { if m.Deleted {
n += 2 n += 2
@ -306,6 +312,9 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
if m.Sequence != 0 { if m.Sequence != 0 {
n += 1 + sovStructs(uint64(m.Sequence)) n += 1 + sovStructs(uint64(m.Sequence))
} }
if m.ModifiedNs != 0 {
n += 1 + sovStructs(uint64(m.ModifiedNs))
}
return n return n
} }
@ -631,9 +640,9 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
} }
case 5: case 5:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Modified", wireType) return fmt.Errorf("proto: wrong wireType = %d for field ModifiedS", wireType)
} }
m.Modified = 0 m.ModifiedS = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowStructs return ErrIntOverflowStructs
@ -643,7 +652,7 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
} }
b := data[iNdEx] b := data[iNdEx]
iNdEx++ iNdEx++
m.Modified |= (int64(b) & 0x7F) << shift m.ModifiedS |= (int64(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
@ -757,6 +766,25 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
break break
} }
} }
case 11:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ModifiedNs", wireType)
}
m.ModifiedNs = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.ModifiedNs |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipStructs(data[iNdEx:]) skippy, err := skipStructs(data[iNdEx:])
@ -884,30 +912,32 @@ var (
) )
var fileDescriptorStructs = []byte{ var fileDescriptorStructs = []byte{
// 400 bytes of a gzipped FileDescriptorProto // 419 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0x4d, 0x6b, 0xe2, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0xcd, 0xaa, 0xd3, 0x40,
0x18, 0x4e, 0x34, 0xab, 0x71, 0xb2, 0xba, 0xbb, 0xc3, 0x22, 0xc1, 0x43, 0x14, 0x61, 0x61, 0x59, 0x18, 0x4d, 0xda, 0xdc, 0x36, 0xfd, 0x62, 0xaf, 0x3a, 0xc8, 0x25, 0x14, 0x4c, 0x2f, 0x05, 0x41,
0xd8, 0xb8, 0xeb, 0xb2, 0x97, 0x1e, 0x3d, 0x08, 0x85, 0x1e, 0x4a, 0x28, 0xf6, 0x58, 0x4c, 0x66, 0x04, 0x53, 0xbd, 0xe2, 0xc6, 0x65, 0x17, 0x05, 0x41, 0x44, 0x46, 0xa9, 0xcb, 0xd2, 0x64, 0xa6,
0x8c, 0x03, 0xc9, 0x4c, 0x9a, 0x99, 0x08, 0xf6, 0x97, 0xf4, 0xe8, 0xcf, 0xf1, 0xd8, 0x43, 0xcf, 0xe9, 0x40, 0x32, 0x13, 0x33, 0x93, 0x42, 0x7d, 0x12, 0x97, 0x7d, 0x9c, 0x2e, 0x7d, 0x02, 0xd1,
0xa5, 0xb5, 0x7f, 0xa4, 0xe3, 0x4c, 0x62, 0x73, 0xec, 0x21, 0xf0, 0x3e, 0x79, 0x3e, 0xde, 0x87, 0xfa, 0x12, 0x2e, 0x9d, 0x4e, 0x7e, 0xcc, 0xd2, 0x45, 0xe0, 0x3b, 0x73, 0xce, 0xf9, 0xce, 0x99,
0x79, 0x41, 0x97, 0x8b, 0xbc, 0x88, 0x04, 0xf7, 0xb3, 0x9c, 0x09, 0x06, 0x1b, 0x28, 0x1c, 0xfc, 0x0c, 0x8c, 0xa5, 0x2a, 0xca, 0x58, 0xc9, 0x30, 0x2f, 0x84, 0x12, 0xa8, 0x47, 0xa2, 0xc9, 0xf3,
0x8e, 0x89, 0x58, 0x17, 0xa1, 0x1f, 0xb1, 0x74, 0x12, 0xb3, 0x98, 0x4d, 0x14, 0x15, 0x16, 0x2b, 0x84, 0xa9, 0x5d, 0x19, 0x85, 0xb1, 0xc8, 0xe6, 0x89, 0x48, 0xc4, 0xdc, 0x50, 0x51, 0xb9, 0x35,
0x85, 0x14, 0x50, 0x93, 0xb6, 0x0c, 0xfe, 0xd7, 0xe4, 0x7c, 0x4b, 0x23, 0xb1, 0x26, 0x34, 0xae, 0xc8, 0x00, 0x33, 0x55, 0x96, 0xc9, 0xeb, 0x8e, 0x5c, 0x1e, 0x78, 0xac, 0x76, 0x8c, 0x27, 0x9d,
0x4d, 0x09, 0x09, 0x75, 0x42, 0xc4, 0x92, 0x49, 0x88, 0x33, 0x6d, 0x1b, 0x5f, 0x03, 0x67, 0x4e, 0x29, 0x65, 0x51, 0xb5, 0x21, 0x16, 0xe9, 0x3c, 0xa2, 0x79, 0x65, 0x9b, 0x7d, 0x06, 0x6f, 0xc9,
0x12, 0xbc, 0xc0, 0x39, 0x27, 0x8c, 0xc2, 0x3f, 0xa0, 0xbd, 0xd1, 0xa3, 0x6b, 0x8e, 0xcc, 0x9f, 0x52, 0xba, 0xa2, 0x85, 0x64, 0x82, 0xa3, 0x17, 0x30, 0xdc, 0x57, 0xa3, 0x6f, 0xdf, 0xda, 0x4f,
0xce, 0xf4, 0xab, 0x5f, 0x99, 0xfc, 0x05, 0x8e, 0x04, 0xcb, 0x67, 0xd6, 0xfe, 0x69, 0x68, 0x04, 0xbd, 0xbb, 0x07, 0x61, 0x63, 0x0a, 0x57, 0x34, 0x56, 0xa2, 0x58, 0x38, 0xa7, 0x1f, 0x53, 0x0b,
0x95, 0x0c, 0xf6, 0x41, 0x0b, 0xe1, 0x0d, 0x89, 0xb0, 0xdb, 0x90, 0x86, 0xcf, 0x41, 0x89, 0xc6, 0x37, 0x32, 0x74, 0x03, 0x03, 0x42, 0xf7, 0x2c, 0xa6, 0x7e, 0x4f, 0x1b, 0xee, 0xe1, 0x1a, 0xcd,
0x73, 0xe0, 0x94, 0xa1, 0x17, 0x84, 0x0b, 0xf8, 0x17, 0xd8, 0xa5, 0x83, 0xcb, 0xe4, 0xa6, 0x4c, 0x96, 0xe0, 0xd5, 0x4b, 0xdf, 0x31, 0xa9, 0xd0, 0x4b, 0x70, 0x6b, 0x87, 0xd4, 0x9b, 0xfb, 0x7a,
0xfe, 0xe2, 0xa3, 0xd0, 0xaf, 0xed, 0x2e, 0x83, 0x4f, 0xb2, 0x33, 0xeb, 0x7e, 0x37, 0x34, 0xc6, 0xf3, 0xfd, 0x90, 0x44, 0x61, 0x27, 0xbb, 0x5e, 0xdc, 0xca, 0xde, 0x38, 0xdf, 0x8e, 0x53, 0x6b,
0x8f, 0x0d, 0xf0, 0xed, 0xa8, 0x3a, 0xa7, 0x2b, 0x76, 0x95, 0x17, 0x34, 0x5a, 0x0a, 0x8c, 0x20, 0xf6, 0xa7, 0x07, 0x0f, 0x2f, 0xaa, 0xb7, 0x7c, 0x2b, 0x3e, 0x15, 0x25, 0x8f, 0x37, 0x8a, 0x12,
0x04, 0x16, 0x5d, 0xa6, 0x58, 0x95, 0xec, 0x04, 0x6a, 0x86, 0xbf, 0x80, 0x25, 0xb6, 0x99, 0xee, 0x84, 0xc0, 0xe1, 0x9b, 0x8c, 0x9a, 0x92, 0x23, 0x6c, 0x66, 0xf4, 0x0c, 0x1c, 0x75, 0xc8, 0xab,
0xd1, 0x9b, 0xf6, 0xdf, 0x8b, 0x9f, 0xec, 0x92, 0x0d, 0x94, 0xe6, 0xe8, 0xe7, 0xe4, 0x0e, 0xbb, 0x1e, 0xd7, 0x77, 0x37, 0xff, 0x8a, 0xb7, 0x76, 0xcd, 0x62, 0xa3, 0xb9, 0xf8, 0x25, 0xfb, 0x4a,
0x4d, 0xa9, 0x6d, 0x06, 0x6a, 0x86, 0x23, 0xe0, 0x64, 0x38, 0x4f, 0x09, 0xd7, 0x2d, 0x2d, 0x49, 0xfd, 0xbe, 0xd6, 0xf6, 0xb1, 0x99, 0xd1, 0x2d, 0x78, 0x39, 0x2d, 0x32, 0x26, 0xab, 0x96, 0x8e,
0x75, 0x83, 0xfa, 0x2f, 0x38, 0x00, 0x76, 0xca, 0x10, 0x59, 0x11, 0x8c, 0xdc, 0x4f, 0xca, 0x79, 0xa6, 0xc6, 0xb8, 0x7b, 0x84, 0x1e, 0x03, 0x64, 0x82, 0xb0, 0x2d, 0xa3, 0x64, 0x2d, 0xfd, 0x2b,
0xc2, 0xd0, 0x05, 0x6d, 0x84, 0x13, 0x2c, 0xcb, 0xb9, 0x2d, 0x49, 0xd9, 0x41, 0x05, 0x8f, 0x0c, 0xe3, 0x1d, 0x35, 0x27, 0x1f, 0x91, 0x0f, 0x43, 0x42, 0x53, 0xaa, 0xfb, 0xf9, 0x03, 0xcd, 0xb9,
0xa1, 0x9b, 0x65, 0x42, 0x90, 0xdb, 0xd6, 0x4c, 0x09, 0xe1, 0x0f, 0xd0, 0xa3, 0xec, 0xa6, 0xbe, 0xb8, 0x81, 0x17, 0x86, 0xf1, 0xfd, 0x26, 0x65, 0xc4, 0x1f, 0x56, 0x4c, 0x0d, 0xd1, 0x13, 0xb8,
0xd4, 0x56, 0x82, 0x2e, 0x65, 0x97, 0xb5, 0xb5, 0xb5, 0xa3, 0x74, 0x3e, 0x76, 0x14, 0x59, 0x94, 0xe6, 0x62, 0xdd, 0xcd, 0x75, 0x8d, 0x60, 0xcc, 0xc5, 0x87, 0x4e, 0x72, 0xe7, 0x5d, 0x46, 0xff,
0xe3, 0xdb, 0x02, 0x53, 0x79, 0x16, 0xa0, 0x8b, 0x56, 0x58, 0x3f, 0xeb, 0xec, 0xfb, 0xfe, 0xc5, 0xf7, 0x2e, 0x13, 0x70, 0x25, 0xfd, 0x52, 0x52, 0xae, 0x5f, 0x06, 0x4c, 0xd3, 0x16, 0xa3, 0x29,
0x33, 0xf6, 0x07, 0xcf, 0x7c, 0x90, 0xdf, 0xf3, 0xc1, 0x33, 0x76, 0xaf, 0x9e, 0x19, 0xb6, 0x54, 0x78, 0xed, 0x3d, 0x74, 0xa2, 0xa7, 0xe9, 0x2b, 0xdc, 0x5e, 0xed, 0x7d, 0xfd, 0xeb, 0x17, 0x8f,
0xee, 0xbf, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xb3, 0x6f, 0x36, 0x8f, 0x02, 0x00, 0x00, 0x4e, 0xbf, 0x02, 0xeb, 0x74, 0x0e, 0xec, 0xef, 0xfa, 0xfb, 0x79, 0x0e, 0xac, 0xe3, 0xef, 0xc0,
0x8e, 0x06, 0x26, 0xf8, 0xd5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xae, 0x24, 0x77, 0xb3,
0x02, 0x00, 0x00,
} }

View File

@ -26,7 +26,8 @@ message FileInfoTruncated {
protocol.FileInfoType type = 2; protocol.FileInfoType type = 2;
int64 size = 3; int64 size = 3;
uint32 permissions = 4; uint32 permissions = 4;
int64 modified = 5; int64 modified_s = 5;
int32 modified_ns = 11;
bool deleted = 6; bool deleted = 6;
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;

View File

@ -4,9 +4,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file, // License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/. // You can obtain one at http://mozilla.org/MPL/2.0/.
//go:generate go run ../../script/protofmt.go mtime.proto
//go:generate protoc --proto_name=../../../../../:../../../../gogo/protobuf/protobuf:. --gogofast_out=. mtime.proto
package fs package fs
import ( import (

View File

@ -1658,7 +1658,8 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error
Name: f.Name, Name: f.Name,
Type: f.Type, Type: f.Type,
Size: f.Size, Size: f.Size,
Modified: f.Modified, ModifiedS: f.ModifiedS,
ModifiedNs: f.ModifiedNs,
Permissions: f.Permissions, Permissions: f.Permissions,
NoPermissions: f.NoPermissions, NoPermissions: f.NoPermissions,
Invalid: true, Invalid: true,
@ -1676,12 +1677,13 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error
// directory") when we try to Lstat() them. // directory") when we try to Lstat() them.
nf := protocol.FileInfo{ nf := protocol.FileInfo{
Name: f.Name, Name: f.Name,
Type: f.Type, Type: f.Type,
Size: f.Size, Size: f.Size,
Modified: f.Modified, ModifiedS: f.ModifiedS,
Deleted: true, ModifiedNs: f.ModifiedNs,
Version: f.Version.Update(m.shortID), Deleted: true,
Version: f.Version.Update(m.shortID),
} }
batch = append(batch, nf) batch = append(batch, nf)
@ -1948,7 +1950,7 @@ func (m *Model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly
if !dirsonly && base != "" { if !dirsonly && base != "" {
last[base] = []interface{}{ last[base] = []interface{}{
time.Unix(f.Modified, 0), f.FileSize(), f.ModTime(), f.FileSize(),
} }
} }

View File

@ -54,22 +54,22 @@ func init() {
var testDataExpected = map[string]protocol.FileInfo{ var testDataExpected = map[string]protocol.FileInfo{
"foo": { "foo": {
Name: "foo", Name: "foo",
Type: protocol.FileInfoTypeFile, Type: protocol.FileInfoTypeFile,
Modified: 0, ModifiedS: 0,
Blocks: []protocol.BlockInfo{{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: []protocol.BlockInfo{{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": { "empty": {
Name: "empty", Name: "empty",
Type: protocol.FileInfoTypeFile, Type: protocol.FileInfoTypeFile,
Modified: 0, ModifiedS: 0,
Blocks: []protocol.BlockInfo{{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: []protocol.BlockInfo{{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": { "bar": {
Name: "bar", Name: "bar",
Type: protocol.FileInfoTypeFile, Type: protocol.FileInfoTypeFile,
Modified: 0, ModifiedS: 0,
Blocks: []protocol.BlockInfo{{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: []protocol.BlockInfo{{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}}},
}, },
} }
@ -78,7 +78,7 @@ func init() {
for n, f := range testDataExpected { for n, f := range testDataExpected {
fi, _ := os.Stat("testdata/" + n) fi, _ := os.Stat("testdata/" + n)
f.Permissions = uint32(fi.Mode()) f.Permissions = uint32(fi.Mode())
f.Modified = fi.ModTime().Unix() f.ModifiedS = fi.ModTime().Unix()
f.Size = fi.Size() f.Size = fi.Size()
testDataExpected[n] = f testDataExpected[n] = f
} }
@ -144,9 +144,9 @@ func genFiles(n int) []protocol.FileInfo {
t := time.Now().Unix() t := time.Now().Unix()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
files[i] = protocol.FileInfo{ files[i] = protocol.FileInfo{
Name: fmt.Sprintf("file%d", i), Name: fmt.Sprintf("file%d", i),
Modified: t, ModifiedS: t,
Blocks: []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}}, Blocks: []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}},
} }
} }
@ -284,9 +284,9 @@ func BenchmarkRequest(b *testing.B) {
t := time.Now().Unix() t := time.Now().Unix()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
files[i] = protocol.FileInfo{ files[i] = protocol.FileInfo{
Name: fmt.Sprintf("file%d", i), Name: fmt.Sprintf("file%d", i),
Modified: t, ModifiedS: t,
Blocks: []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}}, Blocks: []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}},
} }
} }
@ -755,11 +755,11 @@ func TestGlobalDirectoryTree(t *testing.T) {
blocks = []protocol.BlockInfo{{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 = []protocol.BlockInfo{{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}}}
} }
return protocol.FileInfo{ return protocol.FileInfo{
Name: filepath.Join(path...), Name: filepath.Join(path...),
Type: typ, Type: typ,
Modified: 0x666, ModifiedS: 0x666,
Blocks: blocks, Blocks: blocks,
Size: 0xa, Size: 0xa,
} }
} }
@ -1006,11 +1006,11 @@ func TestGlobalDirectorySelfFixing(t *testing.T) {
blocks = []protocol.BlockInfo{{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 = []protocol.BlockInfo{{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}}}
} }
return protocol.FileInfo{ return protocol.FileInfo{
Name: filepath.Join(path...), Name: filepath.Join(path...),
Type: typ, Type: typ,
Modified: 0x666, ModifiedS: 0x666,
Blocks: blocks, Blocks: blocks,
Size: 0xa, Size: 0xa,
} }
} }
@ -1148,7 +1148,7 @@ func genDeepFiles(n, d int) []protocol.FileInfo {
i++ i++
} }
files[i].Modified = t files[i].ModifiedS = t
files[i].Blocks = []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}} files[i].Blocks = []protocol.BlockInfo{{Offset: 0, Size: 100, Hash: []byte("some hash bytes")}}
} }

View File

@ -9,6 +9,7 @@ package model
import ( import (
"math/rand" "math/rand"
"sort" "sort"
"time"
"github.com/syncthing/syncthing/lib/sync" "github.com/syncthing/syncthing/lib/sync"
) )
@ -22,7 +23,7 @@ type jobQueue struct {
type jobQueueEntry struct { type jobQueueEntry struct {
name string name string
size int64 size int64
modified int64 modified time.Time
} }
func newJobQueue() *jobQueue { func newJobQueue() *jobQueue {
@ -31,7 +32,7 @@ func newJobQueue() *jobQueue {
} }
} }
func (q *jobQueue) Push(file string, size, modified int64) { func (q *jobQueue) Push(file string, size int64, modified time.Time) {
q.mut.Lock() q.mut.Lock()
q.queued = append(q.queued, jobQueueEntry{file, size, modified}) q.queued = append(q.queued, jobQueueEntry{file, size, modified})
q.mut.Unlock() q.mut.Unlock()
@ -160,5 +161,5 @@ func (q smallestFirst) Swap(a, b int) { q[a], q[b] = q[b], q[a] }
type oldestFirst []jobQueueEntry type oldestFirst []jobQueueEntry
func (q oldestFirst) Len() int { return len(q) } func (q oldestFirst) Len() int { return len(q) }
func (q oldestFirst) Less(a, b int) bool { return q[a].modified < q[b].modified } func (q oldestFirst) Less(a, b int) bool { return q[a].modified.Before(q[b].modified) }
func (q oldestFirst) Swap(a, b int) { q[a], q[b] = q[b], q[a] } func (q oldestFirst) Swap(a, b int) { q[a], q[b] = q[b], q[a] }

View File

@ -9,6 +9,7 @@ package model
import ( import (
"fmt" "fmt"
"testing" "testing"
"time"
"github.com/d4l3k/messagediff" "github.com/d4l3k/messagediff"
) )
@ -16,10 +17,10 @@ import (
func TestJobQueue(t *testing.T) { func TestJobQueue(t *testing.T) {
// Some random actions // Some random actions
q := newJobQueue() q := newJobQueue()
q.Push("f1", 0, 0) q.Push("f1", 0, time.Time{})
q.Push("f2", 0, 0) q.Push("f2", 0, time.Time{})
q.Push("f3", 0, 0) q.Push("f3", 0, time.Time{})
q.Push("f4", 0, 0) q.Push("f4", 0, time.Time{})
progress, queued := q.Jobs() progress, queued := q.Jobs()
if len(progress) != 0 || len(queued) != 4 { if len(progress) != 0 || len(queued) != 4 {
@ -44,7 +45,7 @@ func TestJobQueue(t *testing.T) {
t.Fatal("Wrong length", len(progress), len(queued)) t.Fatal("Wrong length", len(progress), len(queued))
} }
q.Push(n, 0, 0) q.Push(n, 0, time.Time{})
progress, queued = q.Jobs() progress, queued = q.Jobs()
if len(progress) != 0 || len(queued) != 4 { if len(progress) != 0 || len(queued) != 4 {
t.Fatal("Wrong length") t.Fatal("Wrong length")
@ -121,10 +122,10 @@ func TestJobQueue(t *testing.T) {
func TestBringToFront(t *testing.T) { func TestBringToFront(t *testing.T) {
q := newJobQueue() q := newJobQueue()
q.Push("f1", 0, 0) q.Push("f1", 0, time.Time{})
q.Push("f2", 0, 0) q.Push("f2", 0, time.Time{})
q.Push("f3", 0, 0) q.Push("f3", 0, time.Time{})
q.Push("f4", 0, 0) q.Push("f4", 0, time.Time{})
_, queued := q.Jobs() _, queued := q.Jobs()
if diff, equal := messagediff.PrettyDiff([]string{"f1", "f2", "f3", "f4"}, queued); !equal { if diff, equal := messagediff.PrettyDiff([]string{"f1", "f2", "f3", "f4"}, queued); !equal {
@ -162,10 +163,10 @@ func TestBringToFront(t *testing.T) {
func TestShuffle(t *testing.T) { func TestShuffle(t *testing.T) {
q := newJobQueue() q := newJobQueue()
q.Push("f1", 0, 0) q.Push("f1", 0, time.Time{})
q.Push("f2", 0, 0) q.Push("f2", 0, time.Time{})
q.Push("f3", 0, 0) q.Push("f3", 0, time.Time{})
q.Push("f4", 0, 0) q.Push("f4", 0, time.Time{})
// This test will fail once in eight million times (1 / (4!)^5) :) // This test will fail once in eight million times (1 / (4!)^5) :)
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
@ -187,10 +188,10 @@ func TestShuffle(t *testing.T) {
func TestSortBySize(t *testing.T) { func TestSortBySize(t *testing.T) {
q := newJobQueue() q := newJobQueue()
q.Push("f1", 20, 0) q.Push("f1", 20, time.Time{})
q.Push("f2", 40, 0) q.Push("f2", 40, time.Time{})
q.Push("f3", 30, 0) q.Push("f3", 30, time.Time{})
q.Push("f4", 10, 0) q.Push("f4", 10, time.Time{})
q.SortSmallestFirst() q.SortSmallestFirst()
@ -219,10 +220,10 @@ func TestSortBySize(t *testing.T) {
func TestSortByAge(t *testing.T) { func TestSortByAge(t *testing.T) {
q := newJobQueue() q := newJobQueue()
q.Push("f1", 0, 20) q.Push("f1", 0, time.Unix(20, 0))
q.Push("f2", 0, 40) q.Push("f2", 0, time.Unix(40, 0))
q.Push("f3", 0, 30) q.Push("f3", 0, time.Unix(30, 0))
q.Push("f4", 0, 10) q.Push("f4", 0, time.Unix(10, 0))
q.SortOldestFirst() q.SortOldestFirst()
@ -254,7 +255,7 @@ func BenchmarkJobQueueBump(b *testing.B) {
q := newJobQueue() q := newJobQueue()
for _, f := range files { for _, f := range files {
q.Push(f.Name, 0, 0) q.Push(f.Name, 0, time.Time{})
} }
b.ResetTimer() b.ResetTimer()
@ -270,7 +271,7 @@ func BenchmarkJobQueuePushPopDone10k(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
q := newJobQueue() q := newJobQueue()
for _, f := range files { for _, f := range files {
q.Push(f.Name, 0, 0) q.Push(f.Name, 0, time.Time{})
} }
for _ = range files { for _ = range files {
n, _ := q.Pop() n, _ := q.Pop()

View File

@ -449,7 +449,7 @@ func (f *rwFolder) pullerIteration(ignores *ignore.Matcher) int {
devices := folderFiles.Availability(file.Name) devices := folderFiles.Availability(file.Name)
for _, dev := range devices { for _, dev := range devices {
if f.model.ConnectedTo(dev) { if f.model.ConnectedTo(dev) {
f.queue.Push(file.Name, file.Size, file.Modified) f.queue.Push(file.Name, file.Size, file.ModTime())
changed++ changed++
break break
} }
@ -925,7 +925,7 @@ func (f *rwFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocks
// changes that we don't know about yet and we should scan before // changes that we don't know about yet and we should scan before
// touching the file. If we can't stat the file we'll just pull it. // touching the file. If we can't stat the file we'll just pull it.
if info, err := f.mtimeFS.Lstat(realName); err == nil { if info, err := f.mtimeFS.Lstat(realName); err == nil {
if info.ModTime().Unix() != curFile.Modified || info.Size() != curFile.Size { if !info.ModTime().Equal(curFile.ModTime()) || info.Size() != curFile.Size {
l.Debugln("file modified but not rescanned; not pulling:", realName) l.Debugln("file modified but not rescanned; not pulling:", realName)
// Scan() is synchronous (i.e. blocks until the scan is // Scan() is synchronous (i.e. blocks until the scan is
// completed and returns an error), but a scan can't happen // completed and returns an error), but a scan can't happen
@ -1044,8 +1044,7 @@ func (f *rwFolder) shortcutFile(file protocol.FileInfo) error {
} }
} }
t := time.Unix(file.Modified, 0) f.mtimeFS.Chtimes(realName, file.ModTime(), file.ModTime()) // never fails
f.mtimeFS.Chtimes(realName, t, t) // never fails
// This may have been a conflict. We should merge the version vectors so // This may have been a conflict. We should merge the version vectors so
// that our clock doesn't move backwards. // that our clock doesn't move backwards.
@ -1247,8 +1246,7 @@ func (f *rwFolder) performFinish(state *sharedPullerState) error {
} }
// Set the correct timestamp on the new file // Set the correct timestamp on the new file
t := time.Unix(state.file.Modified, 0) f.mtimeFS.Chtimes(state.tempName, state.file.ModTime(), state.file.ModTime()) // never fails
f.mtimeFS.Chtimes(state.tempName, t, t) // never fails
if stat, err := f.mtimeFS.Lstat(state.realName); err == nil { if stat, err := f.mtimeFS.Lstat(state.realName); err == nil {
// There is an old file or directory already in place. We need to // There is an old file or directory already in place. We need to

View File

@ -332,7 +332,7 @@ func TestDeregisterOnFailInCopy(t *testing.T) {
f := setUpRwFolder(m) f := setUpRwFolder(m)
// queue.Done should be called by the finisher routine // queue.Done should be called by the finisher routine
f.queue.Push("filex", 0, 0) f.queue.Push("filex", 0, time.Time{})
f.queue.Pop() f.queue.Pop()
if f.queue.lenProgress() != 1 { if f.queue.lenProgress() != 1 {
@ -405,7 +405,7 @@ func TestDeregisterOnFailInPull(t *testing.T) {
f := setUpRwFolder(m) f := setUpRwFolder(m)
// queue.Done should be called by the finisher routine // queue.Done should be called by the finisher routine
f.queue.Push("filex", 0, 0) f.queue.Push("filex", 0, time.Time{})
f.queue.Pop() f.queue.Pop()
if f.queue.lenProgress() != 1 { if f.queue.lenProgress() != 1 {

View File

@ -103,7 +103,8 @@ func addFiles(n int, s IndexSorter) {
Name: fmt.Sprintf("file-%d", rnd), Name: fmt.Sprintf("file-%d", rnd),
Size: rand.Int63(), Size: rand.Int63(),
Permissions: uint32(rand.Intn(0777)), Permissions: uint32(rand.Intn(0777)),
Modified: rand.Int63(), ModifiedS: rand.Int63(),
ModifiedNs: int32(rand.Int63()),
Sequence: rnd, Sequence: rnd,
Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: uint64(rand.Int63())}}}, Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: uint64(rand.Int63())}}},
Blocks: []protocol.BlockInfo{{ Blocks: []protocol.BlockInfo{{

View File

@ -295,7 +295,8 @@ type FileInfo struct {
Type FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type,omitempty"` Type FileInfoType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.FileInfoType" json:"type,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"` Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
Modified int64 `protobuf:"varint,5,opt,name=modified,proto3" json:"modified,omitempty"` ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"` Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"`
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
@ -789,10 +790,10 @@ func (m *FileInfo) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintBep(data, i, uint64(m.Permissions)) i = encodeVarintBep(data, i, uint64(m.Permissions))
} }
if m.Modified != 0 { if m.ModifiedS != 0 {
data[i] = 0x28 data[i] = 0x28
i++ i++
i = encodeVarintBep(data, i, uint64(m.Modified)) i = encodeVarintBep(data, i, uint64(m.ModifiedS))
} }
if m.Deleted { if m.Deleted {
data[i] = 0x30 data[i] = 0x30
@ -837,6 +838,11 @@ func (m *FileInfo) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintBep(data, i, uint64(m.Sequence)) i = encodeVarintBep(data, i, uint64(m.Sequence))
} }
if m.ModifiedNs != 0 {
data[i] = 0x58
i++
i = encodeVarintBep(data, i, uint64(m.ModifiedNs))
}
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, msg := range m.Blocks { for _, msg := range m.Blocks {
data[i] = 0x82 data[i] = 0x82
@ -1348,8 +1354,8 @@ func (m *FileInfo) ProtoSize() (n int) {
if m.Permissions != 0 { if m.Permissions != 0 {
n += 1 + sovBep(uint64(m.Permissions)) n += 1 + sovBep(uint64(m.Permissions))
} }
if m.Modified != 0 { if m.ModifiedS != 0 {
n += 1 + sovBep(uint64(m.Modified)) n += 1 + sovBep(uint64(m.ModifiedS))
} }
if m.Deleted { if m.Deleted {
n += 2 n += 2
@ -1365,6 +1371,9 @@ func (m *FileInfo) ProtoSize() (n int) {
if m.Sequence != 0 { if m.Sequence != 0 {
n += 1 + sovBep(uint64(m.Sequence)) n += 1 + sovBep(uint64(m.Sequence))
} }
if m.ModifiedNs != 0 {
n += 1 + sovBep(uint64(m.ModifiedNs))
}
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, e := range m.Blocks { for _, e := range m.Blocks {
l = e.ProtoSize() l = e.ProtoSize()
@ -2632,9 +2641,9 @@ func (m *FileInfo) Unmarshal(data []byte) error {
} }
case 5: case 5:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Modified", wireType) return fmt.Errorf("proto: wrong wireType = %d for field ModifiedS", wireType)
} }
m.Modified = 0 m.ModifiedS = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowBep return ErrIntOverflowBep
@ -2644,7 +2653,7 @@ func (m *FileInfo) Unmarshal(data []byte) error {
} }
b := data[iNdEx] b := data[iNdEx]
iNdEx++ iNdEx++
m.Modified |= (int64(b) & 0x7F) << shift m.ModifiedS |= (int64(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
@ -2758,6 +2767,25 @@ func (m *FileInfo) Unmarshal(data []byte) error {
break break
} }
} }
case 11:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ModifiedNs", wireType)
}
m.ModifiedNs = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBep
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.ModifiedNs |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 16: case 16:
if wireType != 2 { if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType)
@ -3926,104 +3954,105 @@ var (
) )
var fileDescriptorBep = []byte{ var fileDescriptorBep = []byte{
// 1569 bytes of a gzipped FileDescriptorProto // 1589 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0xdb, 0x46, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x6f, 0xdb, 0x46,
0x16, 0xb7, 0x24, 0x8a, 0x92, 0x46, 0xb2, 0x23, 0x4f, 0x1c, 0x47, 0xcb, 0x78, 0x6d, 0x2f, 0x93, 0x16, 0xb7, 0x24, 0xea, 0xdf, 0x48, 0x76, 0xe4, 0x89, 0xe3, 0x68, 0x19, 0xc7, 0xf6, 0x32, 0x09,
0x60, 0xbd, 0xc2, 0xc6, 0xd9, 0x4d, 0xda, 0x06, 0x28, 0xd0, 0x02, 0xb2, 0x44, 0x3b, 0x44, 0x64, 0xd6, 0x2b, 0x6c, 0x9c, 0xdd, 0x64, 0x77, 0x03, 0x14, 0x68, 0x01, 0x59, 0xa2, 0x1d, 0x21, 0x32,
0x4a, 0xa1, 0x24, 0xa7, 0xe9, 0xa1, 0x02, 0x25, 0x8e, 0x64, 0x22, 0x14, 0x47, 0x25, 0xa9, 0x24, 0xa5, 0x50, 0x92, 0xd3, 0xf4, 0x50, 0x41, 0x12, 0x47, 0x32, 0x11, 0x8a, 0xa3, 0x92, 0x54, 0x12,
0xee, 0x47, 0x68, 0xbf, 0x40, 0x2f, 0x05, 0x82, 0xde, 0x7a, 0xef, 0x87, 0xc8, 0x31, 0xc8, 0xb1, 0xf7, 0x23, 0xb4, 0x5f, 0xa0, 0x97, 0x02, 0x41, 0x6e, 0xbd, 0xf7, 0x43, 0xe4, 0x18, 0xe4, 0xd8,
0x87, 0xa0, 0x75, 0x2f, 0xfd, 0x02, 0xbd, 0x16, 0x7d, 0x9c, 0x21, 0x45, 0xca, 0x7f, 0x8a, 0x1c, 0x43, 0xd0, 0xba, 0x97, 0x7e, 0x81, 0xde, 0xfb, 0xf8, 0x86, 0x94, 0x28, 0xff, 0x29, 0x72, 0xe8,
0x7a, 0x10, 0x34, 0xf3, 0xde, 0x6f, 0xde, 0xcc, 0xfc, 0xde, 0xef, 0xbd, 0x21, 0x2a, 0x0c, 0xc8, 0xc1, 0xd0, 0xcc, 0x7b, 0xbf, 0x99, 0x37, 0xf3, 0x7b, 0xbf, 0xf7, 0x86, 0x26, 0xd9, 0x3e, 0x9b,
0x74, 0x77, 0xea, 0x52, 0x9f, 0xe2, 0x3c, 0xfb, 0x1b, 0x52, 0x5b, 0xba, 0x33, 0xb6, 0xfc, 0xe3, 0xec, 0x4e, 0x1c, 0xee, 0x71, 0x9a, 0xc1, 0x9f, 0x01, 0xb7, 0xe4, 0xbb, 0x23, 0xd3, 0x3b, 0x9e,
0xd9, 0x60, 0x77, 0x48, 0x27, 0x77, 0xc7, 0x74, 0x4c, 0xef, 0x32, 0xcf, 0x60, 0x36, 0x62, 0x33, 0xf6, 0x77, 0x07, 0x7c, 0x7c, 0x6f, 0xc4, 0x47, 0xfc, 0x1e, 0x7a, 0xfa, 0xd3, 0x21, 0xce, 0x70,
0x36, 0x61, 0x23, 0xbe, 0x50, 0x9e, 0xa2, 0xec, 0x43, 0x62, 0xdb, 0x14, 0x6f, 0xa1, 0xa2, 0x49, 0x82, 0x23, 0xb1, 0x50, 0x99, 0x90, 0xe4, 0x23, 0x66, 0x59, 0x9c, 0x6e, 0x91, 0x9c, 0xc1, 0x5e,
0x9e, 0x5b, 0x43, 0xd2, 0x77, 0x8c, 0x09, 0xa9, 0xa4, 0xb6, 0x53, 0x3b, 0x05, 0x1d, 0x71, 0x93, 0x98, 0x03, 0xd6, 0xb5, 0x7b, 0x63, 0x56, 0x8c, 0x6d, 0xc7, 0x76, 0xb2, 0x3a, 0x11, 0x26, 0x0d,
0x06, 0x96, 0x00, 0x30, 0xb4, 0x2d, 0xe2, 0xf8, 0x1c, 0x90, 0xe6, 0x00, 0x6e, 0x62, 0x80, 0xdb, 0x2c, 0x3e, 0x60, 0x60, 0x99, 0xcc, 0xf6, 0x04, 0x20, 0x2e, 0x00, 0xc2, 0x84, 0x80, 0x3b, 0x64,
0x68, 0x25, 0x04, 0x3c, 0x27, 0xae, 0x67, 0x51, 0xa7, 0x92, 0x61, 0x98, 0x65, 0x6e, 0x3d, 0xe2, 0x25, 0x00, 0xbc, 0x60, 0x8e, 0x6b, 0x72, 0xbb, 0x98, 0x40, 0xcc, 0xb2, 0xb0, 0x1e, 0x09, 0xa3,
0x46, 0xd9, 0x43, 0xe2, 0x43, 0x62, 0x98, 0xc4, 0xc5, 0xff, 0x41, 0x82, 0x7f, 0x32, 0xe5, 0x7b, 0xe2, 0x92, 0xd4, 0x23, 0xd6, 0x33, 0x98, 0x43, 0xff, 0x49, 0x24, 0xef, 0x64, 0x22, 0x62, 0xad,
0xad, 0xdc, 0xbb, 0xb6, 0x1b, 0xdd, 0x61, 0xf7, 0x90, 0x78, 0x9e, 0x31, 0x26, 0x5d, 0x70, 0xea, 0xdc, 0xbf, 0xb6, 0x1b, 0xde, 0x61, 0xf7, 0x90, 0xb9, 0x6e, 0x6f, 0xc4, 0xda, 0xe0, 0xd4, 0x11,
0x0c, 0x82, 0x3f, 0x85, 0xcd, 0xe9, 0x64, 0xea, 0x82, 0x23, 0x08, 0x9c, 0x66, 0x2b, 0x36, 0xce, 0x42, 0x3f, 0x83, 0xe0, 0x7c, 0x3c, 0x71, 0xc0, 0xe1, 0x6f, 0x1c, 0xc7, 0x15, 0x1b, 0xe7, 0x56,
0xad, 0xa8, 0xc7, 0x18, 0x3d, 0xb9, 0x40, 0xae, 0xa1, 0xe5, 0xba, 0x3d, 0xf3, 0x7c, 0xe2, 0xd6, 0x54, 0xe6, 0x18, 0x3d, 0xba, 0x40, 0x29, 0x93, 0xe5, 0x8a, 0x35, 0x75, 0x3d, 0xe6, 0x54, 0xb8,
0xa9, 0x33, 0xb2, 0xc6, 0xf8, 0x7f, 0x28, 0x37, 0xa2, 0x36, 0x9c, 0xc2, 0x83, 0xed, 0x33, 0x3b, 0x3d, 0x34, 0x47, 0xf4, 0xdf, 0x24, 0x3d, 0xe4, 0x16, 0x9c, 0xc2, 0x85, 0xf0, 0x89, 0x9d, 0xdc,
0xc5, 0x7b, 0xe5, 0x38, 0xd8, 0x3e, 0x73, 0xec, 0x09, 0xaf, 0xdf, 0x6d, 0x2d, 0xe9, 0x11, 0x4c, 0xfd, 0xc2, 0x7c, 0xb3, 0x7d, 0x74, 0xec, 0x49, 0x6f, 0x3f, 0x6c, 0x2d, 0xe9, 0x21, 0x4c, 0xf9,
0xfe, 0x26, 0x8d, 0x44, 0xee, 0xc1, 0xeb, 0x28, 0x6d, 0x99, 0x9c, 0xa2, 0x3d, 0xf1, 0xf4, 0xdd, 0x36, 0x4e, 0x52, 0xc2, 0x43, 0xd7, 0x49, 0xdc, 0x34, 0x04, 0x45, 0x7b, 0xa9, 0xd3, 0x0f, 0x5b,
0x56, 0x5a, 0x6d, 0xe8, 0x60, 0xc1, 0x6b, 0x28, 0x6b, 0x1b, 0x03, 0x62, 0x87, 0xe4, 0xf0, 0x09, 0xf1, 0x5a, 0x55, 0x07, 0x0b, 0x5d, 0x23, 0x49, 0xab, 0xd7, 0x67, 0x56, 0x40, 0x8e, 0x98, 0xd0,
0xbe, 0x81, 0x0a, 0x2e, 0x5c, 0xb8, 0x4f, 0x1d, 0xfb, 0x84, 0x51, 0x92, 0xd7, 0xf3, 0x81, 0xa1, 0x1b, 0x24, 0xeb, 0xc0, 0x85, 0xbb, 0xdc, 0xb6, 0x4e, 0x90, 0x92, 0x8c, 0x9e, 0xf1, 0x0d, 0x0d,
0x05, 0x73, 0x7c, 0x07, 0x61, 0x6b, 0xec, 0x50, 0x97, 0xf4, 0xa7, 0xc4, 0x9d, 0x58, 0xec, 0xb4, 0x98, 0xd3, 0xbb, 0x84, 0x9a, 0x23, 0x9b, 0x3b, 0xac, 0x3b, 0x61, 0xce, 0xd8, 0xc4, 0xd3, 0xba,
0x5e, 0x45, 0x60, 0xa8, 0x55, 0xee, 0x69, 0xc7, 0x0e, 0x7c, 0x13, 0x2d, 0x87, 0x70, 0x93, 0xd8, 0x45, 0x09, 0x51, 0xab, 0xc2, 0xd3, 0x9c, 0x3b, 0xe8, 0x2d, 0xb2, 0x1c, 0xc0, 0x0d, 0x66, 0x31,
0xc4, 0x27, 0x95, 0x2c, 0x43, 0x96, 0xb8, 0xb1, 0xc1, 0x6c, 0x70, 0xb7, 0x35, 0xd3, 0xf2, 0x8c, 0x8f, 0x15, 0x93, 0x88, 0xcc, 0x0b, 0x63, 0x15, 0x6d, 0x70, 0xb7, 0x35, 0xc3, 0x74, 0x7b, 0x7d,
0x81, 0x4d, 0xfa, 0x3e, 0x99, 0x4c, 0xfb, 0x96, 0x63, 0x92, 0x97, 0xc4, 0xab, 0x88, 0x0c, 0x8b, 0x8b, 0x75, 0x3d, 0x36, 0x9e, 0x74, 0x4d, 0xdb, 0x60, 0xaf, 0x98, 0x5b, 0x4c, 0x21, 0x96, 0x06,
0x43, 0x5f, 0x17, 0x5c, 0x2a, 0xf7, 0x04, 0x6c, 0xf0, 0x4c, 0x7b, 0x95, 0xf2, 0x59, 0x36, 0x1a, 0xbe, 0x36, 0xb8, 0x6a, 0xc2, 0xe3, 0xb3, 0x21, 0x32, 0xed, 0x16, 0x0b, 0x67, 0xd9, 0xa8, 0xa2,
0xcc, 0x11, 0xb1, 0x11, 0xc2, 0xe4, 0xef, 0x81, 0x0d, 0xee, 0x49, 0xb0, 0x51, 0x5a, 0x60, 0x03, 0x23, 0x64, 0x23, 0x80, 0x29, 0x6f, 0x80, 0x0d, 0xe1, 0x89, 0xb0, 0x91, 0x5f, 0x60, 0x83, 0x12,
0x23, 0x21, 0xa1, 0x14, 0x36, 0xc6, 0x1b, 0xa8, 0x60, 0x98, 0x66, 0x90, 0x15, 0xd8, 0x2a, 0x03, 0x29, 0xa2, 0x14, 0x1c, 0xd3, 0x0d, 0x92, 0xed, 0x19, 0x86, 0x9f, 0x15, 0x08, 0x95, 0x80, 0x50,
0x5b, 0x15, 0xf4, 0xd8, 0x80, 0x1f, 0x2c, 0x66, 0x59, 0x38, 0xab, 0x8b, 0xcb, 0xd2, 0x1b, 0x50, 0x59, 0x7d, 0x6e, 0xa0, 0x0f, 0x17, 0xb3, 0x2c, 0x9d, 0xd5, 0xc5, 0x65, 0xe9, 0xf5, 0x29, 0x1e,
0x3c, 0x24, 0x6e, 0xa8, 0xcc, 0x2c, 0xdb, 0x2f, 0x1f, 0x18, 0x98, 0x2e, 0xff, 0x85, 0x4a, 0x13, 0x30, 0x27, 0x50, 0x66, 0x12, 0xe3, 0x65, 0x7c, 0x03, 0xea, 0xf2, 0xef, 0x24, 0x3f, 0xee, 0xbd,
0xe3, 0x65, 0xdf, 0x23, 0x5f, 0xce, 0x88, 0x33, 0x24, 0x8c, 0x86, 0x8c, 0x5e, 0x04, 0x5b, 0x27, 0xea, 0xba, 0xec, 0xab, 0x29, 0xb3, 0x07, 0x0c, 0x69, 0x48, 0xe8, 0x39, 0xb0, 0xb5, 0x02, 0x13,
0x34, 0xe1, 0x4d, 0x84, 0x2c, 0xc7, 0x77, 0xa9, 0x39, 0x83, 0x55, 0x95, 0x1c, 0xe3, 0x29, 0x61, 0xdd, 0x24, 0xc4, 0xb4, 0x3d, 0x87, 0x1b, 0x53, 0x58, 0x55, 0x4c, 0x23, 0x4f, 0x11, 0x0b, 0xfd,
0xc1, 0x1f, 0xa2, 0x3c, 0x23, 0xb1, 0x0f, 0x17, 0xcd, 0x83, 0x57, 0xd8, 0x93, 0x02, 0x3a, 0x7e, 0x1f, 0xc9, 0x20, 0x89, 0x5d, 0xb8, 0x68, 0x06, 0xbc, 0xd2, 0x9e, 0xec, 0xd3, 0xf1, 0xd3, 0x87,
0x7a, 0xb7, 0x95, 0x63, 0x14, 0xaa, 0x8d, 0xd3, 0x78, 0xa8, 0xe7, 0x18, 0x56, 0x35, 0xe5, 0x16, 0xad, 0x34, 0x52, 0x58, 0xab, 0x9e, 0xce, 0x87, 0x7a, 0x1a, 0xb1, 0x35, 0x43, 0x69, 0x90, 0x24,
0xca, 0x32, 0x1b, 0x50, 0x24, 0x72, 0x19, 0x85, 0x75, 0x15, 0xce, 0xf0, 0x2e, 0xca, 0x8e, 0x2c, 0xda, 0x80, 0xa2, 0x94, 0x90, 0x51, 0x50, 0x57, 0xc1, 0x8c, 0xee, 0x92, 0xe4, 0xd0, 0xb4, 0x80,
0x1b, 0xa8, 0x48, 0x33, 0xd6, 0x71, 0x42, 0x83, 0x60, 0x56, 0x9d, 0x11, 0x0d, 0x79, 0xe7, 0x30, 0x8a, 0x38, 0xb2, 0x4e, 0x23, 0x1a, 0x04, 0x73, 0xcd, 0x1e, 0xf2, 0x80, 0x77, 0x01, 0x53, 0x3a,
0xb9, 0x87, 0x8a, 0x2c, 0x60, 0x6f, 0x6a, 0x1a, 0x3e, 0xf9, 0xdb, 0xc2, 0xfe, 0x91, 0x46, 0xf9, 0x24, 0x87, 0x1b, 0x76, 0x26, 0x46, 0xcf, 0x63, 0x7f, 0xd9, 0xb6, 0x6f, 0x12, 0x24, 0x13, 0x7a,
0xc8, 0x33, 0x4f, 0x5b, 0x2a, 0x91, 0xb6, 0x6a, 0x58, 0xa9, 0xbc, 0xee, 0xd6, 0xcf, 0xc7, 0x4b, 0x66, 0x69, 0x8b, 0x45, 0xd2, 0x56, 0x0a, 0x2a, 0x55, 0xd4, 0xdd, 0xfa, 0xf9, 0xfd, 0x22, 0xa5,
0x94, 0x2a, 0xac, 0xf7, 0xac, 0xaf, 0x08, 0x53, 0x7a, 0x46, 0x67, 0x63, 0xbc, 0x8d, 0x8a, 0x67, 0x0a, 0xeb, 0x5d, 0xf3, 0x6b, 0x86, 0x4a, 0x4f, 0xe8, 0x38, 0xa6, 0xdb, 0x24, 0x77, 0x56, 0xde,
0xe5, 0xbd, 0xac, 0x27, 0x4d, 0x58, 0x42, 0xf9, 0x09, 0x35, 0xad, 0x91, 0x45, 0x4c, 0x96, 0xc0, 0xcb, 0x7a, 0xd4, 0x44, 0x6f, 0x12, 0x32, 0xe6, 0x86, 0x39, 0x34, 0x99, 0xd1, 0x75, 0x31, 0x85,
0x8c, 0x3e, 0x9f, 0xe3, 0x4a, 0xa0, 0xce, 0x40, 0xd9, 0x66, 0x28, 0xe1, 0x68, 0x1a, 0x78, 0x2c, 0x09, 0x3d, 0x1b, 0x5a, 0x5a, 0xb4, 0xe8, 0x0b, 0xd4, 0x17, 0xb7, 0x11, 0xa8, 0x38, 0x9c, 0xfa,
0xe7, 0xb9, 0x61, 0x43, 0x5a, 0x78, 0xd2, 0xa2, 0x69, 0xd0, 0x8c, 0x1c, 0xba, 0x50, 0x53, 0x79, 0x1e, 0xd3, 0x7e, 0xd1, 0xb3, 0x20, 0x33, 0x22, 0x6f, 0xe1, 0xd4, 0xef, 0x47, 0x36, 0x5f, 0x28,
0x06, 0x58, 0x76, 0x68, 0xb2, 0x9e, 0x40, 0xf8, 0x51, 0xb3, 0x2a, 0x80, 0x7f, 0x41, 0xf8, 0x47, 0xab, 0x0c, 0x02, 0x96, 0x6d, 0x1e, 0x2d, 0x29, 0xd0, 0x7e, 0xd8, 0xaf, 0xb2, 0xe0, 0x5f, 0xd0,
0x64, 0xe8, 0xd3, 0x79, 0x1b, 0x08, 0x61, 0xc1, 0x41, 0xe7, 0x4a, 0x42, 0xfc, 0xa0, 0xd1, 0x1c, 0xfe, 0x11, 0x1b, 0x78, 0x7c, 0xd6, 0x09, 0x02, 0x18, 0x95, 0x49, 0x66, 0x26, 0x26, 0x82, 0x27,
0xff, 0x1f, 0x89, 0x7b, 0x36, 0x1d, 0x3e, 0x8b, 0xaa, 0xe8, 0x6a, 0x1c, 0x8c, 0xd9, 0x13, 0xcc, 0x9d, 0xcd, 0xfd, 0x2e, 0x39, 0xbb, 0x07, 0x44, 0xcc, 0x81, 0x3b, 0xa9, 0xcf, 0xae, 0xa6, 0xb9,
0x8b, 0x03, 0x06, 0xfc, 0x58, 0xf8, 0xf6, 0xd5, 0xd6, 0x92, 0xfc, 0x18, 0x15, 0xe6, 0x80, 0x20, 0xf4, 0x3f, 0x24, 0xb5, 0x67, 0xf1, 0xc1, 0xf3, 0xb0, 0xd2, 0xae, 0xce, 0xa3, 0xa1, 0x3d, 0x92,
0xab, 0x74, 0x34, 0xf2, 0x88, 0xcf, 0x52, 0x90, 0xd1, 0xc3, 0xd9, 0x9c, 0xd8, 0x20, 0x09, 0xd9, 0x9d, 0x54, 0x1f, 0x81, 0x9f, 0x48, 0xdf, 0xbd, 0xde, 0x5a, 0x52, 0x9e, 0x90, 0xec, 0x0c, 0xe0,
0x90, 0x58, 0xb0, 0x1d, 0x1b, 0xde, 0x31, 0x23, 0xbb, 0xa4, 0xb3, 0x71, 0x18, 0xf2, 0x13, 0x24, 0x67, 0x9e, 0x0f, 0x87, 0x2e, 0xf3, 0x30, 0x4d, 0x09, 0x3d, 0x98, 0xcd, 0xc8, 0x8f, 0x63, 0x5c,
0xf2, 0x0b, 0xe0, 0xfb, 0x28, 0x3f, 0xa4, 0x33, 0xc7, 0x8f, 0x7b, 0xdd, 0x6a, 0xb2, 0xa4, 0x98, 0x41, 0x3e, 0xd8, 0x8e, 0x7b, 0xee, 0x31, 0x26, 0x24, 0xaf, 0xe3, 0x38, 0xd8, 0xf2, 0x53, 0x92,
0x27, 0x3c, 0xd5, 0x1c, 0x28, 0xef, 0xa3, 0x5c, 0xe8, 0x02, 0x2a, 0xa3, 0xfa, 0x16, 0xf6, 0xae, 0x12, 0x37, 0xa4, 0x0f, 0x48, 0x66, 0xc0, 0xa7, 0xb6, 0x37, 0xef, 0x87, 0xab, 0xd1, 0xb2, 0x43,
0x45, 0xb2, 0xef, 0x1c, 0x53, 0xd7, 0x67, 0xb2, 0x4f, 0x34, 0x3f, 0xa0, 0x7e, 0xc6, 0xcf, 0x27, 0x4f, 0x70, 0xaa, 0x19, 0x50, 0xd9, 0x27, 0xe9, 0xc0, 0x05, 0x5c, 0x87, 0x3d, 0x40, 0xda, 0xbb,
0xe8, 0x7c, 0x22, 0xff, 0x98, 0x42, 0x39, 0x3d, 0xe0, 0xc7, 0xf3, 0x13, 0x8d, 0x22, 0xbb, 0xd0, 0x16, 0x96, 0x46, 0xeb, 0x98, 0x3b, 0x1e, 0x96, 0x46, 0xa4, 0x41, 0x42, 0x6e, 0xa6, 0xe2, 0x7c,
0x28, 0x62, 0x19, 0xa7, 0x17, 0x64, 0x1c, 0x29, 0x31, 0x93, 0x50, 0x62, 0x4c, 0x8e, 0x70, 0x21, 0x92, 0x2e, 0x26, 0xca, 0x8f, 0x31, 0x92, 0xd6, 0x7d, 0x02, 0x5d, 0x2f, 0xd2, 0x4c, 0x92, 0x0b,
0x39, 0xd9, 0x0b, 0xc8, 0x11, 0x63, 0x72, 0x02, 0x5d, 0x8c, 0x5c, 0x3a, 0x61, 0x8d, 0x91, 0xba, 0xcd, 0x64, 0x2e, 0xf5, 0xf8, 0x82, 0xd4, 0x43, 0xb5, 0x26, 0x22, 0x6a, 0x9d, 0x93, 0x23, 0x5d,
0x86, 0x7b, 0x12, 0x0a, 0x67, 0x39, 0xb0, 0x76, 0x23, 0xa3, 0xdc, 0x47, 0x79, 0x9d, 0x78, 0x53, 0x48, 0x4e, 0xf2, 0x02, 0x72, 0x52, 0x73, 0x72, 0x7c, 0xe1, 0x0c, 0x1d, 0x3e, 0xc6, 0xe6, 0xc9,
0x90, 0x08, 0xb9, 0xf4, 0xd8, 0x10, 0x1e, 0xaa, 0xd0, 0x60, 0x87, 0x86, 0xf0, 0xc1, 0x18, 0xff, 0x9d, 0x9e, 0x73, 0x12, 0x28, 0x6b, 0xd9, 0xb7, 0xb6, 0x43, 0xa3, 0xd2, 0x25, 0x19, 0x9d, 0xb9,
0x1b, 0x09, 0x43, 0x6a, 0xf2, 0x23, 0xaf, 0x24, 0xf3, 0xaf, 0xb8, 0x2e, 0x85, 0xb7, 0xc7, 0x84, 0x13, 0xd0, 0x10, 0xbb, 0xf4, 0xd8, 0xb0, 0x3d, 0x54, 0x6a, 0x0f, 0x0f, 0x0d, 0xdb, 0xfb, 0x63,
0x2a, 0x09, 0x00, 0xf0, 0xee, 0x96, 0x1b, 0xf4, 0x85, 0x63, 0x53, 0xc3, 0x6c, 0xbb, 0x74, 0x1c, 0xfa, 0x0f, 0x22, 0x0d, 0xb8, 0x21, 0x8e, 0xbc, 0x12, 0xcd, 0xbf, 0xea, 0x38, 0x1c, 0xde, 0x27,
0x34, 0xb2, 0x4b, 0xcb, 0xb9, 0x81, 0x72, 0x33, 0x56, 0xf0, 0x51, 0x41, 0xdf, 0x5a, 0x2c, 0xc0, 0x03, 0x2a, 0xc9, 0x07, 0xc0, 0xdb, 0x5c, 0xa8, 0xf2, 0x97, 0xb6, 0xc5, 0x7b, 0x46, 0xd3, 0xe1,
0xb3, 0x81, 0x78, 0x77, 0x88, 0x84, 0x1b, 0x2e, 0x95, 0xdf, 0xa6, 0x90, 0x74, 0x39, 0x1a, 0xab, 0x23, 0xbf, 0xd9, 0x5d, 0x5a, 0xf2, 0x55, 0x92, 0x9e, 0x62, 0x53, 0x08, 0x8b, 0xfe, 0xf6, 0x62,
0xa8, 0xc8, 0x91, 0xfd, 0xc4, 0x9b, 0xbc, 0xf3, 0x3e, 0x1b, 0xb1, 0xda, 0x47, 0xb3, 0xf9, 0xf8, 0x91, 0x9e, 0xdd, 0x48, 0x74, 0x90, 0x50, 0xd9, 0xc1, 0x52, 0xe5, 0x7d, 0x8c, 0xc8, 0x97, 0xa3,
0xc2, 0xc6, 0x9f, 0x28, 0xb4, 0xcc, 0xfb, 0x15, 0x1a, 0x3c, 0x75, 0xac, 0x46, 0xe6, 0xcf, 0x97, 0x69, 0x8d, 0xe4, 0x04, 0xb2, 0x1b, 0x79, 0xb7, 0x77, 0x3e, 0x26, 0x10, 0xf6, 0x07, 0x32, 0x9d,
0x00, 0x77, 0xcf, 0xea, 0xa5, 0x01, 0x2f, 0x14, 0x66, 0x93, 0x45, 0x24, 0xb4, 0x2d, 0x67, 0x2c, 0x8d, 0x2f, 0x7c, 0x1c, 0x22, 0x95, 0x98, 0xf8, 0xb8, 0x4a, 0x84, 0xe7, 0x10, 0x6b, 0x64, 0xf6,
0x6f, 0xa1, 0x6c, 0xdd, 0xa6, 0x2c, 0x59, 0x22, 0xbc, 0xad, 0x1e, 0x6c, 0x13, 0x72, 0xc8, 0x67, 0xc4, 0x49, 0x70, 0xf7, 0xa4, 0x9e, 0xef, 0x8b, 0x42, 0x41, 0x9b, 0x92, 0x22, 0x52, 0xd3, 0xb4,
0xd5, 0xb7, 0x69, 0x54, 0x4c, 0x7c, 0x56, 0xc0, 0x79, 0x56, 0xea, 0xcd, 0x5e, 0xa7, 0xab, 0xe8, 0x47, 0xca, 0x16, 0x49, 0x56, 0x2c, 0x8e, 0xc9, 0x4a, 0xc1, 0xfb, 0xeb, 0x42, 0x98, 0x80, 0x43,
0xfd, 0x7a, 0x4b, 0xdb, 0x57, 0x0f, 0xca, 0x4b, 0xd2, 0xc6, 0xd7, 0xdf, 0x6d, 0x57, 0x26, 0x31, 0x31, 0x2b, 0xbd, 0x8f, 0x93, 0x5c, 0xe4, 0xd3, 0x03, 0xce, 0xb3, 0x52, 0xa9, 0x77, 0x5a, 0x6d,
0x68, 0xf1, 0x8b, 0x01, 0xb6, 0x50, 0xb5, 0x86, 0xf2, 0x59, 0x39, 0x25, 0xad, 0x01, 0xb0, 0x9c, 0x55, 0xef, 0x56, 0x1a, 0xda, 0x7e, 0xed, 0xa0, 0xb0, 0x24, 0x6f, 0x7c, 0xf3, 0xfd, 0x76, 0x71,
0x00, 0xf2, 0x26, 0xff, 0x5f, 0x54, 0x62, 0x80, 0x7e, 0xaf, 0xdd, 0xa8, 0x75, 0x95, 0x72, 0x5a, 0x3c, 0x07, 0x2d, 0x7e, 0x55, 0x40, 0x88, 0x9a, 0x56, 0x55, 0x3f, 0x2f, 0xc4, 0xe4, 0x35, 0x00,
0x92, 0x00, 0xb7, 0x7e, 0x16, 0x17, 0xf2, 0x7d, 0x13, 0xea, 0x42, 0x79, 0xdc, 0x53, 0x3a, 0xdd, 0x16, 0x22, 0x40, 0xf1, 0x10, 0xfc, 0x8b, 0xe4, 0x11, 0xd0, 0xed, 0x34, 0xab, 0xe5, 0xb6, 0x5a,
0x72, 0x46, 0x5a, 0x07, 0x20, 0x4e, 0x00, 0xa3, 0x8a, 0xb9, 0x0d, 0x32, 0x54, 0x3a, 0xed, 0x96, 0x88, 0xcb, 0x32, 0xe0, 0xd6, 0xcf, 0xe2, 0x02, 0xbe, 0x6f, 0x41, 0x5d, 0xa8, 0x4f, 0x3a, 0x6a,
0xd6, 0x51, 0xca, 0x82, 0x74, 0x1d, 0x50, 0x57, 0x17, 0x50, 0xa1, 0x42, 0x3f, 0x42, 0xab, 0x8d, 0xab, 0x5d, 0x48, 0xc8, 0xeb, 0x00, 0xa4, 0x11, 0x60, 0x58, 0x31, 0x77, 0x40, 0x86, 0x6a, 0xab,
0xd6, 0x13, 0xad, 0xd9, 0xaa, 0x35, 0xfa, 0x6d, 0xbd, 0x75, 0x00, 0x6b, 0x3a, 0xe5, 0xac, 0xb4, 0xd9, 0xd0, 0x5a, 0x6a, 0x41, 0x92, 0xaf, 0x03, 0xea, 0xea, 0x02, 0x2a, 0x50, 0xe8, 0xff, 0xc9,
0x05, 0xf8, 0x1b, 0x09, 0xfc, 0x39, 0xc1, 0xfd, 0x13, 0xd8, 0x53, 0xb5, 0x83, 0xb2, 0x28, 0x5d, 0x6a, 0xb5, 0xf1, 0x54, 0xab, 0x37, 0xca, 0xd5, 0x6e, 0x53, 0x6f, 0x1c, 0xc0, 0x9a, 0x56, 0x21,
0x05, 0xe8, 0x95, 0x04, 0x34, 0x20, 0x35, 0xb8, 0x71, 0xbd, 0xd9, 0x82, 0xad, 0x73, 0xe7, 0x6e, 0x29, 0x6f, 0x01, 0xfe, 0x46, 0x04, 0x7f, 0x4e, 0x70, 0x37, 0x81, 0xbd, 0x9a, 0x76, 0x50, 0x48,
0xcc, 0xc8, 0xae, 0x7e, 0x81, 0xf0, 0xf9, 0x0f, 0x2f, 0x7c, 0x0b, 0x09, 0x5a, 0x4b, 0x53, 0x80, 0xc9, 0x57, 0x01, 0x7a, 0x25, 0x02, 0xf5, 0x49, 0xf5, 0x6f, 0x5c, 0xa9, 0x37, 0x20, 0x74, 0xfa,
0x50, 0x76, 0xff, 0xf3, 0x08, 0x8d, 0x3a, 0x04, 0xcb, 0x28, 0xd3, 0xfc, 0xfc, 0x03, 0x20, 0xf3, 0xdc, 0x8d, 0x91, 0xec, 0xd2, 0x97, 0x84, 0x9e, 0xff, 0x38, 0xa3, 0xb7, 0x89, 0xa4, 0x35, 0x34,
0x1f, 0x00, 0xba, 0x76, 0x1e, 0x04, 0xce, 0x2a, 0x45, 0xc5, 0x64, 0x60, 0x19, 0xe5, 0x0f, 0x95, 0x15, 0x08, 0xc5, 0xfb, 0x9f, 0x47, 0x68, 0xdc, 0x66, 0x54, 0x21, 0x89, 0xfa, 0x17, 0xff, 0x05,
0x6e, 0x0d, 0xc8, 0xad, 0x41, 0x70, 0x76, 0xa4, 0xc8, 0x7d, 0x48, 0x7c, 0x83, 0x15, 0xe0, 0x06, 0x32, 0xff, 0x06, 0xa0, 0x6b, 0xe7, 0x41, 0xe0, 0x2c, 0x71, 0x92, 0x8b, 0x6e, 0xac, 0x90, 0xcc,
0xca, 0x6a, 0xca, 0x91, 0xa2, 0x43, 0xe0, 0x55, 0x00, 0x2c, 0x47, 0x00, 0x8d, 0x80, 0xae, 0xe0, 0xa1, 0xda, 0x2e, 0x03, 0xb9, 0x65, 0xd8, 0x1c, 0x8f, 0x14, 0xba, 0x0f, 0x99, 0xd7, 0xc3, 0x02,
0x9d, 0x17, 0x6b, 0xcd, 0x27, 0xb5, 0xa7, 0x1d, 0x48, 0x0e, 0x06, 0xf7, 0x4a, 0xe4, 0xae, 0xd9, 0xdc, 0x20, 0x49, 0x4d, 0x3d, 0x52, 0x75, 0xd8, 0x78, 0x15, 0x00, 0xcb, 0x21, 0x40, 0x63, 0xa0,
0x2f, 0x8c, 0x13, 0xaf, 0xfa, 0x7b, 0x0a, 0x95, 0x92, 0x4f, 0x1a, 0x2c, 0x10, 0xf6, 0xd5, 0xa6, 0x2b, 0xf8, 0x16, 0x48, 0x95, 0xeb, 0x4f, 0xcb, 0xcf, 0x5a, 0x90, 0x1c, 0x0a, 0xee, 0x95, 0xd0,
0x12, 0x6d, 0x97, 0xf4, 0x05, 0x63, 0xbc, 0x83, 0x0a, 0x0d, 0x55, 0x57, 0xea, 0xdd, 0x96, 0xfe, 0x5d, 0xb6, 0x5e, 0xf6, 0x4e, 0xdc, 0xd2, 0xef, 0x31, 0x92, 0x8f, 0x3e, 0x7b, 0xb0, 0x40, 0xda,
0x34, 0xba, 0x4b, 0x12, 0xd4, 0xb0, 0x5c, 0x26, 0xee, 0xe0, 0x43, 0xaf, 0xd4, 0x79, 0x7a, 0xd8, 0xaf, 0xd5, 0xd5, 0x30, 0x5c, 0xd4, 0xe7, 0x8f, 0xe9, 0x0e, 0xc9, 0x56, 0x6b, 0xba, 0x5a, 0x69,
0x54, 0xb5, 0x47, 0x7d, 0x16, 0x31, 0x2d, 0xdd, 0x00, 0xf0, 0xf5, 0x24, 0xb8, 0x73, 0x32, 0xb1, 0x37, 0xf4, 0x67, 0xe1, 0x5d, 0xa2, 0xa0, 0xaa, 0xe9, 0xa0, 0xb8, 0xfd, 0x8f, 0xc1, 0x7c, 0xeb,
0x2d, 0xe7, 0x19, 0x0b, 0xfc, 0x00, 0xad, 0x46, 0xf0, 0x78, 0x83, 0x8c, 0xb4, 0x0d, 0x6b, 0x36, 0xd9, 0x61, 0xbd, 0xa6, 0x3d, 0xee, 0xe2, 0x8e, 0x71, 0xf9, 0x06, 0x80, 0xaf, 0x47, 0xc1, 0xad,
0x2e, 0x58, 0x13, 0xef, 0x73, 0x1f, 0x5d, 0x89, 0x16, 0xf6, 0xb4, 0x47, 0x1a, 0xc8, 0x02, 0x94, 0x93, 0xb1, 0x65, 0xda, 0xcf, 0x71, 0xe3, 0x87, 0x64, 0x35, 0x84, 0xcf, 0x03, 0x24, 0xe4, 0x6d,
0xb3, 0x09, 0xcb, 0xa4, 0x0b, 0x96, 0xf5, 0x9c, 0x67, 0x0e, 0x88, 0xa2, 0xfa, 0x43, 0x0a, 0x15, 0x58, 0xb3, 0x71, 0xc1, 0x9a, 0x79, 0x9c, 0x07, 0xe4, 0x4a, 0xb8, 0xb0, 0xa3, 0x3d, 0xd6, 0x40,
0xe6, 0x1d, 0x2a, 0xe0, 0x59, 0x6b, 0xf5, 0x15, 0x5d, 0x6f, 0xe9, 0xd1, 0xc5, 0xe7, 0x4e, 0x8d, 0x16, 0xa0, 0x9c, 0x4d, 0x58, 0x26, 0x5f, 0xb0, 0xac, 0x63, 0x3f, 0xb7, 0x41, 0x14, 0xa5, 0x1f,
0xb2, 0x21, 0x7c, 0x54, 0xe5, 0x0e, 0x14, 0x4d, 0xd1, 0xd5, 0x7a, 0x54, 0x0f, 0x73, 0xc8, 0x01, 0x62, 0x24, 0x3b, 0xeb, 0x50, 0x3e, 0xcf, 0x5a, 0xa3, 0xab, 0xea, 0x7a, 0x43, 0x0f, 0x2f, 0x3e,
0x71, 0x88, 0x6b, 0x0d, 0xe1, 0xf3, 0xbe, 0x04, 0x61, 0x3a, 0xbd, 0xfa, 0xc3, 0xe8, 0xc6, 0x4c, 0x73, 0x6a, 0x1c, 0x87, 0xf0, 0xe1, 0x95, 0x3e, 0x50, 0x35, 0x55, 0xaf, 0x55, 0xc2, 0x7a, 0x98,
0xc0, 0x89, 0x50, 0x9d, 0xd9, 0xf0, 0x98, 0xdd, 0xb6, 0x1a, 0x94, 0xce, 0x51, 0xad, 0xa9, 0x36, 0x41, 0x0e, 0x98, 0xcd, 0x1c, 0x73, 0x00, 0xff, 0x02, 0xe4, 0x61, 0x9b, 0x56, 0xa7, 0xf2, 0x28,
0x38, 0x34, 0x23, 0x55, 0x00, 0xba, 0x36, 0x87, 0xaa, 0xfc, 0x55, 0x0f, 0xb0, 0x55, 0x13, 0x6d, 0xbc, 0x31, 0x0a, 0x38, 0xb2, 0x55, 0x6b, 0x3a, 0x38, 0xc6, 0xdb, 0x96, 0xfc, 0xd2, 0x39, 0x2a,
0xfe, 0x75, 0x2f, 0x82, 0xaf, 0x0d, 0xb1, 0xd6, 0x6e, 0x2b, 0x5a, 0x23, 0x3a, 0x7d, 0xec, 0xab, 0xd7, 0x6b, 0x55, 0x01, 0x4d, 0xc8, 0x45, 0x80, 0xae, 0xcd, 0xa0, 0x35, 0xf1, 0xec, 0xfb, 0xd8,
0x4d, 0xa7, 0xc4, 0x31, 0x03, 0xc4, 0x7e, 0x4b, 0x3f, 0x50, 0xba, 0xd1, 0xe1, 0x63, 0xc4, 0x3e, 0x92, 0x41, 0x36, 0xff, 0xbc, 0x17, 0xc1, 0x17, 0x49, 0xaa, 0xdc, 0x6c, 0xaa, 0x5a, 0x35, 0x3c,
0x75, 0xc7, 0xc4, 0xdf, 0xdb, 0x78, 0xfd, 0xcb, 0xe6, 0xd2, 0x1b, 0xf8, 0xbd, 0x3e, 0xdd, 0x4c, 0xfd, 0xdc, 0x57, 0x9e, 0x4c, 0x98, 0x6d, 0xf8, 0x88, 0xfd, 0x86, 0x7e, 0xa0, 0xb6, 0xc3, 0xc3,
0xbd, 0x81, 0xdf, 0xcf, 0xa7, 0x9b, 0x4b, 0xbf, 0xc1, 0xff, 0xab, 0x5f, 0x37, 0x53, 0x03, 0x91, 0xcf, 0x11, 0xfb, 0xdc, 0x19, 0x31, 0x6f, 0x6f, 0xe3, 0xed, 0x2f, 0x9b, 0x4b, 0xef, 0xe0, 0xef,
0xf5, 0xae, 0xfb, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x49, 0x51, 0xc5, 0x82, 0x0d, 0x00, 0xed, 0xe9, 0x66, 0xec, 0x1d, 0xfc, 0xfd, 0x7c, 0xba, 0xb9, 0xf4, 0x1b, 0xfc, 0xbe, 0xfe, 0x75,
0x00, 0x33, 0xd6, 0x4f, 0x61, 0xef, 0x7a, 0xf0, 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x88, 0xa1,
0x6a, 0xa6, 0x0d, 0x00, 0x00,
} }

View File

@ -97,7 +97,8 @@ message FileInfo {
FileInfoType type = 2; FileInfoType type = 2;
int64 size = 3; int64 size = 3;
uint32 permissions = 4; uint32 permissions = 4;
int64 modified = 5; int64 modified_s = 5;
int32 modified_ns = 11;
bool deleted = 6; bool deleted = 6;
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;

View File

@ -11,6 +11,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"time"
"github.com/syncthing/syncthing/lib/rand" "github.com/syncthing/syncthing/lib/rand"
) )
@ -25,8 +26,8 @@ func (m Hello) Magic() uint32 {
} }
func (f FileInfo) String() string { func (f FileInfo) String() string {
return fmt.Sprintf("File{Name:%q, Type:%v, Sequence:%d, Permissions:0%o, Modified:%d, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}", return fmt.Sprintf("File{Name:%q, Type:%v, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}",
f.Name, f.Type, f.Sequence, f.Permissions, f.Modified, f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks) f.Name, f.Type, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks)
} }
func (f FileInfo) IsDeleted() bool { func (f FileInfo) IsDeleted() bool {
@ -65,6 +66,10 @@ func (f FileInfo) FileName() string {
return f.Name return f.Name
} }
func (f FileInfo) ModTime() time.Time {
return time.Unix(f.ModifiedS, int64(f.ModifiedNs))
}
// WinsConflict returns true if "f" is the one to choose when it is in // WinsConflict returns true if "f" is the one to choose when it is in
// conflict with "other". // conflict with "other".
func (f FileInfo) WinsConflict(other FileInfo) bool { func (f FileInfo) WinsConflict(other FileInfo) bool {
@ -78,10 +83,10 @@ func (f FileInfo) WinsConflict(other FileInfo) bool {
} }
// The one with the newer modification time wins. // The one with the newer modification time wins.
if f.Modified > other.Modified { if f.ModTime().After(other.ModTime()) {
return true return true
} }
if f.Modified < other.Modified { if f.ModTime().Before(other.ModTime()) {
return false return false
} }

View File

@ -7,9 +7,9 @@ import "testing"
func TestWinsConflict(t *testing.T) { func TestWinsConflict(t *testing.T) {
testcases := [][2]FileInfo{ testcases := [][2]FileInfo{
// The first should always win over the second // The first should always win over the second
{{Modified: 42}, {Modified: 41}}, {{ModifiedS: 42}, {ModifiedS: 41}},
{{Modified: 41}, {Modified: 42, Deleted: true}}, {{ModifiedS: 41}, {ModifiedS: 42, Deleted: true}},
{{Modified: 41, Version: Vector{[]Counter{{42, 2}, {43, 1}}}}, {Modified: 41, Version: Vector{[]Counter{{42, 1}, {43, 2}}}}}, {{ModifiedS: 41, Version: Vector{[]Counter{{42, 2}, {43, 1}}}}, {ModifiedS: 41, Version: Vector{[]Counter{{42, 1}, {43, 2}}}}},
} }
for _, tc := range testcases { for _, tc := range testcases {

View File

@ -221,7 +221,7 @@ func TestMarshalledIndexMessageSize(t *testing.T) {
Type: FileInfoTypeFile, Type: FileInfoTypeFile,
Size: fileSize, Size: fileSize,
Permissions: 0666, Permissions: 0666,
Modified: time.Now().Unix(), ModifiedS: time.Now().Unix(),
Version: Vector{Counters: []Counter{{ID: 1 << 60, Value: 1}, {ID: 2 << 60, Value: 1}}}, Version: Vector{Counters: []Counter{{ID: 1 << 60, Value: 1}, {ID: 2 << 60, Value: 1}}},
Blocks: make([]BlockInfo, fileSize/blockSize), Blocks: make([]BlockInfo, fileSize/blockSize),
} }

View File

@ -310,7 +310,7 @@ func (w *walker) walkRegular(relPath string, info os.FileInfo, fchan chan protoc
// - has the same size as previously // - has the same size as previously
cf, ok := w.CurrentFiler.CurrentFile(relPath) cf, ok := w.CurrentFiler.CurrentFile(relPath)
permUnchanged := w.IgnorePerms || !cf.HasPermissionBits() || PermsEqual(cf.Permissions, curMode) permUnchanged := w.IgnorePerms || !cf.HasPermissionBits() || PermsEqual(cf.Permissions, curMode)
if ok && permUnchanged && !cf.IsDeleted() && cf.Modified == info.ModTime().Unix() && !cf.IsDirectory() && if ok && permUnchanged && !cf.IsDeleted() && cf.ModTime().Equal(info.ModTime()) && !cf.IsDirectory() &&
!cf.IsSymlink() && !cf.IsInvalid() && cf.Size == info.Size() { !cf.IsSymlink() && !cf.IsInvalid() && cf.Size == info.Size() {
return nil return nil
} }
@ -323,7 +323,8 @@ func (w *walker) walkRegular(relPath string, info os.FileInfo, fchan chan protoc
Version: cf.Version.Update(w.ShortID), Version: cf.Version.Update(w.ShortID),
Permissions: curMode & uint32(maskModePerm), Permissions: curMode & uint32(maskModePerm),
NoPermissions: w.IgnorePerms, NoPermissions: w.IgnorePerms,
Modified: info.ModTime().Unix(), ModifiedS: info.ModTime().Unix(),
ModifiedNs: int32(info.ModTime().Nanosecond()),
Size: info.Size(), Size: info.Size(),
} }
l.Debugln("to hash:", relPath, f) l.Debugln("to hash:", relPath, f)
@ -357,7 +358,8 @@ func (w *walker) walkDir(relPath string, info os.FileInfo, dchan chan protocol.F
Version: cf.Version.Update(w.ShortID), Version: cf.Version.Update(w.ShortID),
Permissions: uint32(info.Mode() & maskModePerm), Permissions: uint32(info.Mode() & maskModePerm),
NoPermissions: w.IgnorePerms, NoPermissions: w.IgnorePerms,
Modified: info.ModTime().Unix(), ModifiedS: info.ModTime().Unix(),
ModifiedNs: int32(info.ModTime().Nanosecond()),
} }
l.Debugln("dir:", relPath, f) l.Debugln("dir:", relPath, f)
@ -416,7 +418,6 @@ func (w *walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileIn
Name: relPath, Name: relPath,
Type: SymlinkType(targetType), Type: SymlinkType(targetType),
Version: cf.Version.Update(w.ShortID), Version: cf.Version.Update(w.ShortID),
Modified: 0,
NoPermissions: true, // Symlinks don't have permissions of their own NoPermissions: true, // Symlinks don't have permissions of their own
Blocks: blocks, Blocks: blocks,
} }

View File

@ -455,7 +455,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
f = fileInfo{ f = fileInfo{
name: rn, name: rn,
mode: info.Mode(), mode: info.Mode(),
mod: info.ModTime().Unix(), mod: info.ModTime().Truncate(time.Microsecond).UnixNano(),
size: info.Size(), size: info.Size(),
} }
sum, err := md5file(path) sum, err := md5file(path)