Upgrade to Digest-SHA-5.38.
authorSteve Peters <steve@fisharerojo.org>
Thu, 25 May 2006 13:48:56 +0000 (13:48 +0000)
committerSteve Peters <steve@fisharerojo.org>
Thu, 25 May 2006 13:48:56 +0000 (13:48 +0000)
p4raw-id: //depot/perl@28306

ext/Digest/SHA/Changes
ext/Digest/SHA/README
ext/Digest/SHA/SHA.pm
ext/Digest/SHA/bin/shasum
ext/Digest/SHA/src/hmac.c
ext/Digest/SHA/src/hmac.h
ext/Digest/SHA/src/sha.c
ext/Digest/SHA/src/sha.h
ext/Digest/SHA/t/2-nist-sha-oo.t

index 18d1213..5f01e1c 100644 (file)
@@ -1,5 +1,17 @@
 Revision history for Perl extension Digest::SHA.
 
+5.38  Thu May 25 02:02:02 MST 2006
+       - added new capabilities to the "addfile" method
+               -- now able to accept file names as well as handles
+               -- includes mode for portable digest calculation
+                       -- thanks to Adam Kennedy for emails and ideas
+                               ref. File::LocalizeNewlines
+       - used expanded addfile interface to simplify shasum (sumfile)
+               -- regex a tad less general than 5.37, but handles all
+                       known newline variants in UNIX/Windows/MacOS
+       - enhanced WARNING messages from shasum checkfile processing
+               -- to mimic behavior of md5sum
+
 5.37  Mon May  8 04:30:09 MST 2006
        - modified shasum to avoid file slurping (ref. sub sumfile)
        - improved error handling of checksum files in shasum
index fcdea0f..2f833d6 100644 (file)
@@ -1,4 +1,4 @@
-Digest::SHA version 5.37
+Digest::SHA version 5.38
 ========================
 
 Digest::SHA is a complete implementation of the NIST Secure Hash
index 38f34a2..0ba9347 100644 (file)
@@ -1,10 +1,12 @@
 package Digest::SHA;
 
+require 5.006000;
+
 use strict;
 use warnings;
 use integer;
 
-our $VERSION = '5.36_01';
+our $VERSION = '5.38_01';
 
 require Exporter;
 our @ISA = qw(Exporter);
@@ -23,13 +25,14 @@ our @EXPORT_OK = qw(
 
 # If possible, inherit from Digest::base (which depends on MIME::Base64)
 
+*addfile = \&Addfile;
+
 eval {
        require MIME::Base64;
        require Digest::base;
        push(@ISA, 'Digest::base');
 };
 if ($@) {
-       *addfile = \&Addfile;
        *hexdigest = \&Hexdigest;
        *b64digest = \&B64digest;
 }
@@ -85,25 +88,66 @@ sub add_bits {
        return($self);
 }
 
-# local copy of "addfile" in case Digest::base not installed
+sub _bail {
+       my $msg = shift;
+
+        require Carp;
+        Carp::croak("$msg: $!");
+}
 
-sub Addfile {  # this is "addfile" from Digest::base 1.00
+sub _addfile {  # this is "addfile" from Digest::base 1.00
     my ($self, $handle) = @_;
 
     my $n;
     my $buf = "";
 
     while (($n = read($handle, $buf, 4096))) {
-       $self->add($buf);
-    }
-    unless (defined $n) {
-       require Carp;
-       Carp::croak("Read failed: $!");
+        $self->add($buf);
     }
+    _bail("Read failed") unless defined $n;
 
     $self;
 }
 
+sub Addfile {
+       my ($self, $file, $mode) = @_;
+
+       if (ref(\$file) eq 'GLOB') { return(_addfile($self, $file)) }
+
+       $mode = defined($mode) ? $mode : "";
+       my ($binary, $portable) = map { $_ eq $mode } ("b", "p");
+       my $text = -T $file;
+
+       local *F;
+       _bail("Open failed") unless open(F, "<$file");
+       binmode(F) if $binary || $portable;
+
+       unless ($portable && $text) {
+               $self->_addfile(*F);
+               close(F);
+               return($self);
+       }
+
+       my ($n1, $n2);
+       my ($buf1, $buf2) = ("", "");
+
+       while (($n1 = read(F, $buf1, 4096))) {
+               while (substr($buf1, -1) eq "\015") {
+                       $n2 = read(F, $buf2, 4096);
+                       _bail("Read failed") unless defined $n2;
+                       last unless $n2;
+                       $buf1 .= $buf2;
+               }
+                $buf1 =~ s/\015?\015\012/\012/g;       # DOS/Windows
+                $buf1 =~ s/\015/\012/g;                # Apple/MacOS 9
+               $self->add($buf1);
+       }
+       _bail("Read failed") unless defined $n1;
+       close(F);
+
+       $self;
+}
+
 sub dump {
        my $self = shift;
        my $file = shift || "";
@@ -156,7 +200,10 @@ In programs:
        $sha = Digest::SHA->new($alg);
 
        $sha->add($data);               # feed data into stream
+
        $sha->addfile(*F);
+       $sha->addfile($filename);
+
        $sha->add_bits($bits);
        $sha->add_bits($data, $nbits);
 
@@ -409,8 +456,32 @@ So, the following two statements do the same thing:
 Reads from I<FILE> until EOF, and appends that data to the current
 state.  The return value is the updated object itself.
 
-This method is inherited if L<Digest::base> is installed on your
-system.  Otherwise, a functionally equivalent substitute is used.
+=item B<addfile($filename [, $mode])>
+
+Reads the contents of I<$filename>, and appends that data to the current
+state.  The return value is the updated object itself.
+
+By default, I<$filename> is simply opened and read; no special modes
+or I/O disciplines are used.  To change this, set the optional I<$mode>
+argument to one of the following values:
+
+=over 4
+
+=item B<"b">   read file in binary mode
+
+=item B<"p">   use portable mode
+
+=back
+
+The "p" mode is handy since it ensures that the digest value of
+I<$filename> will be the same when computed on different operating
+systems.  It accomplishes this by internally translating all newlines
+in text files to UNIX format before calculating the digest; on the other
+hand, binary files are read in raw mode with no translation whatsoever.
+
+For a fuller discussion of newline formats, refer to CPAN module
+L<File::LocalizeNewlines>.  Its "universal line separator" regex forms
+the basis of I<addfile>'s portable mode processing.
 
 =item B<dump($filename)>
 
@@ -539,6 +610,7 @@ The author is particularly grateful to
        Jeffrey Friedl
        Robert Gilmour
        Brian Gladman
+       Adam Kennedy
        Andy Lester
        Alex Muntada
        Steve Peters
index 0c28719..fdb615b 100755 (executable)
@@ -4,8 +4,8 @@
        #
        # Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
        #
-       # Version: 5.37
-       # Mon May  8 04:30:09 MST 2006
+       # Version: 5.38
+       # Thu May 25 02:02:02 MST 2006
 
 =head1 NAME
 
@@ -22,7 +22,7 @@ shasum - Print or Check SHA Checksums
   -b, --binary       read files in binary mode (default on DOS/Windows)
   -c, --check        check SHA sums against given list
   -p, --portable     read files in portable mode
-                         produces same digest on Windows/Unix/MacOS
+                         produces same digest on Windows/Unix/MacOS 9
   -t, --text         read files in text mode (default)
 
  The following two options are useful only when verifying checksums:
@@ -52,7 +52,7 @@ L<Digest::SHA::PurePerl>.
 use strict;
 use Getopt::Long;
 
-my $VERSION = "5.37";
+my $VERSION = "5.38";
 
 
        # Try to use Digest::SHA, since it's faster.  If not installed,
@@ -79,10 +79,10 @@ sub usage {
 
        $msg = "" unless defined $msg;
        if ($err) {
-               print STDERR "$msg", "Type shasum -h for help\n";
+               warn($msg . "Type shasum -h for help\n");
                exit($err);
        }
-       print STDOUT <<'END_OF_USAGE';
+       print <<'END_OF_USAGE';
 Usage: shasum [OPTION] [FILE]...
    or: shasum [OPTION] --check [FILE]
 Print or check SHA checksums.
@@ -92,7 +92,7 @@ With no FILE, or when FILE is -, read standard input.
   -b, --binary       read files in binary mode (default on DOS/Windows)
   -c, --check        check SHA sums against given list
   -p, --portable     read files in portable mode
-                         produces same digest on Windows/Unix/MacOS
+                         produces same digest on Windows/Unix/MacOS 9
   -t, --text         read files in text mode (default)
 
 The following two options are useful only when verifying checksums:
@@ -132,11 +132,11 @@ GetOptions(
 
 usage(0)
        if $help;
-usage(1, "ambiguous file mode\n")
+usage(1, "Ambiguous file mode\n")
        if scalar(grep { defined $_ } ($binary, $portable, $text)) > 1;
-usage(1, "warn option used only when verifying checksums\n")
+usage(1, "shasum: --warn option used only when verifying checksums\n")
        if $warn && !$check;
-usage(1, "status option used only when verifying checksums\n")
+usage(1, "shasum: --status option used only when verifying checksums\n")
        if $status && !$check;
 
 
@@ -144,7 +144,7 @@ usage(1, "status option used only when verifying checksums\n")
 
 $alg = 1 unless $alg;
 grep { $_ == $alg } (1, 224, 256, 384, 512)
-       or usage(1, "unrecognized algorithm\n");
+       or usage(1, "Unrecognized algorithm\n");
 
 
        # Display version information if requested
@@ -157,13 +157,13 @@ if ($version) {
 
        # Try to figure out if the OS is DOS-like.  If it is,
        # default to binary mode when reading files, unless
-       # explicitly overriden by command line "text" or
-       # "portable" options.
+       # explicitly overriden by command line "--text" or
+       # "--portable" options.
 
 my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/);
 if ($isDOSish) { $binary = 1 unless $text || $portable }
 
-my $mode = $binary ? '*' : ($portable ? '?' : ' ');
+my $modesym = $binary ? '*' : ($portable ? '?' : ' ');
 
 
        # Read from STDIN (-) if no files listed on command line
@@ -176,27 +176,24 @@ my $mode = $binary ? '*' : ($portable ? '?' : ' ');
 sub sumfile {
        my $file = shift;
 
-       local *F;
-       return unless open(F, "<$file");
-       binmode(F) if $binary || $portable;
+       unless (-e $file) {
+               warn "shasum: $file: No such file or directory\n";
+               return;
+       }
+       unless (-r $file) {
+               warn "shasum: $file: FAILED open or read\n";
+               return;
+       }
 
        my $digest = $module->new($alg);
-       if ($portable && -T $file) {
-               local $/ = \4096;
-               while (defined (my $rec = <F>)) {
-                       while (substr($rec, -1) eq "\015") {
-                               defined (my $extra = <F>) or last;
-                               $rec .= $extra;
-                       }
-                       $rec =~ s/\015+\012/\012/g;
-                       $rec =~ s/\015/\012/g;
-                       $digest->add($rec);
-               }
+       unless ($digest) {
+               warn "shasum: $file: FAILED digest creation\n";
+               return;
        }
-       else { $digest->addfile(*F) }
-       close(F);
 
-       $digest->hexdigest;
+       my $readmode = $portable ? 'p' : ($binary ? 'b' : '');
+
+       $digest->addfile($file, $readmode)->hexdigest;
 }
 
 
@@ -209,37 +206,41 @@ my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512);
 
 if ($check) {
        my $checkfile = shift(@ARGV);
-       my $err = 0;
+       my ($err, $read_errs, $match_errs) = (0, 0, 0);
+       my ($num_files, $num_checksums) = (0, 0);
        my ($fh, $sum, $fname, $rsp);
 
        die "shasum: $checkfile: No such file or directory\n"
                unless open($fh, "<$checkfile");
        while (<$fh>) {
                s/\s+$//;
-               ($sum, $mode, $fname) = /^(\S+) (.)(.*)$/;
-               unless (-e $fname) {
-                       warn "shasum: $fname: No such file or directory\n";
-                       next;
-               }
+               ($sum, $modesym, $fname) = /^(\S+) (.)(.*)$/;
                ($binary, $portable, $text) =
-                       map { $_ eq $mode } ('*', '?', ' ');
+                       map { $_ eq $modesym } ('*', '?', ' ');
                unless ($alg = $len2alg{length($sum)}) {
                        warn("shasum: $checkfile: $.: improperly " .
                                "formatted SHA checksum line\n") if $warn;
                        next;
                }
-               $rsp = "$fname: ";
+               $rsp = "$fname: "; $num_files++;
                unless (my $digest = sumfile($fname)) {
                        $rsp .= "FAILED open or read\n";
-                       $err = 1;
+                       $err = 1; $read_errs++;
                }
                else {
+                       $num_checksums++;
                        if (lc($sum) eq $digest) { $rsp .= "OK\n" }
-                       else { $rsp .= "FAILED\n"; $err = 1 }
+                       else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ }
                }
                print $rsp unless $status;
        }
        close($fh);
+       unless ($status) {
+               warn("shasum: WARNING: $read_errs of $num_files listed " .
+                       "files could not be read\n") if $read_errs;
+               warn("shasum: WARNING: $match_errs of $num_checksums " .
+                       "computed checksums did NOT match\n") if $match_errs;
+       }
        exit($err);
 }
 
@@ -248,9 +249,9 @@ if ($check) {
 
 for my $arg (@ARGV) {
        if (-d $arg) {
-               print STDERR "shasum: $arg: Is a directory\n";
+               warn "shasum: $arg: Is a directory\n";
                next;
        }
-       next unless my $digest = sumfile($arg);
-       print "$digest $mode", "$arg\n";
+       my $digest = sumfile($arg) or next;
+       print "$digest $modesym$arg\n";
 }
index e423bd5..be2fe64 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
  *
- * Version: 5.37
- * Mon May  8 04:30:09 MST 2006
+ * Version: 5.38
+ * Thu May 25 02:02:02 MST 2006
  *
  */
 
index 43a7afa..221c09f 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
  *
- * Version: 5.37
- * Mon May  8 04:30:09 MST 2006
+ * Version: 5.38
+ * Thu May 25 02:02:02 MST 2006
  *
  */
 
index 47a18fe..7b4faa4 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
  *
- * Version: 5.37
- * Mon May  8 04:30:09 MST 2006
+ * Version: 5.38
+ * Thu May 25 02:02:02 MST 2006
  *
  */
 
index 95597d3..bf850c4 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
  *
- * Version: 5.37
- * Mon May  8 04:30:09 MST 2006
+ * Version: 5.38
+ * Thu May 25 02:02:02 MST 2006
  *
  */
 
index deefce9..c1a6b3e 100644 (file)
@@ -20,7 +20,7 @@ BEGIN {
 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
        );
 
-       plan tests => 1 + scalar(@vec);
+       plan tests => 5 + scalar(@vec);
 }
 
        # attempt to use an invalid algorithm, and check for failure
@@ -46,6 +46,37 @@ ok($ctx->clone->add("b", "c")->b64digest, $rsp);
 $rsp = shift(@vec);
 open(FILE, "<$file");
 binmode(FILE);
-ok($ctx->addfile(*FILE)->hexdigest, $rsp);
+ok($ctx->clone->addfile(*FILE)->hexdigest, $rsp);
 close(FILE);
+
+       # test addfile using file name instead of handle
+
+ok($ctx->addfile($file, "b")->hexdigest, $rsp);
+
+       # test addfile portable mode
+
+open(FILE, ">$file");
+binmode(FILE);
+print FILE "abc\012" x 2048;           # using UNIX newline
+close(FILE);
+
+ok($ctx->new(1)->addfile($file, "p")->hexdigest,
+       "d449e19c1b0b0c191294c8dc9fa2e4a6ff77fc51");
+
+open(FILE, ">$file");
+binmode(FILE);
+print FILE "abc\015\012" x 2048;       # using DOS/Windows newline
+close(FILE);
+
+ok($ctx->new(1)->addfile($file, "p")->hexdigest,
+       "d449e19c1b0b0c191294c8dc9fa2e4a6ff77fc51");
+
+open(FILE, ">$file");
+binmode(FILE);
+print FILE "abc\015" x 2048;           # using Apple/Mac newline
+close(FILE);
+
+ok($ctx->new(1)->addfile($file, "p")->hexdigest,
+       "d449e19c1b0b0c191294c8dc9fa2e4a6ff77fc51");
+
 unlink($file);