main pico / pkg / rsync-receiver / rsyncreceiver / do.go
Eric Bower  ·  2026-05-31
 1package rsyncreceiver
 2
 3import (
 4	"context"
 5
 6	"github.com/picosh/pico/pkg/rsync-receiver/rsyncstats"
 7	"github.com/picosh/pico/pkg/rsync-receiver/rsyncwire"
 8	"github.com/picosh/pico/pkg/rsync-receiver/utils"
 9	"golang.org/x/sync/errgroup"
10)
11
12func (rt *Transfer) deleteFiles(fileList []*utils.ReceiverFile) error {
13	if rt.IOErrors > 0 {
14		rt.Logger.Debug("IO error encountered, skipping file deletion")
15		return nil
16	}
17
18	return rt.Files.Remove(fileList)
19}
20
21// rsync/main.c:do_recv.
22func (rt *Transfer) Do(c *rsyncwire.Conn, fileList []*utils.ReceiverFile, noReport bool) (*rsyncstats.TransferStats, error) {
23	if rt.Opts.DeleteMode {
24		if err := rt.deleteFiles(fileList); err != nil {
25			return nil, err
26		}
27	}
28
29	ctx := context.Background()
30	eg, ctx := errgroup.WithContext(ctx)
31	eg.Go(func() error {
32		return rt.GenerateFiles(fileList)
33	})
34	eg.Go(func() error {
35		// Ensure we don’t block on the receiver when the generator returns an
36		// error.
37		errChan := make(chan error)
38		go func() {
39			errChan <- rt.RecvFiles(fileList)
40		}()
41		select {
42		case <-ctx.Done():
43			return ctx.Err()
44		case err := <-errChan:
45			return err
46		}
47	})
48	if err := eg.Wait(); err != nil {
49		return nil, err
50	}
51
52	var stats *rsyncstats.TransferStats
53	if !noReport {
54		var err error
55		stats, err = report(c)
56		rt.Logger.Debug("report", "stats", stats)
57		if err != nil {
58			return nil, err
59		}
60	}
61
62	// send final goodbye message
63	if err := c.WriteInt32(-1); err != nil {
64		return nil, err
65	}
66
67	return stats, nil
68}
69
70// rsync/main.c:report.
71func report(c *rsyncwire.Conn) (*rsyncstats.TransferStats, error) {
72	// read statistics:
73	// total bytes read (from network connection)
74	read, err := c.ReadInt64()
75	if err != nil {
76		return nil, err
77	}
78	// total bytes written (to network connection)
79	written, err := c.ReadInt64()
80	if err != nil {
81		return nil, err
82	}
83	// total size of files
84	size, err := c.ReadInt64()
85	if err != nil {
86		return nil, err
87	}
88
89	return &rsyncstats.TransferStats{
90		Read:    read,
91		Written: written,
92		Size:    size,
93	}, nil
94}