Eric Bower
·
2026-05-31
1package rsyncsender
2
3import (
4 "io"
5 "log/slog"
6 "os"
7)
8
9// rsync.h:map_struct.
10type mapStruct struct {
11 fileSize int64 // file size (from stat)
12 pOffset int64 // window start
13 pFdOffset int64 // offset of cursor in fd ala lseek
14 window []byte // window pointer
15 pSize int64 // largest window we allocated
16 pLen int64 // latest (rounded) window size
17 defWindowSize int64 // default window size
18 f *os.File // file descriptor
19 err error // first read error
20}
21
22const alignBoundary = 1024
23
24func alignedLength(l int64) int64 {
25 return ((l - 1) | (alignBoundary - 1)) + 1
26}
27
28func alignedOvershoot(off int64) int64 {
29 return off & (alignBoundary - 1)
30}
31
32func mapFile(f *os.File, len int64, readSize int32, blkSize int32) *mapStruct {
33 if blkSize > 0 && readSize%blkSize != 0 {
34 readSize += blkSize - (readSize % blkSize)
35 }
36 return &mapStruct{
37 fileSize: len,
38 defWindowSize: alignedLength(int64(readSize)),
39 f: f,
40 }
41}
42
43func (ms *mapStruct) ptr(offset int64, l int32) []byte {
44 //log.Printf("ptr(offset=%d, l=%d)", offset, l)
45 len := int64(l)
46 if len == 0 {
47 return nil
48 }
49 if len < 0 {
50 slog.Debug("BUG: invalid len", "len", len)
51 return nil
52 }
53
54 if offset >= ms.pOffset && offset+int64(len) <= ms.pOffset+int64(ms.pLen) {
55 //log.Printf("-> already available")
56 // region already available
57 off := offset - ms.pOffset
58 return ms.window[off : off+int64(len)]
59 }
60
61 alignFudge := alignedOvershoot(offset)
62 windowStart := offset - alignFudge
63 windowSize := int64(ms.defWindowSize)
64 if windowStart+windowSize > ms.fileSize {
65 windowSize = ms.fileSize - windowStart
66 }
67 if windowSize < len+alignFudge {
68 windowSize = alignedLength(len + alignFudge)
69 }
70 if windowSize > ms.pSize {
71 win := make([]byte, windowSize)
72 copy(win, ms.window)
73 ms.window = win
74 ms.pSize = windowSize
75 }
76 readStart := windowStart
77 readSize := windowSize
78 readOffset := int64(0)
79
80 //log.Printf("windowSize: %d, ms=%+v", windowSize, ms)
81 if windowStart >= ms.pOffset && windowStart < ms.pOffset+ms.pLen &&
82 windowStart+windowSize >= ms.pOffset+ms.pLen {
83 readStart = ms.pOffset + ms.pLen
84 readOffset = readStart - windowStart
85 readSize = windowSize - readOffset
86 off := ms.pLen - readOffset
87 copy(ms.window[:], ms.window[off:off+readOffset])
88 }
89 if readSize <= 0 {
90 slog.Debug("BUG: invalid readSize", "readSize", readSize)
91 return nil
92 }
93 if ms.pFdOffset != readStart {
94 if _, err := ms.f.Seek(readStart, io.SeekStart); err != nil {
95 slog.Error("seek error", "err", err)
96 return nil
97 }
98 ms.pFdOffset = readStart
99 }
100 ms.pOffset = windowStart
101 ms.pLen = windowSize
102 //log.Printf("-> reading %d bytes from %d into buffer at offset=%d", readSize, readStart, readOffset)
103 for readSize > 0 {
104 n, err := ms.f.Read(ms.window[readOffset : readOffset+readSize])
105 if err != nil {
106 ms.err = err
107 // TODO: zero the buffer, file has changed mid-transfer
108 slog.Debug("file has changed mid-transfer")
109 return nil
110 }
111 ms.pFdOffset += int64(n)
112 readOffset += int64(n)
113 readSize -= int64(n)
114 }
115 return ms.window[alignFudge : alignFudge+len]
116}