Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions cmd/dump/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
rootcmd "lvmsync_go/cmd/root"
"lvmsync_go/common"
"lvmsync_go/device"
internalcommon "lvmsync_go/internal/common"
"lvmsync_go/internal/config"
cpufeatures "lvmsync_go/internal/cpufeatures"
digestpkg "lvmsync_go/internal/digest"
Expand Down Expand Up @@ -197,10 +198,6 @@ var copyBufferPool = sync.Pool{New: func() any {
return &buf
}}

type writeOnlyReadWriter struct{ io.Writer }

func (writeOnlyReadWriter) Read(p []byte) (int, error) { return 0, io.EOF }

type contextReader struct {
ctx context.Context
r io.Reader
Expand Down Expand Up @@ -549,7 +546,7 @@ func (r *Runner) StreamToRemote(ctx context.Context, cfg *config.Config, remoteS
return fmt.Errorf("compute digest: %w", err)
}

rw := writeOnlyReadWriter{remoteStdin}
rw := internalcommon.WriteOnlyReadWriter{Writer: remoteStdin}
cl := rsyncwire.NewClient(rsyncwire.NewStream(rw, maxFrame))
if err := cl.SendDigest(ctx, alg, sum); err != nil {
remoteStdin.Close()
Expand Down Expand Up @@ -582,7 +579,7 @@ func (r *Runner) streamRsyncDelta(ctx context.Context, cfg *config.Config, remot
}
defer common.CloseWithErr(orig, &err, "close origin")

rw := writeOnlyReadWriter{remoteStdin}
rw := internalcommon.WriteOnlyReadWriter{Writer: remoteStdin}
cl := rsyncwire.NewClient(rsyncwire.NewStream(rw, maxFrame))
esc, err := privilege.New(ctx, logger)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions internal/common/writeonly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package common

import "io"

// WriteOnlyReadWriter wraps an io.Writer to satisfy io.ReadWriter.
type WriteOnlyReadWriter struct{ io.Writer }

// Read always returns io.EOF, making it safe to use where a read side is required.
func (WriteOnlyReadWriter) Read([]byte) (int, error) { return 0, io.EOF }
23 changes: 23 additions & 0 deletions internal/common/writeonly_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package common

import (
"bytes"
"io"
"testing"
)

func TestWriteOnlyReadWriter(t *testing.T) {
var buf bytes.Buffer
rw := WriteOnlyReadWriter{Writer: &buf}
if _, err := rw.Write([]byte("hello")); err != nil {
t.Fatalf("unexpected write error: %v", err)
}
b := make([]byte, 1)
n, err := rw.Read(b)
if n != 0 || err != io.EOF {
t.Fatalf("Read() = %d, %v; want 0, io.EOF", n, err)
}
if got := buf.String(); got != "hello" {
t.Fatalf("unexpected buffer content: %q", got)
}
}
7 changes: 2 additions & 5 deletions transfer/delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"lvmsync_go/common"
"lvmsync_go/dedup"
"lvmsync_go/device"
internalcommon "lvmsync_go/internal/common"
"lvmsync_go/internal/config"
digestpkg "lvmsync_go/internal/digest"
"lvmsync_go/internal/privilege"
Expand All @@ -22,10 +23,6 @@ import (

const rsyncMaxFrame = 1 << 20

type writeOnlyReadWriter struct{ io.Writer }

func (w writeOnlyReadWriter) Read([]byte) (int, error) { return 0, io.EOF }

// streamRsyncDelta performs a byte-level delta pre-pass using rsyncwire.
// It streams signatures and deltas followed by a digest frame.
// When out implements io.Closer, it is closed on completion.
Expand Down Expand Up @@ -57,7 +54,7 @@ func (t *Transfer) streamRsyncDelta(ctx context.Context, cfg *config.Config, sna
rwOK bool
)
if rw, rwOK = out.(io.ReadWriter); !rwOK {
rw = writeOnlyReadWriter{out}
rw = internalcommon.WriteOnlyReadWriter{Writer: out}
}
stream = rsyncwire.NewStream(rw, rsyncMaxFrame)
cl := rsyncwire.NewClient(stream)
Expand Down
Loading