diff options
| -rw-r--r-- | librsync/librsync.go | 67 | ||||
| -rw-r--r-- | librsync/signature_test.go | 20 | 
2 files changed, 86 insertions, 1 deletions
| diff --git a/librsync/librsync.go b/librsync/librsync.go index 5d51c10..e154da6 100644 --- a/librsync/librsync.go +++ b/librsync/librsync.go @@ -108,7 +108,25 @@ func (job *Job) Close() error {  	return nil  } +// For errors in callbacks +type jobInternalPanic struct { +	err error +} + +func (jp jobInternalPanic) Error() string { return jp.err.Error() } +  func jobIter(job *C.rs_job_t, rsbufs *C.rs_buffers_t) (running bool, err error) { +	defer func() { +		r := recover() +		jp, ok := r.(jobInternalPanic) +		if !ok { +			panic(r) +		} + +		running = false +		err = jp.err +	}() +  	switch res := C.rs_job_iter(job, rsbufs); res {  	case C.RS_DONE:  	case C.RS_BLOCKED: @@ -243,3 +261,52 @@ func NewDeltaGen(sig Signature, input io.Reader) (job *Job, err error) {  	return  } + +// Patcher is a job with additional hidden data for patching. +//  +// IMPORTANT: You still need to Close() this! +type Patcher struct { +	*Job +	base io.ReaderAt +	buf  []byte +} + +func _patch_callback(_patcher unsafe.Pointer, pos C.rs_long_t, len *C.size_t, _buf *unsafe.Pointer) C.rs_result { +	patcher := (*Patcher)(_patcher) + +	patcher.buf = make([]byte, int(*len)) +	n, err := patcher.base.ReadAt(patcher.buf, int64(pos)) +	if n < int(*len) { +		if err != io.EOF { +			panic(jobInternalPanic{err}) +		} else { +			return C.RS_INPUT_ENDED +		} +	} +	*len = C.size_t(n) +	*_buf = unsafe.Pointer(&(patcher.buf[0])) + +	return C.RS_DONE +} + +var patch_callback = _patch_callback // So we can use the `&` operator in NewPatcher + +func NewPatcher(delta io.Reader, base io.ReaderAt) (job *Patcher, err error) { +	_job, e := newJob(delta) +	if e != nil { +		err = e +		return +	} + +	job = &Patcher{ +		Job:  _job, +		base: base} + +	job.job = C.rs_patch_begin((*C.rs_copy_cb)(unsafe.Pointer(&patch_callback)), unsafe.Pointer(job)) +	if job.job == nil { +		job.Close() +		return nil, errors.New("rs_patch_begin failed") +	} + +	return +} diff --git a/librsync/signature_test.go b/librsync/signature_test.go index 152fd12..e0fd50f 100644 --- a/librsync/signature_test.go +++ b/librsync/signature_test.go @@ -76,5 +76,23 @@ func TestSignatureDeltaPatch(t *testing.T) {  		}  	} -	// TODO: Test patching +	// Apply Patch  +	patchres := new(bytes.Buffer) +	patcher, err := NewPatcher(deltabuf, orig) +	if err != nil { +		t.Fatalf("could not create a patcher: %s", err) +	} +	defer patcher.Close() + +	if _, err = io.Copy(patchres, patcher); err != nil { +		t.Fatalf("Applying the patch failed: %s", err) +	} + +	if !bytes.Equal(patchres.Bytes(), testdata.Mutation()) { +		if path, err := dump(patchres); err == nil { +			t.Fatalf("patch result and mutation are not equal. Result dumped to %s", path) +		} else { +			t.Fatalf("patch result and mutation are not equal. Could not dump result: %s", err) +		} +	}  } | 
