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