… | |
… | |
6 | |
6 | |
7 | use File::Rdiff |
7 | use File::Rdiff |
8 | |
8 | |
9 | =head1 DESCRIPTION |
9 | =head1 DESCRIPTION |
10 | |
10 | |
11 | A more-or-less direct interface to librsync (L<http://rproxy.samba.org>). |
11 | A more-or-less direct interface to librsync (L<http://librsync.sourceforge.net/>). |
12 | |
12 | |
13 | For usage examples (better than this very sparse documentation), see the |
13 | For usage examples (better than this very sparse documentation), see the |
14 | two example scripts rdiff1 and rdiff2 that came with the distribution. |
14 | two example scripts below. |
15 | |
15 | |
16 | =over 4 |
16 | =over 4 |
17 | |
17 | |
18 | =cut |
18 | =cut |
19 | |
19 | |
20 | package File::Rdiff; |
20 | package File::Rdiff; |
21 | |
21 | |
22 | require DynaLoader; |
22 | require DynaLoader; |
23 | require Exporter; |
23 | require Exporter; |
24 | |
24 | |
25 | $VERSION = 0.02; |
25 | $VERSION = '1.0'; |
26 | @ISA = qw/DynaLoader Exporter/; |
26 | @ISA = qw/DynaLoader Exporter/; |
27 | |
27 | |
28 | bootstrap File::Rdiff $VERSION; |
28 | bootstrap File::Rdiff $VERSION; |
29 | |
29 | |
30 | { |
30 | { |
… | |
… | |
178 | |
178 | |
179 | Only valid for C<new_loadsig>, so look there. |
179 | Only valid for C<new_loadsig>, so look there. |
180 | |
180 | |
181 | =back |
181 | =back |
182 | |
182 | |
|
|
183 | =head1 EXAMPLE PROGRAM ONE |
|
|
184 | |
|
|
185 | Very simple program that mimics librsync's rdiff, using the simple file |
|
|
186 | utility functions. see example below for the same program, written using |
|
|
187 | the nonblocking API. |
|
|
188 | |
|
|
189 | #!/usr/bin/perl |
|
|
190 | |
|
|
191 | use File::Rdiff qw(:trace :file); |
|
|
192 | |
|
|
193 | trace_level(LOG_INFO); |
|
|
194 | |
|
|
195 | if ($ARGV[0] eq "signature") { |
|
|
196 | open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; |
|
|
197 | open $sig, ">$ARGV[2]" or die "$ARGV[2]: $!"; |
|
|
198 | |
|
|
199 | File::Rdiff::sig_file $base, $sig; |
|
|
200 | } elsif ($ARGV[0] eq "delta") { |
|
|
201 | open $sig, "<$ARGV[1]" or die "$ARGV[1]: $!"; |
|
|
202 | open $new, "<$ARGV[2]" or die "$ARGV[2]: $!"; |
|
|
203 | open $delta, ">$ARGV[3]" or die "$ARGV[3]: $!"; |
|
|
204 | |
|
|
205 | $sig = loadsig_file $sig; |
|
|
206 | |
|
|
207 | ref $sig or exit 1; |
|
|
208 | |
|
|
209 | $sig->build_hash_table; |
|
|
210 | |
|
|
211 | File::Rdiff::delta_file $sig, $new, $delta; |
|
|
212 | } elsif ($ARGV[0] eq "patch") { |
|
|
213 | open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; |
|
|
214 | open $delta, "<$ARGV[2]" or die "$ARGV[2]: $!"; |
|
|
215 | open $new, ">$ARGV[3]" or die "$ARGV[3]: $!"; |
|
|
216 | |
|
|
217 | File::Rdiff::patch_file $base, $delta, $new; |
|
|
218 | } else { |
|
|
219 | print <<EOF; |
|
|
220 | $0 signature BASE SIGNATURE |
|
|
221 | $0 delta SIGNATURE NEW DELTA |
|
|
222 | $0 patch BASE DELTA NEW |
|
|
223 | EOF |
|
|
224 | exit (1); |
|
|
225 | } |
|
|
226 | |
|
|
227 | =head1 EXAMPLE PROGRAM TWO |
|
|
228 | |
|
|
229 | Same as above, but written using the callback-based, "nonblocking", API. |
|
|
230 | |
|
|
231 | #!/usr/bin/perl |
|
|
232 | |
|
|
233 | use File::Rdiff qw(:trace :nonblocking); |
|
|
234 | |
|
|
235 | trace_level(LOG_INFO); |
|
|
236 | |
|
|
237 | if ($ARGV[0] eq "signature") { |
|
|
238 | open $basis, "<", $ARGV[1] |
|
|
239 | or die "$ARGV[1]: $!"; |
|
|
240 | open $sig, ">", $ARGV[2] |
|
|
241 | or die "$ARGV[2]: $!"; |
|
|
242 | |
|
|
243 | my $job = new_sig File::Rdiff::Job 128; |
|
|
244 | my $buf = new File::Rdiff::Buffers 4096; |
|
|
245 | |
|
|
246 | while ($job->iter($buf) == BLOCKED) { |
|
|
247 | # fetch more input data |
|
|
248 | $buf->avail_in or do { |
|
|
249 | my $in; |
|
|
250 | 65536 == sysread $basis, $in, 65536 or $buf->eof; |
|
|
251 | $buf->in($in); |
|
|
252 | }; |
|
|
253 | print $sig $buf->out; |
|
|
254 | } |
|
|
255 | print $sig $buf->out; |
|
|
256 | |
|
|
257 | } elsif ($ARGV[0] eq "delta") { |
|
|
258 | open $sig, "<$ARGV[1]" or die "$ARGV[1]: $!"; |
|
|
259 | open $new, "<$ARGV[2]" or die "$ARGV[2]: $!"; |
|
|
260 | open $delta, ">$ARGV[3]" or die "$ARGV[3]: $!"; |
|
|
261 | |
|
|
262 | # first load the signature into memory |
|
|
263 | my $job = new_loadsig File::Rdiff::Job; |
|
|
264 | my $buf = new File::Rdiff::Buffers 0; |
|
|
265 | |
|
|
266 | do { |
|
|
267 | $buf->avail_in or do { |
|
|
268 | my $in; |
|
|
269 | 65536 == sysread $sig, $in, 65536 or $buf->eof; |
|
|
270 | $buf->in($in); |
|
|
271 | }; |
|
|
272 | } while $job->iter($buf) == BLOCKED; |
|
|
273 | |
|
|
274 | $sig = $job->signature; |
|
|
275 | |
|
|
276 | $sig->build_hash_table; |
|
|
277 | |
|
|
278 | # now create the delta file |
|
|
279 | my $job = new_delta File::Rdiff::Job $sig; |
|
|
280 | my $buf = new File::Rdiff::Buffers 65536; |
|
|
281 | |
|
|
282 | do { |
|
|
283 | $buf->avail_in or do { |
|
|
284 | my $in; |
|
|
285 | 65536 == sysread $new, $in, 65536 or $buf->eof; |
|
|
286 | $buf->in($in); |
|
|
287 | }; |
|
|
288 | print $delta $buf->out; |
|
|
289 | } while $job->iter($buf) == BLOCKED; |
|
|
290 | print $delta $buf->out; |
|
|
291 | |
|
|
292 | } elsif ($ARGV[0] eq "patch") { |
|
|
293 | open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; |
|
|
294 | open $delta, "<$ARGV[2]" or die "$ARGV[2]: $!"; |
|
|
295 | open $new, ">$ARGV[3]" or die "$ARGV[3]: $!"; |
|
|
296 | |
|
|
297 | # NYI |
|
|
298 | File::Rdiff::patch_file $base, $delta, $new; |
|
|
299 | } else { |
|
|
300 | print <<EOF; |
|
|
301 | $0 signature BASIS SIGNATURE |
|
|
302 | $0 delta SIGNATURE NEW DELTA |
|
|
303 | $0 patch BASE DELTA NEW |
|
|
304 | EOF |
|
|
305 | exit (1); |
|
|
306 | } |
|
|
307 | |
183 | =head1 SEE ALSO |
308 | =head1 SEE ALSO |
184 | |
309 | |
185 | L<File::Rsync>, L<rdiff1> (usage example using simple file API), L<rdiff2> (example using nonblocking API). |
310 | L<File::Rsync>, L<rdiff1> (usage example using simple file API), L<rdiff2> (example using nonblocking API). |
186 | |
311 | |
187 | =head1 BUGS |
312 | =head1 BUGS |