1 |
#include "EXTERN.h" |
2 |
#include "perl.h" |
3 |
#include "XSUB.h" |
4 |
|
5 |
#include "librsync.h" |
6 |
|
7 |
/* try to be compatible with older perls */ |
8 |
/* SvPV_nolen() macro first defined in 5.005_55 */ |
9 |
/* this is slow, not threadsafe, but works */ |
10 |
#include "patchlevel.h" |
11 |
#if (PATCHLEVEL == 4) || ((PATCHLEVEL == 5) && (SUBVERSION < 55)) |
12 |
static STRLEN nolen_na; |
13 |
# define SvPV_nolen(sv) SvPV ((sv), nolen_na) |
14 |
#endif |
15 |
|
16 |
static SV *trace_cb_sv; |
17 |
|
18 |
typedef rs_stats_t * File__Rdiff__Stats; |
19 |
typedef rs_signature_t *File__Rdiff__Signature; |
20 |
|
21 |
typedef struct File__Rdiff__Buffers { |
22 |
rs_buffers_t rs; |
23 |
SV *in; |
24 |
STRLEN in_ofs; |
25 |
SV *out; |
26 |
STRLEN outsize; |
27 |
} *File__Rdiff__Buffers; |
28 |
|
29 |
typedef struct File__Rdiff__Job { |
30 |
rs_job_t *rs; |
31 |
SV *sig; |
32 |
} *File__Rdiff__Job; |
33 |
|
34 |
static SV *new_sig (File__Rdiff__Signature sig) |
35 |
{ |
36 |
SV *sv = NEWSV (0, 0); |
37 |
sv_setref_pv (sv, "File::Rdiff::Signature", (void *)sig); |
38 |
|
39 |
return sv; |
40 |
} |
41 |
|
42 |
static File__Rdiff__Signature |
43 |
old_sig (SV *sv) |
44 |
{ |
45 |
if (sv_derived_from(sv, "File::Rdiff::Signature")) |
46 |
{ |
47 |
IV tmp = SvIV((SV*)SvRV(sv)); |
48 |
return INT2PTR(rs_signature_t *,tmp); |
49 |
} |
50 |
else |
51 |
Perl_croak(aTHX_ "Object of type File::Rdiff::Signature expected"); |
52 |
} |
53 |
|
54 |
static void |
55 |
trace_cb (int level, char const *msg) |
56 |
{ |
57 |
if (SvOK (trace_cb_sv)) |
58 |
{ |
59 |
dSP; |
60 |
|
61 |
SAVETMPS; PUSHMARK(SP); EXTEND(SP,2); |
62 |
|
63 |
PUSHs(sv_2mortal(newSViv(level))); |
64 |
PUSHs(sv_2mortal(newSVpv(msg,0))); |
65 |
|
66 |
PUTBACK; perl_call_sv (trace_cb_sv, G_VOID|G_DISCARD); SPAGAIN; |
67 |
|
68 |
PUTBACK; FREETMPS; |
69 |
} |
70 |
else |
71 |
rs_trace_stderr (level, msg); |
72 |
} |
73 |
|
74 |
/** |
75 |
* \brief Callback used to retrieve parts of the basis file. |
76 |
* |
77 |
* \param pos Position where copying should begin. |
78 |
* |
79 |
* \param len On input, the amount of data that should be retrieved. |
80 |
* Updated to show how much is actually available. |
81 |
* |
82 |
* \param buf On input, a buffer of at least \p *len bytes. May be |
83 |
* updated to point to a buffer allocated by the callback if it |
84 |
* prefers. |
85 |
*/ |
86 |
static rs_result |
87 |
copy_cb (void *cb, rs_long_t pos, size_t *len, void **buf) |
88 |
{ |
89 |
dSP; |
90 |
SV *rbuf; |
91 |
|
92 |
PUSHMARK(SP); EXTEND(SP,2); |
93 |
|
94 |
PUSHs(sv_2mortal(newSViv(pos))); |
95 |
PUSHs(sv_2mortal(newSViv(*len))); |
96 |
|
97 |
PUTBACK; perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN; |
98 |
|
99 |
rbuf = POPs; |
100 |
|
101 |
PUTBACK; |
102 |
|
103 |
if (SvIOKp (rbuf) && !SvPOKp (rbuf)) |
104 |
{ |
105 |
/* assume error code */ |
106 |
return SvIVX (rbuf); |
107 |
} |
108 |
else |
109 |
{ |
110 |
/* assume data. we are not copying because we assume |
111 |
* that the data will be consumed before the next FREETMPS, |
112 |
* which should be just outside ther rs_job_iter call. |
113 |
*/ |
114 |
STRLEN slen; |
115 |
|
116 |
*buf = SvPV (rbuf, slen); |
117 |
*len = slen; |
118 |
|
119 |
return RS_DONE; |
120 |
} |
121 |
} |
122 |
|
123 |
MODULE = File::Rdiff PACKAGE = File::Rdiff |
124 |
|
125 |
PROTOTYPES: ENABLE |
126 |
|
127 |
BOOT: |
128 |
{ |
129 |
HV * stash = gv_stashpv ("File::Rdiff", 0); |
130 |
|
131 |
trace_cb_sv = newSVsv (&PL_sv_undef); |
132 |
|
133 |
rs_trace_to (trace_cb); |
134 |
rs_trace_set_level (RS_LOG_WARNING); |
135 |
|
136 |
newCONSTSUB (stash, "LIBRSYNC_VERSION", newSVpv (rs_librsync_version, 0)); |
137 |
|
138 |
newCONSTSUB (stash, "LOG_EMERG", newSViv (RS_LOG_EMERG)); |
139 |
newCONSTSUB (stash, "LOG_ALERT", newSViv (RS_LOG_ALERT)); |
140 |
newCONSTSUB (stash, "LOG_CRIT", newSViv (RS_LOG_CRIT)); |
141 |
newCONSTSUB (stash, "LOG_ERR", newSViv (RS_LOG_ERR)); |
142 |
newCONSTSUB (stash, "LOG_WARNING", newSViv (RS_LOG_WARNING)); |
143 |
newCONSTSUB (stash, "LOG_NOTICE", newSViv (RS_LOG_NOTICE)); |
144 |
newCONSTSUB (stash, "LOG_INFO", newSViv (RS_LOG_INFO)); |
145 |
newCONSTSUB (stash, "LOG_DEBUG", newSViv (RS_LOG_DEBUG)); |
146 |
newCONSTSUB (stash, "DONE", newSViv (RS_DONE)); |
147 |
newCONSTSUB (stash, "BLOCKED", newSViv (RS_BLOCKED)); |
148 |
newCONSTSUB (stash, "RUNNING", newSViv (RS_RUNNING)); |
149 |
newCONSTSUB (stash, "TEST_SKIPPED", newSViv (RS_TEST_SKIPPED)); |
150 |
newCONSTSUB (stash, "IO_ERROR", newSViv (RS_IO_ERROR)); |
151 |
newCONSTSUB (stash, "SYNTAX_ERROR", newSViv (RS_SYNTAX_ERROR)); |
152 |
newCONSTSUB (stash, "MEM_ERROR", newSViv (RS_MEM_ERROR)); |
153 |
newCONSTSUB (stash, "INPUT_ENDED", newSViv (RS_INPUT_ENDED)); |
154 |
newCONSTSUB (stash, "BAD_MAGIC", newSViv (RS_BAD_MAGIC)); |
155 |
newCONSTSUB (stash, "UNIMPLEMENTED", newSViv (RS_UNIMPLEMENTED)); |
156 |
newCONSTSUB (stash, "CORRUPT", newSViv (RS_CORRUPT)); |
157 |
newCONSTSUB (stash, "INTERNAL_ERROR", newSViv (RS_INTERNAL_ERROR)); |
158 |
newCONSTSUB (stash, "PARAM_ERROR", newSViv (RS_PARAM_ERROR)); |
159 |
} |
160 |
|
161 |
int |
162 |
trace_level(level) |
163 |
int level |
164 |
PROTOTYPE: ;$ |
165 |
CODE: |
166 |
static int oldlevel = RS_LOG_WARNING; /* see BOOT: */ |
167 |
|
168 |
RETVAL = oldlevel; |
169 |
if (items) |
170 |
{ |
171 |
oldlevel = level; |
172 |
rs_trace_set_level (level); |
173 |
} |
174 |
OUTPUT: |
175 |
RETVAL |
176 |
|
177 |
SV * |
178 |
trace_to(cb) |
179 |
SV * cb |
180 |
PROTOTYPE: ;& |
181 |
CODE: |
182 |
RETVAL = sv_2mortal (newSVsv (trace_cb_sv)); |
183 |
if (items) |
184 |
sv_setsv (trace_cb_sv, cb); |
185 |
OUTPUT: |
186 |
RETVAL |
187 |
|
188 |
void |
189 |
supports_trace() |
190 |
PROTOTYPE: |
191 |
CODE: |
192 |
if (rs_supports_trace()) |
193 |
XSRETURN_YES; |
194 |
else |
195 |
XSRETURN_NO; |
196 |
|
197 |
SV * |
198 |
strerror (resultcode) |
199 |
int resultcode |
200 |
CODE: |
201 |
RETVAL = newSVpv (rs_strerror (resultcode), 0); |
202 |
OUTPUT: |
203 |
RETVAL |
204 |
|
205 |
MODULE = File::Rdiff PACKAGE = File::Rdiff::Signature |
206 |
|
207 |
int |
208 |
build_hash_table(self) |
209 |
File::Rdiff::Signature self |
210 |
CODE: |
211 |
RETVAL = rs_build_hash_table (self); |
212 |
OUTPUT: |
213 |
RETVAL |
214 |
|
215 |
void |
216 |
DESTROY(self) |
217 |
File::Rdiff::Signature self |
218 |
CODE: |
219 |
rs_free_sumset (self); |
220 |
|
221 |
void |
222 |
dump(self) |
223 |
File::Rdiff::Signature self |
224 |
CODE: |
225 |
rs_sumset_dump (self); |
226 |
|
227 |
MODULE = File::Rdiff PACKAGE = File::Rdiff::Buffers |
228 |
|
229 |
File::Rdiff::Buffers |
230 |
new(class, outsize = 65536) |
231 |
SV * class |
232 |
STRLEN outsize |
233 |
PROTOTYPE: $;$$ |
234 |
CODE: |
235 |
Newz (0, RETVAL, 1, struct File__Rdiff__Buffers); |
236 |
RETVAL->outsize = outsize; |
237 |
OUTPUT: |
238 |
RETVAL |
239 |
|
240 |
void |
241 |
DESTROY(self) |
242 |
File::Rdiff::Buffers self |
243 |
CODE: |
244 |
if (self->in ) SvREFCNT_dec (self->in ); |
245 |
if (self->out) SvREFCNT_dec (self->out); |
246 |
Safefree (self); |
247 |
|
248 |
void |
249 |
in(self,in) |
250 |
File::Rdiff::Buffers self |
251 |
SV * in |
252 |
CODE: |
253 |
if (self->in) |
254 |
SvREFCNT_dec (self->in); |
255 |
self->in = SvREFCNT_inc (in); |
256 |
self->in_ofs = 0; |
257 |
|
258 |
void |
259 |
eof(self) |
260 |
File::Rdiff::Buffers self |
261 |
CODE: |
262 |
self->rs.eof_in = 1; |
263 |
|
264 |
SV * |
265 |
out(self) |
266 |
File::Rdiff::Buffers self |
267 |
CODE: |
268 |
RETVAL = self->out; |
269 |
self->out = 0; |
270 |
OUTPUT: |
271 |
RETVAL |
272 |
|
273 |
int |
274 |
avail_in(self) |
275 |
File::Rdiff::Buffers self |
276 |
CODE: |
277 |
RETVAL = self->in ? SvCUR (self->in) - self->in_ofs |
278 |
: self->rs.eof_in ? -1 |
279 |
: 0; |
280 |
OUTPUT: |
281 |
RETVAL |
282 |
|
283 |
int |
284 |
avail_out(self) |
285 |
File::Rdiff::Buffers self |
286 |
CODE: |
287 |
RETVAL = self->outsize - (self->out ? SvCUR (self->out) : 0); |
288 |
OUTPUT: |
289 |
RETVAL |
290 |
|
291 |
int |
292 |
size(self) |
293 |
File::Rdiff::Buffers self |
294 |
CODE: |
295 |
RETVAL = self->out ? SvCUR (self->out) : 0; |
296 |
OUTPUT: |
297 |
RETVAL |
298 |
|
299 |
MODULE = File::Rdiff PACKAGE = File::Rdiff::Job |
300 |
|
301 |
File::Rdiff::Job |
302 |
new_sig(class, new_block_len = RS_DEFAULT_BLOCK_LEN, strong_sum_len = RS_DEFAULT_STRONG_LEN) |
303 |
SV * class |
304 |
size_t new_block_len |
305 |
size_t strong_sum_len |
306 |
PROTOTYPE: $;$$ |
307 |
CODE: |
308 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
309 |
RETVAL->rs = rs_sig_begin (new_block_len, strong_sum_len); |
310 |
OUTPUT: |
311 |
RETVAL |
312 |
|
313 |
File::Rdiff::Job |
314 |
new_loadsig(class) |
315 |
SV * class |
316 |
CODE: |
317 |
rs_signature_t *sig; |
318 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
319 |
RETVAL->rs = rs_loadsig_begin (&sig); |
320 |
RETVAL->sig = new_sig (sig); |
321 |
OUTPUT: |
322 |
RETVAL |
323 |
|
324 |
File::Rdiff::Job |
325 |
new_delta(class, signature) |
326 |
SV * class |
327 |
SV * signature |
328 |
CODE: |
329 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
330 |
RETVAL->rs = rs_delta_begin (old_sig (signature)); |
331 |
RETVAL->sig = newSVsv (signature); |
332 |
OUTPUT: |
333 |
RETVAL |
334 |
|
335 |
File::Rdiff::Job |
336 |
new_patch(class, cb_or_fh) |
337 |
SV * class |
338 |
SV * cb_or_fh |
339 |
CODE: |
340 |
rs_copy_cb *cb; |
341 |
void *cb_arg; |
342 |
|
343 |
if (SvROK (cb_or_fh) && SvTYPE (SvRV (cb_or_fh)) == SVt_PVCV) |
344 |
{ |
345 |
cb = copy_cb; |
346 |
cb_arg = (void *)cb_or_fh; |
347 |
} |
348 |
else |
349 |
{ |
350 |
cb = rs_file_copy_cb; |
351 |
cb_arg = (void *)IoIFP (sv_2io (cb_or_fh)); |
352 |
} |
353 |
|
354 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
355 |
RETVAL->rs = rs_patch_begin (cb, cb_arg); |
356 |
OUTPUT: |
357 |
RETVAL |
358 |
|
359 |
void |
360 |
DESTROY(self) |
361 |
File::Rdiff::Job self |
362 |
CODE: |
363 |
if (self->sig) |
364 |
SvREFCNT_dec (self->sig); |
365 |
rs_job_free (self->rs); |
366 |
Safefree (self); |
367 |
|
368 |
SV * |
369 |
signature(self) |
370 |
File::Rdiff::Job self |
371 |
CODE: |
372 |
RETVAL = SvREFCNT_inc (self->sig); |
373 |
OUTPUT: |
374 |
RETVAL |
375 |
|
376 |
int |
377 |
iter(self,buffers) |
378 |
File::Rdiff::Job self |
379 |
File::Rdiff::Buffers buffers |
380 |
CODE: |
381 |
{ |
382 |
STRLEN in_len; |
383 |
|
384 |
if (buffers->in) |
385 |
{ |
386 |
buffers->rs.next_in = SvPV (buffers->in, in_len) + buffers->in_ofs; |
387 |
buffers->rs.avail_in = in_len - buffers->in_ofs; |
388 |
} |
389 |
else |
390 |
{ |
391 |
buffers->rs.next_in = 0; |
392 |
buffers->rs.avail_in = 0; |
393 |
} |
394 |
|
395 |
if (buffers->outsize) |
396 |
{ |
397 |
if (!buffers->out) |
398 |
{ |
399 |
buffers->out = NEWSV (0, buffers->outsize); |
400 |
SvPOK_on (buffers->out); |
401 |
} |
402 |
|
403 |
buffers->rs.next_out = SvEND (buffers->out); |
404 |
buffers->rs.avail_out = buffers->outsize - SvCUR (buffers->out); |
405 |
} |
406 |
else |
407 |
{ |
408 |
buffers->rs.next_out = 0; |
409 |
buffers->rs.avail_out = 0; |
410 |
} |
411 |
|
412 |
RETVAL = rs_job_iter (self->rs, &buffers->rs); |
413 |
|
414 |
buffers->in_ofs = in_len - buffers->rs.avail_in; |
415 |
|
416 |
if (buffers->out) |
417 |
SvCUR_set (buffers->out, buffers->outsize - buffers->rs.avail_out); |
418 |
} |
419 |
OUTPUT: |
420 |
RETVAL |
421 |
|
422 |
# void rs_hexify(char *to_buf, void const *from_buf, int from_len); |
423 |
# size_t rs_unbase64(char *s); |
424 |
# void rs_base64(unsigned char const *buf, int n, char *out); |
425 |
# * \sa rs_format_stats(), rs_log_stats() |
426 |
# */ |
427 |
# typedef struct rs_stats { |
428 |
# char const *op; /**< Human-readable name of current |
429 |
# * operation. For example, "delta". */ |
430 |
# int lit_cmds; /**< Number of literal commands. */ |
431 |
# rs_long_t lit_bytes; /**< Number of literal bytes. */ |
432 |
# rs_long_t lit_cmdbytes; /**< Number of bytes used in literal |
433 |
# * command headers. */ |
434 |
# |
435 |
# rs_long_t copy_cmds, copy_bytes, copy_cmdbytes; |
436 |
# rs_long_t sig_cmds, sig_bytes; |
437 |
# int false_matches; |
438 |
# |
439 |
# rs_long_t sig_blocks; /**< Number of blocks described by the |
440 |
# signature. */ |
441 |
# |
442 |
# size_t block_len; |
443 |
# |
444 |
# rs_long_t in_bytes; /**< Total bytes read from input. */ |
445 |
# rs_long_t out_bytes; /**< Total bytes written to output. */ |
446 |
# } rs_stats_t; |
447 |
# |
448 |
# char *rs_format_stats(rs_stats_t const *, char *, size_t); |
449 |
# |
450 |
# int rs_log_stats(rs_stats_t const *stats); |
451 |
# |
452 |
# const rs_stats_t * rs_job_statistics(rs_job_t *job); |
453 |
# |
454 |
# int rs_accum_value(rs_job_t *, char *sum, size_t sum_len); |
455 |
# |
456 |
|
457 |
MODULE = File::Rdiff PACKAGE = File::Rdiff |
458 |
|
459 |
#ifndef RSYNC_NO_STDIO_INTERFACE |
460 |
|
461 |
int |
462 |
sig_file(old_file, sig_file, block_len = RS_DEFAULT_BLOCK_LEN, strong_len = RS_DEFAULT_STRONG_LEN) |
463 |
FILE * old_file |
464 |
FILE * sig_file |
465 |
size_t block_len |
466 |
size_t strong_len |
467 |
PROTOTYPE: $$;$$ |
468 |
CODE: |
469 |
RETVAL = rs_sig_file(old_file, sig_file, block_len, strong_len, 0); |
470 |
OUTPUT: |
471 |
RETVAL |
472 |
|
473 |
File::Rdiff::Signature |
474 |
loadsig_file(file) |
475 |
FILE * file |
476 |
CODE: |
477 |
rs_result r = rs_loadsig_file(file, &RETVAL, 0); |
478 |
if (r != RS_DONE) |
479 |
XSRETURN_IV (r); |
480 |
OUTPUT: |
481 |
RETVAL |
482 |
|
483 |
int |
484 |
delta_file(signature, new_file, delta_file) |
485 |
File::Rdiff::Signature signature |
486 |
FILE * new_file |
487 |
FILE * delta_file |
488 |
CODE: |
489 |
RETVAL = rs_delta_file (signature, new_file, delta_file, 0); |
490 |
OUTPUT: |
491 |
RETVAL |
492 |
|
493 |
int |
494 |
patch_file(basis_file, delta_file, new_file) |
495 |
FILE * basis_file |
496 |
FILE * delta_file |
497 |
FILE * new_file |
498 |
CODE: |
499 |
RETVAL = rs_patch_file (basis_file, delta_file, new_file, 0); |
500 |
OUTPUT: |
501 |
RETVAL |
502 |
|
503 |
#endif |
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|