main pico / pkg / rsync-receiver / rsyncsender / fileio.go
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}