main pico / pkg / rsync-receiver / rsync / types.go
Eric Bower  ·  2026-05-31
 1package rsync
 2
 3import (
 4	"fmt"
 5
 6	"github.com/picosh/pico/pkg/rsync-receiver/rsyncwire"
 7)
 8
 9// rsync/rsync.h:struct sum_buf.
10type SumBuf struct {
11	Offset int64
12	Len    int64
13	Index  int32
14	Sum1   uint32
15	Sum2   [16]byte
16}
17
18// TODO: remove connection.go:sumHead in favor of this type.
19type SumHead struct {
20	// “number of blocks” (openrsync)
21	// “how many chunks” (rsync)
22	ChecksumCount int32
23
24	// “block length in the file” (openrsync)
25	// maximum (1 << 29) for older rsync, (1 << 17) for newer
26	BlockLength int32
27
28	// “long checksum length” (openrsync)
29	ChecksumLength int32
30
31	// “terminal (remainder) block length” (openrsync)
32	// RemainderLength is flength % BlockLength
33	RemainderLength int32
34
35	Sums []SumBuf
36}
37
38func (sh *SumHead) ReadFrom(c *rsyncwire.Conn) error {
39	// TODO(protocol>=30): update maxBlockLen
40	const maxBlockLen = 1 << 29 // see rsync.h:OLD_MAX_BLOCK_SIZE
41
42	var err error
43	sh.ChecksumCount, err = c.ReadInt32()
44	if err != nil {
45		return err
46	}
47	if sh.ChecksumCount < 0 {
48		return fmt.Errorf("invalid checksum count %d", sh.ChecksumCount)
49	}
50
51	sh.BlockLength, err = c.ReadInt32()
52	if err != nil {
53		return err
54	}
55	if sh.BlockLength < 0 || sh.BlockLength > maxBlockLen {
56		return fmt.Errorf("invalid block length %d", sh.BlockLength)
57	}
58
59	sh.ChecksumLength, err = c.ReadInt32()
60	if err != nil {
61		return err
62	}
63	// TODO(protocol>=27): update max sh.ChecksumLength check
64	if sh.ChecksumLength < 0 || sh.ChecksumLength > 16 {
65		return fmt.Errorf("invalid checksum length %d", sh.ChecksumLength)
66	}
67
68	sh.RemainderLength, err = c.ReadInt32()
69	if err != nil {
70		return err
71	}
72	if sh.RemainderLength < 0 || sh.RemainderLength > sh.BlockLength {
73		return fmt.Errorf("invalid remainder length %d", sh.RemainderLength)
74	}
75
76	return nil
77}
78
79func (sh *SumHead) WriteTo(c *rsyncwire.Conn) error {
80	var buf rsyncwire.Buffer
81	buf.WriteInt32(sh.ChecksumCount)
82	buf.WriteInt32(sh.BlockLength)
83	buf.WriteInt32(sh.ChecksumLength)
84	buf.WriteInt32(sh.RemainderLength)
85	return c.WriteString(buf.String())
86}