1 |
#include "EXTERN.h" |
2 |
#include "perl.h" |
3 |
#include "XSUB.h" |
4 |
|
5 |
#include "rsync.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, off_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 : 0; |
278 |
OUTPUT: |
279 |
RETVAL |
280 |
|
281 |
int |
282 |
avail_out(self) |
283 |
File::Rdiff::Buffers self |
284 |
CODE: |
285 |
RETVAL = self->outsize - (self->out ? SvCUR (self->out) : 0); |
286 |
OUTPUT: |
287 |
RETVAL |
288 |
|
289 |
int |
290 |
size(self) |
291 |
File::Rdiff::Buffers self |
292 |
CODE: |
293 |
RETVAL = self->out ? SvCUR (self->out) : 0; |
294 |
OUTPUT: |
295 |
RETVAL |
296 |
|
297 |
MODULE = File::Rdiff PACKAGE = File::Rdiff::Job |
298 |
|
299 |
File::Rdiff::Job |
300 |
new_sig(class, new_block_len = RS_DEFAULT_BLOCK_LEN, strong_sum_len = RS_DEFAULT_STRONG_LEN) |
301 |
SV * class |
302 |
size_t new_block_len |
303 |
size_t strong_sum_len |
304 |
PROTOTYPE: $;$$ |
305 |
CODE: |
306 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
307 |
RETVAL->rs = rs_sig_begin (new_block_len, strong_sum_len); |
308 |
OUTPUT: |
309 |
RETVAL |
310 |
|
311 |
File::Rdiff::Job |
312 |
new_loadsig(class) |
313 |
SV * class |
314 |
CODE: |
315 |
rs_signature_t *sig; |
316 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
317 |
RETVAL->rs = rs_loadsig_begin (&sig); |
318 |
RETVAL->sig = new_sig (sig); |
319 |
OUTPUT: |
320 |
RETVAL |
321 |
|
322 |
File::Rdiff::Job |
323 |
new_delta(class, signature) |
324 |
SV * class |
325 |
SV * signature |
326 |
CODE: |
327 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
328 |
RETVAL->rs = rs_delta_begin (old_sig (signature)); |
329 |
RETVAL->sig = newSVsv (signature); |
330 |
OUTPUT: |
331 |
RETVAL |
332 |
|
333 |
File::Rdiff::Job |
334 |
new_patch(class, cb_or_fh) |
335 |
SV * class |
336 |
SV * cb_or_fh |
337 |
CODE: |
338 |
rs_copy_cb *cb; |
339 |
void *cb_arg; |
340 |
|
341 |
if (SvROK (cb_or_fh) && SvTYPE (SvRV (cb_or_fh)) == SVt_PVCV) |
342 |
{ |
343 |
cb = copy_cb; |
344 |
cb_arg = (void *)cb_or_fh; |
345 |
} |
346 |
else |
347 |
{ |
348 |
cb = rs_file_copy_cb; |
349 |
cb_arg = (void *)IoIFP (sv_2io (cb_or_fh)); |
350 |
} |
351 |
|
352 |
Newz (0, RETVAL, 1, struct File__Rdiff__Job); |
353 |
RETVAL->rs = rs_patch_begin (cb, cb_arg); |
354 |
OUTPUT: |
355 |
RETVAL |
356 |
|
357 |
void |
358 |
DESTROY(self) |
359 |
File::Rdiff::Job self |
360 |
CODE: |
361 |
if (self->sig) |
362 |
SvREFCNT_dec (self->sig); |
363 |
rs_job_free (self->rs); |
364 |
Safefree (self); |
365 |
|
366 |
SV * |
367 |
signature(self) |
368 |
File::Rdiff::Job self |
369 |
CODE: |
370 |
RETVAL = self->sig; |
371 |
OUTPUT: |
372 |
RETVAL |
373 |
|
374 |
int |
375 |
iter(self,buffers) |
376 |
File::Rdiff::Job self |
377 |
File::Rdiff::Buffers buffers |
378 |
CODE: |
379 |
{ |
380 |
STRLEN in_len; |
381 |
|
382 |
if (buffers->in) |
383 |
{ |
384 |
buffers->rs.next_in = SvPV (buffers->in, in_len) + buffers->in_ofs; |
385 |
buffers->rs.avail_in = in_len - buffers->in_ofs; |
386 |
} |
387 |
else |
388 |
{ |
389 |
buffers->rs.next_in = 0; |
390 |
buffers->rs.avail_in = 0; |
391 |
} |
392 |
|
393 |
if (!buffers->out) |
394 |
{ |
395 |
buffers->out = NEWSV (0, buffers->outsize); |
396 |
SvPOK_on (buffers->out); |
397 |
} |
398 |
|
399 |
buffers->rs.next_out = SvEND (buffers->out); |
400 |
buffers->rs.avail_out = buffers->outsize - SvCUR (buffers->out); |
401 |
|
402 |
RETVAL = rs_job_iter (self->rs, &buffers->rs); |
403 |
|
404 |
buffers->in_ofs = in_len - buffers->rs.avail_in; |
405 |
SvCUR_set (buffers->out, buffers->outsize - buffers->rs.avail_out); |
406 |
} |
407 |
OUTPUT: |
408 |
RETVAL |
409 |
|
410 |
# void rs_hexify(char *to_buf, void const *from_buf, int from_len); |
411 |
# size_t rs_unbase64(char *s); |
412 |
# void rs_base64(unsigned char const *buf, int n, char *out); |
413 |
# * \sa rs_format_stats(), rs_log_stats() |
414 |
# */ |
415 |
# typedef struct rs_stats { |
416 |
# char const *op; /**< Human-readable name of current |
417 |
# * operation. For example, "delta". */ |
418 |
# int lit_cmds; /**< Number of literal commands. */ |
419 |
# rs_long_t lit_bytes; /**< Number of literal bytes. */ |
420 |
# rs_long_t lit_cmdbytes; /**< Number of bytes used in literal |
421 |
# * command headers. */ |
422 |
# |
423 |
# rs_long_t copy_cmds, copy_bytes, copy_cmdbytes; |
424 |
# rs_long_t sig_cmds, sig_bytes; |
425 |
# int false_matches; |
426 |
# |
427 |
# rs_long_t sig_blocks; /**< Number of blocks described by the |
428 |
# signature. */ |
429 |
# |
430 |
# size_t block_len; |
431 |
# |
432 |
# rs_long_t in_bytes; /**< Total bytes read from input. */ |
433 |
# rs_long_t out_bytes; /**< Total bytes written to output. */ |
434 |
# } rs_stats_t; |
435 |
# |
436 |
# char *rs_format_stats(rs_stats_t const *, char *, size_t); |
437 |
# |
438 |
# int rs_log_stats(rs_stats_t const *stats); |
439 |
# |
440 |
# |
441 |
# /** |
442 |
# * Stream through which the calling application feeds data to and from the |
443 |
# * library. |
444 |
# * |
445 |
# * On each call to rs_job_iter, the caller can make available |
446 |
# * |
447 |
# * - avail_in bytes of input data at next_in |
448 |
# * - avail_out bytes of output space at next_out |
449 |
# * - some of both |
450 |
# * |
451 |
# * Buffers must be allocated and passed in by the caller. This |
452 |
# * routine never allocates, reallocates or frees buffers. |
453 |
# * |
454 |
# * Pay attention to the meaning of the returned pointer and length |
455 |
# * values. They do \b not indicate the location and amount of |
456 |
# * returned data. Rather, if \p *out_ptr was originally set to \p |
457 |
# * out_buf, then the output data begins at \p out_buf, and has length |
458 |
# * \p *out_ptr - \p out_buf. |
459 |
# * |
460 |
# * Note also that if \p *avail_in is nonzero on return, then not all of |
461 |
# * the input data has been consumed. The caller should either provide |
462 |
# * more output buffer space and call rs_work() again passing the same |
463 |
# * \p next_in and \p avail_in, or put the remaining input data into some |
464 |
# * persistent buffer and call rs_work() with it again when there is |
465 |
# * more output space. |
466 |
# * |
467 |
# * \param next_in References a pointer which on entry should point to |
468 |
# * the start of the data to be encoded. Updated to point to the byte |
469 |
# * after the last one consumed. |
470 |
# * |
471 |
# * \param avail_in References the length of available input. Updated to |
472 |
# * be the number of unused data bytes, which will be zero if all the |
473 |
# * input was consumed. May be zero if there is no new input, but the |
474 |
# * caller just wants to drain output. |
475 |
# * |
476 |
# * \param next_out References a pointer which on entry points to the |
477 |
# * start of the output buffer. Updated to point to the byte after the |
478 |
# * last one filled. |
479 |
# * |
480 |
# * \param avail_out References the size of available output buffer. |
481 |
# * Updated to the size of unused output buffer. |
482 |
# * |
483 |
# * \return The ::rs_result that caused iteration to stop. |
484 |
# * |
485 |
# * \sa rs_buffers_t |
486 |
# * \sa \ref api_buffers |
487 |
# */ |
488 |
# struct rs_buffers_s { |
489 |
# char *next_in; /**< Next input byte */ |
490 |
# size_t avail_in; /**< Number of bytes available at next_in */ |
491 |
# int eof_in; /**< True if there is no more data |
492 |
# * after this. */ |
493 |
# |
494 |
# char *next_out; /**< Next output byte should be put there */ |
495 |
# size_t avail_out; /**< Remaining free space at next_out */ |
496 |
# }; |
497 |
# |
498 |
# /** |
499 |
# * Stream through which the calling application feeds data to and from the |
500 |
# * library. |
501 |
# * |
502 |
# * \sa struct rs_buffers_s |
503 |
# * \sa \ref api_buffers |
504 |
# */ |
505 |
# typedef struct rs_buffers_s rs_buffers_t; |
506 |
# |
507 |
# /** Default length of strong signatures, in bytes. The MD4 checksum |
508 |
# * is truncated to this size. */ |
509 |
# #define RS_DEFAULT_STRONG_LEN 8 |
510 |
# |
511 |
# /** Default block length, if not determined by any other factors. */ |
512 |
# #define RS_DEFAULT_BLOCK_LEN 2048 |
513 |
# |
514 |
# |
515 |
# |
516 |
# /** \typedef struct rs_job rs_job_t |
517 |
# * |
518 |
# * \brief Job of work to be done. |
519 |
# * |
520 |
# * Created by functions such as rs_sig_begin(), and then iterated |
521 |
# * over by rs_job_iter(). */ |
522 |
# typedef struct rs_job rs_job_t; |
523 |
# |
524 |
# /** |
525 |
# * Bitmask values that may be passed to the options parameter of |
526 |
# * rs_work(). |
527 |
# */ |
528 |
# typedef enum rs_work_options { |
529 |
# RS_END = 0x01 /**< End of input file; please finish |
530 |
# * up. */ |
531 |
# } rs_work_options; |
532 |
# |
533 |
# |
534 |
# rs_result rs_job_iter(rs_job_t *, rs_buffers_t *); |
535 |
# |
536 |
# const rs_stats_t * rs_job_statistics(rs_job_t *job); |
537 |
# |
538 |
# rs_result rs_job_free(rs_job_t *); |
539 |
# |
540 |
# int rs_accum_value(rs_job_t *, char *sum, size_t sum_len); |
541 |
# |
542 |
|
543 |
MODULE = File::Rdiff PACKAGE = File::Rdiff |
544 |
|
545 |
#ifndef RSYNC_NO_STDIO_INTERFACE |
546 |
|
547 |
int |
548 |
sig_file(old_file, sig_file, block_len = RS_DEFAULT_BLOCK_LEN, strong_len = RS_DEFAULT_STRONG_LEN) |
549 |
FILE * old_file |
550 |
FILE * sig_file |
551 |
size_t block_len |
552 |
size_t strong_len |
553 |
PROTOTYPE: $$;$$ |
554 |
CODE: |
555 |
RETVAL = rs_sig_file(old_file, sig_file, block_len, strong_len, 0); |
556 |
OUTPUT: |
557 |
RETVAL |
558 |
|
559 |
File::Rdiff::Signature |
560 |
loadsig_file(file) |
561 |
FILE * file |
562 |
CODE: |
563 |
rs_result r = rs_loadsig_file(file, &RETVAL, 0); |
564 |
if (r != RS_DONE) |
565 |
XSRETURN_IV (r); |
566 |
OUTPUT: |
567 |
RETVAL |
568 |
|
569 |
int |
570 |
delta_file(signature, new_file, delta_file) |
571 |
File::Rdiff::Signature signature |
572 |
FILE * new_file |
573 |
FILE * delta_file |
574 |
CODE: |
575 |
RETVAL = rs_delta_file (signature, new_file, delta_file, 0); |
576 |
OUTPUT: |
577 |
RETVAL |
578 |
|
579 |
int |
580 |
patch_file(basis_file, delta_file, new_file) |
581 |
FILE * basis_file |
582 |
FILE * delta_file |
583 |
FILE * new_file |
584 |
CODE: |
585 |
RETVAL = rs_patch_file (basis_file, delta_file, new_file, 0); |
586 |
OUTPUT: |
587 |
RETVAL |
588 |
|
589 |
#endif |
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|