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);
# 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;
}
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 || "";
$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);
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)>
Jeffrey Friedl
Robert Gilmour
Brian Gladman
+ Adam Kennedy
Andy Lester
Alex Muntada
Steve Peters
#
# 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
-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:
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,
$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.
-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:
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;
$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
# 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
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;
}
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);
}
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";
}
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
);
- plan tests => 1 + scalar(@vec);
+ plan tests => 5 + scalar(@vec);
}
# attempt to use an invalid algorithm, and check for failure
$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);