ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/File-Rdiff/Rdiff.xs
Revision: 1.1
Committed: Thu Mar 21 23:49:01 2002 UTC (22 years, 2 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
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