File::Rdiff -- generate remote signatures and patch files using librsync
use File::Rdiff
A more-or-less direct interface to librsync (http://librsync.sourceforge.net/).
For usage examples (better than this very sparse documentation), see the two example scripts below.
A constant describing the version of the rsync library used in this module. My version claimed to be "0.9.5 librsync" when I wrote this document ;)
Return the current tracelevel and optionally set a new one.
Return the current trace callback and optionally set a new one. The callback will be called with the log level as the first argument and the log message as the second one.
Calling trace_to with undef will restore the default handler (which currently prints the message to standard error).
trace_to
undef
Returns wether debugging traces are supported in this version of the library.
Returns a string representation of the given error code. You usually just "exit(1)" or something when a function/method fails, as all (most?) librsync functions log the error properly, so there is rarely a need to call this function.
This class contains the input and output buffers for the non-blocking interface. It is slightly unusual in that it allows direct manipulation of (some) of it's internal variables.
Creates and initializes a new buffers structure. $outsize specifies the maximum number of bytes to be read into the output scalar until it is considered full. The default is 64k.
$outsize
Set the next block of input to consume. Data will be read from this scalar (no copy will be made!) until all bytes have been consumed or a new input scalar is set.
Return the current output data and create a new buffer. Returns undef if no data has been accumulated.
Set the eof flag to true. This indicates that no data is following the current input scalar.
Returns the numer of bytes still available for input. If there are no input bytes available but the eof flag is set, returns -1 (to make boolean tests easy to check wether to supply more data easier).
Returns the number of bytes still available in the output buffer.
The number of bytes that have been accumulated in the current buffer so far.
It is possible to have multiple jobs running at the same time. The idea is to create job objects and then drive them incrementally with input or output data until all date has been processed.
Create a job that converts a base stream into a signature stream (i.e. creates signatures).
Create a job that converts the input stream into a in-memory File::Rdiff::Signature object. The signature object can be fetched anytime with the signature-method.
signature
Creates a job that creates (outputs) a delta between the input stream (the newer file) and the file represented by the given signature.
Creates a job that patches a file according to the input stream (a delta stream). The single argument is used to read the base file contents. If it is a filehandle, it must be a seekable handle to the base file.
If it is a coderef, it will be called whenever base file data must be read. Two arguments will be passed: the file offset and the length. The callback should eithe return the data read (must be a string, not a number!) or an error code.
Do as much work as possible given the input and/or output data in the File::Rdiff::Buffers structure and return either DONE when the job is finished, BLOCKED if there aren't enough bytes available in the input or output buffers (in which case you should deplete the output buffer and/or fill the input buffer and loop), or some error code indicating that the operation failed.
DONE
BLOCKED
Only valid for new_loadsig, so look there.
new_loadsig
Very simple program that mimics librsync's rdiff, using the simple file utility functions. see example below for the same program, written using the nonblocking API.
#!/usr/bin/perl use File::Rdiff qw(:trace :file); trace_level(LOG_INFO); if ($ARGV[0] eq "signature") { open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; open $sig, ">$ARGV[2]" or die "$ARGV[2]: $!"; File::Rdiff::sig_file $base, $sig; } elsif ($ARGV[0] eq "delta") { open $sig, "<$ARGV[1]" or die "$ARGV[1]: $!"; open $new, "<$ARGV[2]" or die "$ARGV[2]: $!"; open $delta, ">$ARGV[3]" or die "$ARGV[3]: $!"; $sig = loadsig_file $sig; ref $sig or exit 1; $sig->build_hash_table; File::Rdiff::delta_file $sig, $new, $delta; } elsif ($ARGV[0] eq "patch") { open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; open $delta, "<$ARGV[2]" or die "$ARGV[2]: $!"; open $new, ">$ARGV[3]" or die "$ARGV[3]: $!"; File::Rdiff::patch_file $base, $delta, $new; } else { print <<EOF; $0 signature BASE SIGNATURE $0 delta SIGNATURE NEW DELTA $0 patch BASE DELTA NEW EOF exit (1); }
Same as above, but written using the callback-based, "nonblocking", API.
#!/usr/bin/perl use File::Rdiff qw(:trace :nonblocking); trace_level(LOG_INFO); if ($ARGV[0] eq "signature") { open $basis, "<", $ARGV[1] or die "$ARGV[1]: $!"; open $sig, ">", $ARGV[2] or die "$ARGV[2]: $!"; my $job = new_sig File::Rdiff::Job 128; my $buf = new File::Rdiff::Buffers 4096; while ($job->iter($buf) == BLOCKED) { # fetch more input data $buf->avail_in or do { my $in; 65536 == sysread $basis, $in, 65536 or $buf->eof; $buf->in($in); }; print $sig $buf->out; } print $sig $buf->out; } elsif ($ARGV[0] eq "delta") { open $sig, "<$ARGV[1]" or die "$ARGV[1]: $!"; open $new, "<$ARGV[2]" or die "$ARGV[2]: $!"; open $delta, ">$ARGV[3]" or die "$ARGV[3]: $!"; # first load the signature into memory my $job = new_loadsig File::Rdiff::Job; my $buf = new File::Rdiff::Buffers 0; do { $buf->avail_in or do { my $in; 65536 == sysread $sig, $in, 65536 or $buf->eof; $buf->in($in); }; } while $job->iter($buf) == BLOCKED; $sig = $job->signature; $sig->build_hash_table; # now create the delta file my $job = new_delta File::Rdiff::Job $sig; my $buf = new File::Rdiff::Buffers 65536; do { $buf->avail_in or do { my $in; 65536 == sysread $new, $in, 65536 or $buf->eof; $buf->in($in); }; print $delta $buf->out; } while $job->iter($buf) == BLOCKED; print $delta $buf->out; } elsif ($ARGV[0] eq "patch") { open $base, "<$ARGV[1]" or die "$ARGV[1]: $!"; open $delta, "<$ARGV[2]" or die "$ARGV[2]: $!"; open $new, ">$ARGV[3]" or die "$ARGV[3]: $!"; # NYI File::Rdiff::patch_file $base, $delta, $new; } else { print <<EOF; $0 signature BASIS SIGNATURE $0 delta SIGNATURE NEW DELTA $0 patch BASE DELTA NEW EOF exit (1); }
File::Rsync, rdiff1 (usage example using simple file API), rdiff2 (example using nonblocking API).
- not well-tested so far.
- low memory will result in segfaults rather than croaks.
- no access to statistics yet
- documentation leaves much to be deserved.
Marc Lehmann <schmorp@schmorp.de> http://home.schmorp.de/
To install File::Rdiff, copy and paste the appropriate command in to your terminal.
cpanm
cpanm File::Rdiff
CPAN shell
perl -MCPAN -e shell install File::Rdiff
For more information on module installation, please visit the detailed CPAN module installation guide.