main pico / pkg / rsync-receiver / rsyncsender / do.go
Eric Bower  ·  2026-05-31
 1package rsyncsender
 2
 3import (
 4	"fmt"
 5	"sort"
 6
 7	"github.com/picosh/pico/pkg/rsync-receiver/rsyncstats"
 8	"github.com/picosh/pico/pkg/rsync-receiver/rsyncwire"
 9)
10
11// rsync/main.c:client_run am_sender.
12func (st *Transfer) Do(crd *rsyncwire.CountingReader, cwr *rsyncwire.CountingWriter, paths []string, exclusionList *filterRuleList) (*rsyncstats.TransferStats, error) {
13	if exclusionList == nil {
14		exclusionList = &filterRuleList{}
15	}
16
17	// “Update exchange” as per
18	// https://github.com/kristapsdz/openrsync/blob/master/rsync.5
19
20	// send file list
21	fileList, err := st.SendFileList(st.Opts, paths, exclusionList)
22	if err != nil {
23		return nil, err
24	}
25
26	st.Logger.Debug("file list sent")
27
28	// Sort the file list. The client sorts, so we need to sort, too (in the
29	// same way!), otherwise our indices do not match what the client will
30	// request.
31	sort.Slice(fileList.Files, func(i, j int) bool {
32		return fileList.Files[i].WPath < fileList.Files[j].WPath
33	})
34
35	if err := st.SendFiles(fileList); err != nil {
36		return nil, err
37	}
38
39	// send statistics:
40	// total bytes read (from network connection)
41	if err := st.Conn.WriteInt64(crd.BytesRead); err != nil {
42		return nil, err
43	}
44	// total bytes written (to network connection)
45	if err := st.Conn.WriteInt64(cwr.BytesWritten); err != nil {
46		return nil, err
47	}
48	// total size of files
49	if err := st.Conn.WriteInt64(fileList.TotalSize); err != nil {
50		return nil, err
51	}
52
53	st.Logger.Debug("reading final int32")
54
55	finish, err := st.Conn.ReadInt32()
56	if err != nil {
57		return nil, err
58	}
59	if finish != -1 {
60		return nil, fmt.Errorf("protocol error: expected final -1, got %d", finish)
61	}
62
63	return &rsyncstats.TransferStats{
64		Read:    crd.BytesRead,
65		Written: cwr.BytesWritten,
66		Size:    fileList.TotalSize,
67	}, nil
68}