Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

md5sum for PPT

by idnopheq (Chaplain)
on Apr 13, 2001 at 01:35 UTC ( [id://72205]=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info idnopheq
Description: md5sum computes a 128-bit checksum (or fingerprint or message-digest) for each specified file. If a file is specified as `-' or if no files are given md5sum computes the checksum for the standard input. md5sum can also determine whether a file and checksum are consistent.

For each file, `md5sum' outputs the MD5 checksum, a flag indicating a binary or text input file, and the filename. If file is omitted or specified as `-', standard input is read.

I added functionallity from BSD md5 and some other md5sum ports (MS-DOS, etc.) for compatibility. FSF md5sum is the default.

#!/usr/bin/perl -wT
#-*-perl-*-
#  $rcs = ' $Id: md5sum,v 1.5 2001/04/12 07:12:12 idnopheq Exp idnophe
+q $ ' ; 

use strict;
use FileHandle;
use Digest::MD5;
use Getopt::Mixed 1.006, "nextOption";
use vars qw ( %option );

my ($VERSION) = '$Revision: 1.5 $' =~ /([.\d]+)/;

my $warnings = 0;

# Print a usage message on a unknown option.
# Requires abigail's patch to Getopt::Std of 25 Feb 1999.

$SIG {__WARN__} = sub {
    if (substr ($_ [0], 0, 14) 
 eq "Unknown option") {
      die "Usage"
    };
    require File::Basename;
    $0 = File::Basename::basename ($0);
    $warnings = 1;
    warn "$0: @_";
};

$SIG {__DIE__} = sub {
    require File::Basename;
    $0 = File::Basename::basename ($0);
    if (substr ($_ [0], 0,  7) eq "Version") {
      die <<VER;
$0 (Perl bin utils) $VERSION

VER
      }
    elsif (substr ($_ [0], 0,  5) eq "Usage") {
        die <<EOF;
$0 (Perl bin utils) $VERSION
$0 [-bBcpqrtwvV] [-s string] [file ...]
EOF
      }
    elsif (substr ($_ [0], 0,  4) eq "Help") {
        die <<HELP;
$0 (Perl bin utils) $VERSION
$0 [-bBcpqrtwvV] [-s string] [file ...]

  -b, --binary   binary file mode
  -B, --bsd      FreeBSD, maybe OpenBSD?, format
  -c, --check    check manifest file
  -p,            print from stdin. Does nothing, included for FreeBSD
  -q, --quiet    only the MD5 sum is printed out
  -r, --reverse  Reverses the format of the output like FSF but no bin
+ary *
  -s, --string   Print a checksum of the given string
  -t, --text     text file mode (default)
  -v,            does nothing, included for Win32
  -h, --help     display this help and exit
  -V, --version  output version information and exit

The following two options are useful only when verifying checksums:
      --status   don't output anything, status code shows success
  -w, --warn     warn about improperly formated MD5 checksum lines

The sums are computed as described in RFC 1321.  When checking, the in
+put
should be a former default output of this program.  The default mode i
+s to
print a line with checksum, a character indicating type ('*' for binar
+y, ' '
for text), and name for each FILE.

HELP
    }
    die "$0: @_";
};

# Get the options.

Getopt::Mixed::init ( 
       "binary",        # binary file mode
       "b>binary",      # -b an alias for --binary
       "bsd",           # FreeBSD, maybe OpenBSD?, format
       "B>bsd",         # -B an alias for --bsd
       "check",         # check manifest file
       "c>check",       # -c an alias for --check
       "help",          # more detailed help
       "?>help",        # -? an alias for --help
       "h>help",        # -h an alias for --help
       "p",             # does nothing, included for FreeBSD
       "quiet",         # only the MD5 sum is printed out
       "q>quiet" ,      # -q an alias for --quiet
       "reverse",       # Reverses the format of the output
                                      #  like FSF but no binary *
       "r>reverse",     # -r an alias for --reverse
       "status",        # return 0 on ok, non-0 on badness
                                      #  only useful w/ -c or --check
       "string=s",      # Print a checksum of a given string
       "s>string",      # -s an alias for --string
       "text",          # text mode (default)
       "t>text",        # -t an alias for --text
       "v",             # does nothing, included for Win32
       "version",       # print the version number and exit
       "V>version",     # -V an alias for --version
       "warn",          # show # of ok and bad checksums
                        #  only useful w/ -c or --check
       "w>warn",        # -w an alias for --warn
      );

# process the options and gently place them in a hash for easy access

while ( 
       my (
    $option,
    $value,
    $asEntered
   )           = nextOption () 
      ) {

  $option{$option}    = $value || 1;
}

# cleanup options

Getopt::Mixed::cleanup();

# *** BEGGING FOR SWITCH CONSTRUCT

die "Version"
  if $option{'version'};

die "Help"
  if $option{'help'};

# if the 'string' option was presented, $option{'string'} will hold th
+at
# string, so hash it & print & outta here

if ( $option{'string'} ) {
  my $inMD5           = Digest::MD5->new;
  $inMD5->add ( $option{'string'} );
  print outputHash( 
     $option{'string'},
     $inMD5->hexdigest,
     ' '
     );
  exit;
}

# if we are checking file from a manifest file, the do it and bye!

if ( $option{'check'} ) {
  checkManifest ( $ARGV[0] );
  exit;
}

# figure out if we're working binary via OS and a 'text' override

$option{'binary'}   ||= $^O =~ /MSWin32/;
undef $option{'binary'}
  if $option{'text'};

$ARGV[0]            ||= "-";

# here endeth the begging ***

# MAIN, if you will
# parse each remaining option and treat it as a file to hash

foreach my $file ( @ARGV ) {
  chomp $file;
  my (
      $md5Digest,
      $binary
     ) = MD5 ( $file );
  print &outputHash ( 
      $file, 
      $md5Digest,
      $binary
     );
}

sub MD5 {
  my $file            = shift;
  my $prefix          = ' ';
  my $inFile          = new FileHandle;
  my $inMD5           = Digest::MD5->new;
  unless (-e $file) {
    warn "$file: No such file or directory\n";
    return;
  }
  unless ( $inFile->open ( "<$file" ) ) {
    warn "Could not open $file:$!\n"; 
    return;
  }
  binmode ( $inFile ) && ( $prefix = '*' )
    if $option{'binary'};
  $inMD5->addfile ( $inFile );
  $inFile->close;                  # being tidy
  return $inMD5->hexdigest, $prefix;
}

sub checkManifest {
  my $file = shift;
  my $inFile          = new FileHandle;
  unless (-e $file) {
    warn "$file: No such file or directory\n";
    return;
  }
  $inFile->open ( "<$file" )
    or die "Could not open $file:$!\n";
  my $ok = my $failed = 0;

  while ( <$inFile> ) {
    next
      if /^#/;                     # skip comments
    # our manifest file ~should be~ in a fixed format if sane
    my (
 $md5Hash,
 $binary,
 $fileName
       )              = unpack "a32 a2 A*", $_;
    warn "$fileName: No such file or directory\n" && next
      unless -e $fileName;
    my $karma = verifyHash ( 
       $md5Hash,
       $fileName
      );
  KARMA: {
      unless ( $karma && -e $fileName ) { 
 warn "$fileName: No such file or directory\n";
 $failed++;
 return;
 return;
      }
      unless ( $karma ) {
 warn "$fileName: Improperly formatted MD5 checksum line\n";
 $failed++;
 next;
 return;
      }
      bless $inFile;
    }
    my $md5 = ( MD5 ( $fileName ) )[0]
      or return;
    $option{'binary'} = ( $binary =~ /\*/ ) || undef;
    if ( $md5Hash eq $md5 ) {
      print $fileName , ": OK\n"
 unless $option{'status'};
      $ok++;
    }
    else {
      print $fileName , ": FAILED\n"
 unless $option{'status'};
      $failed++;
    }
  }
  if ( $option{'status'} ) {
      if ( $failed > 0 ) { return 1; };
      return 0;
  }
  $= = $ok+$failed;
  warn "WARNING: $failed of ", $=, " computed checksums did NOT match\
+n"
      if ( $failed > 0 && $option{'warn'} ); 
}

sub verifyHash {
  my (
      $hash,
      $file
      )              = @_;
  if ( length $hash != 32 ) { return }
  elsif ( ! -e $file )      { return 2 }
  return 1;
}

sub onError {
  require File::Basename;
  return File::Basename::basename ($0);
}

sub outputHash {
  my (
     $file,
     $md5Hash,
     $bin
     )               = @_;
  return
    unless $md5Hash;

  if ( ( defined $option{'bsd'} ) 
       + ( defined $option{'quiet'} ) 
       + ( defined $option{'reverse'} ) 
       > 1 ) {
    warn "Too many output options defined. Setting to default (FSF) st
+yle.\n";
    undef $option{'bsd'};
    undef $option{'quiet'};
    undef $option{'reverse'};
  }

 OUTPUT: {
    $option{'bsd'}     && do { 
      return onError() , " ($file) = $md5Hash\n"; 
      last OUTPUT; 
    };
    $option{'quiet'}   && do { 
      return "$md5Hash\n"; 
      last OUTPUT; 
    };
    $option{'reverse'} && do { 
      return "$md5Hash $file\n"; 
      last OUTPUT; 
    };
    return "$md5Hash $bin$file\n";
  }
}
__DATA__

=pod

=head1 NAME

md5sum - Print or check message-digests

=head2 SYNOPSIS

md5sum [option]... [file]...
md5sum [option]... --check [file]

=head2 DESCRIPTION

md5sum computes a 128-bit checksum (or fingerprint or message-digest) 
+for each specified file. If a file is specified as `-' or if no files
+ are given md5sum computes the checksum for the standard input. md5su
+m can also determine whether a file and checksum are consistent. Syno
+pses:

For each file, `md5sum' outputs the MD5 checksum, a flag indicating a 
+binary or text input file, and the filename. If file is omitted or sp
+ecified as `-', standard input is read.

=head2 OPTIONS

The program accepts the following options.

=item -b --binary        Treat all input files as binary.

This option has no effect on Unix systems, since they don't distinguis
+h between binary and text files. This option is useful on systems tha
+t have different internal and external character representations. On 
+MS-DOS and MS-Windows, this is the default. 

=item -B --bsd           Provide FreeBSD default output

Like the md5 command of the BSD-derrivitives.  This output will not wo
+rk with the check feature.

=item -c --check

Read filenames and checksum information from the single file (or from 
+stdin if no file was specified) and report whether each named file an
+d the corresponding checksum data are consistent.

The input to this mode of md5sum is usually the output of a prior, che
+cksum-generating run of `md5sum'. Each valid line of input consists o
+f an MD5 checksum, a binary/text flag, and then a filename. Binary fi
+les are marked with `*', text with ` '. For each such line, md5sum re
+ads the named file and computes its MD5 checksum. Then, if the comput
+ed message digest does not match the one on the line with the filenam
+e, the file is noted as having failed the test. Otherwise, the file p
+asses the test. 

By default, for each valid line, one line is written to standard outpu
+t indicating whether the named file passed the test. After all checks
+ have been performed, if there were any failures, a warning is issued
+ to standard error. Use the `--status' option to inhibit that output.
+ If any listed file cannot be opened or read, if any valid line has a
+n MD5 checksum inconsistent with the associated file, or if no valid 
+line is found, md5sum exits with nonzero status. Otherwise, it exits 
+successfully. 

=item -p                 Echo stdin to stdout and appends the MD5 sum 
+to stdout

(Default w/o options, so ignorred).  For *BSD boxen.

=item -q --quiet         Quiet mode

Only the MD5 sum is printed out.  Overrides the -r option.

=item -r --reverse       Reverses the format of the output

This helps with visual diffs, if you're on a *BSD box.  Simillar to de
+fault output, but w/o the binary star '*' prepending binary files.  T
+his may be important if you're on a Win32 boxen.

=item --status

This option is useful only when verifying checksums. When verifying ch
+ecksums, don't generate the default one-line-per-file diagnostic and 
+don't output the warning summarizing any failures. Failures to open o
+r read a file still evoke individual diagnostics to standard error. I
+f all listed files are readable and are consistent with the associate
+d MD5 checksums, exit successfully. Otherwise exit with a status code
+ indicating there was a failure. 

=item -s --string        Print the MD5 checksum of the string

This option overrides most options, and requires you to provide text a
+s an argument to the option.  Based on your shell, you will likely wa
+nt to single quote ' the text on both ends.

=item -t --text          Treat all input files as text files

This is the reverse of `--binary'.

=item -v                 Verbose output

(Default w/o options, so ignorred).  For MS-DOS-derrived boxen.

=item -w --warn

This option is useful only when verifying checksums. When verifying ch
+ecksums, warn about improperly formatted MD5 checksum lines. This opt
+ion is useful only if all but a few lines in the checked input are va
+lid. 

=head2 SEE ALSO

I dunno?  Some man pages, like md5sum and md5?

=head2 ACKNOWLEDGEMENTS

RSA Data Security probably think they get some credit.  I'd like to th
+ank the Academy, all those people who I love, and of course the Perl 
+Monks, especially abigail.

=head2 LICENSE

# Copyright (c) 2001
#      Dexter Coffin.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in t
+he
#    documentation and/or other materials provided with the distributi
+on.
#
# THIS SOFTWARE IS PROVIDED BY DEXTER COFFIN AND CONTRIBUTORS ``AS IS'
+' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, TH
+E
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR P
+URPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL DEXTER COFFIN OR CONTRIBUTORS BE 
+LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQU
+ENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GO
+ODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION
+)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN AN
+Y WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+OF
# SUCH DAMAGE.
#


=cut

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://72205]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (1)
As of 2024-04-19 18:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found