Aprendiendo Perl, el reto: tripwire
Marcelo E. Magallon
marcelo.magallon en gmail.com
Sab Abr 21 16:48:55 PDT 2012
On Mon, Apr 16, 2012 at 11:03:58AM -0600, Marcelo E. Magallon wrote:
> Escriba un programa que monitoree un directorio para encontrar
> cualquier archivo que cambie.
Mi aproximación a una solución. No "monitorea" un directorio
exactamente como lo plantea el reto original, sino que lee
(recursivamente) un directorio y guarda un archivo con la
información de cada archivo en ese directorio. Si el archivo ya
existe entonces lo que hace es verificar los cambios que
ocurrieron. Tiene varias deficiencias, pero implementa el
concepto básico.
Saludos,
Marcelo
------------------------------ >8 ------------------------------
#!/usr/bin/env perl
use Modern::Perl;
use Digest::MD5;
use File::Find;
use Getopt::Std;
use constant DATAFILE => ".checksums";
sub get_checksum
{
my $filename = shift;
open my $fh, "<", $filename or return;
local $/;
return Digest::MD5::md5_hex(<$fh>);
}
sub get_checksums
{
my $info = {};
find({
wanted => sub {
return if -d $_ || ! -r $_;
return unless defined (my $checksum = get_checksum($_));
my $size = -s $_;
$info->{$_} = "$size:$checksum";
},
no_chdir => 1,
},
@_);
return $info;
}
sub store_checksums
{
my $datafile = shift;
my $info = shift;
open my $fh, ">", $datafile;
foreach my $filename (keys %$info)
{
say $fh "$filename:$info->{$filename}"
}
}
sub read_checksums
{
my $datafile = shift;
my $info = {};
open my $fh, "<", $datafile;
while (<$fh>)
{
chomp;
my ($filename, $data) = split ':', $_, 2;
$info->{$filename} = $data;
}
return $info;
}
sub verify_checksums
{
my $old = read_checksums shift;
my $new = shift;
foreach my $filename (keys { map { $_ => 1 } (keys %$new, keys %$old) })
{
if (exists $new->{$filename} && exists $old->{$filename})
{
my ($odata, $ndata) = ($old->{$filename}, $new->{$filename});
if ($odata ne $ndata)
{
say "$filename changed from $odata to $ndata";
}
}
elsif (exists $new->{$filename})
{
say "$filename is new";
}
else
{
say "$filename dissapeared";
}
}
}
my %opts = ( f => DATAFILE );
getopts('rf:', \%opts);
push @ARGV, '.' unless scalar @ARGV;
my $checksums = get_checksums @ARGV;
if (exists $opts{'r'} || ! -e $opts{'f'})
{
store_checksums $opts{'f'}, $checksums;
}
else
{
verify_checksums $opts{'f'}, $checksums;
}
------------------------------ 8< ------------------------------
Más información sobre la lista de distribución Costarica-pm