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

# User Rev Content
1 root 1.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