CHKSHA1 DOWNLOAD PAGE

CHKSHA1 is a perl program to check file integrity.

  • Download chksha1.pl ( file size is under 2Kbyte )
    NOTE:
  • chksha1.pl will run under any UNIX.
     Check integrity of commands on your command $PATH.
    
     Usage: chksha1  [--check] [--sha1sum]
     Initialize 
         % chksha1 > foo                         ; chksha1 original format
         % chksha1 --sha1sum > foo                ; sha1sum compatible format
     Check Integrity
         % chksha1 --check < foo                 ; chksha1 original format
         % sha1sum -c < foo                      ; check by sha1sum command
    


    Author: Hironobu SUZUKI
    Contact E-mail address: hironobu @ h2np . net

    Source Code:
    #!/usr/bin/perl
    #
    # $Id: chksha1.pl,v 1.1 2005/11/24 07:50:28 hironobu Exp hironobu $
    # Hironobu SUZUKI  < hironobu @ h2np -dot- net >
    # ChecK file SHA1 On the PATH.
    # GPL General Public License 2
    #
    # Check integrity of commands on your command $PATH.
    #
    # Usage: chksha1  [--check] [--sha1sum]
    #
    # Initialize
    #     % chksha1 > foo                         ; chksha1 original format
    #     % chksha1 --sha1sum > foo                ; sha1sum format
    # Check Integrity
    #     % chksha1 --check < foo                 ; chksha1 original format
    #     % sha1sum -c < foo                      ; sha1sum format
    #
    # Help 
    #     % sha1sum --help                        ; show help
    
    require 'stat.pl';
    use Digest::SHA1;
    
    # Init Vars
    $sha1sumcompatible="NO";
    $checkflag="NO";
    
    $output=STDOUT;
    
    @checkdata="";
    $dateofcheckdata="";
    %hcheckdata=();
    @currentdata="";
    %hcurrentdata=();
    $dateofcurrentdata="";
    
    $printbuf="";
    
    %dirnamehash=();		# dir name hash table
    
    $MAXDEPTH=3;
    ##MAIN
    
    get_option(@ARGV);
    
    if ( $checkflag eq "YES" ) {
        readCheckData();
    }
    
    onPathFiles();
    
    if ( $checkflag eq "YES" ) {
        compareTwoHashData();
    }
    
    ###
    
    
    #
    # Subroutines
    #
    
    sub onPathFiles {
       $p=$ENV{'PATH'};
       @a=split(':',$p);
       makeCheckSha1(@a);
    
       if ( $sha1sumcompatible eq "NO" ) { 
           $str= "Date: ".scalar localtime()."\n";
           printVal($str);
       }
    }
    sub makeCheckSha1 {
        foreach $i (@_) {
    	makeCheckDateFromFile($i,0);
        }
    }
    
    sub makeCheckDateFromFile{
        my ($fname,$depth)=@_;
        my $i="";
        my @f="";
    
        if ( $depth > $MAXDEPTH ) {
    	return ;
        }
        
        if ( -d $fname ) {
    	if ( alreadyReadDirCheck($fname) < 1 ) {
               # already read this directory (or NOT directory)
    	    return "";		
    	}
    	if ($fname ne "." and  $fname ne ".." ) {
    	    chdir($fname);
    	}
    	if ($fname ne "..") {
    	    opendir (D,$fname) || return;
    	}
    	else {
    	    return;
    	}
    	@f=readdir(D);
    	foreach $i (@f) {
    	    if ($i eq "." or $i eq ".." ) {
    		next;
    	    }
    	    $flp=$fname."/".$i;
    	    makeCheckDateFromFile($flp,$depth+1);
    	}
        }
        else {
    	if ( -x $fname ) {
    	    fileStatAndSha1($fname);
    	}
        }
    }
    
    
    sub fileStatAndSha1 {
        my($fname)=@_;
        my $str="";
        my(@st) = stat($fname);
        open(F,$fname) || return "";
        my $sha1 = new Digest::SHA1;
        $sha1->reset();
        $sha1->addfile(F);
        $str=$sha1->hexdigest();
        close(F);
        if ( $sha1sumcompatible eq "NO" ) { 
    	printVal(@st[$ST_INO].":");
    	printVal(@st[$ST_SIZE].":");
    	printVal(@st[$ST_MODE].":");
    	printVal(@st[$ST_UID].":");
    	printVal(@st[$ST_GID].":");
    	printVal(@st[$ST_MTIME]." ");
        }
        printVal("$str  $fname\n");
    }
    
    sub printVal {
        my ($stval,$hashval,$filepath);
    
        if ( $checkflag eq "YES" ) {
    	$printbuf=$printbuf."@_";
    	if ( $printbuf =~/\n/) {
    	    if ( $printbuf =~ /^Date:/ ) {
    		$dateofcurrentdata=$printbuf;
    		chop $dateofcurrentdata;
    	    }
    	    else {
    		($stval,$hashval,$filepath)=split('\s+',$printbuf);
    		$hcurrentdata{$filepath}=$printbuf;
    	    }
    	    $printbuf="";
    	}
    	return;
    
        }
        print $output "@_";
    }
    
    sub get_option {
        my @largs=@_;
        my $larg="";
        foreach $larg (@largs) {
    	if ( $larg =~ /--check/ ) {
    	    $checkflag="YES";
    	    $checkfile=STDIN;
    	}
    	elsif ( $larg =~ /--sha1sum/ ) {
    	    $sha1sumcompatible="YES";
    	}
    	elsif ( $larg =~ /--help/ ) {
    	    print "Check integrity of commands on your command \$PATH\n";
    	    print " Usage: chksha1  [--check] [--sha1sum]\n";
    	    print " Initialize\n";
    	    print "\t% chksha1 > foo              ; chksha1 original format\n";
    	    print "\t% chksha1 --sha1sum > foo    ; sha1sum compatible format\n";
    	    print " Check Integrity\n";
    	    print "\t% chksha1 --check < foo      ; chksha1 original format\n";
    	    print "\t% sha1sum -c < foo           ; sha1sum compatible format\n";
    	    exit(0);
    	}
        }
    }
    
    sub readCheckData() {
        my($stval,$hashval,$filepath);
        while(<$checkfile>) {
    	chop;
    	if ( $_ =~ /^Date:/ ) {
    	    $dateofcheckdata=$_;
    	    last;
    	}
    	else {
    	    ($stval,$hashval,$filepath)=split('\s+',$_);
    	    $hcheckdata{$filepath}=$_;
    	}
    	
        }
        close($checkfile);
    }
    
    sub compareTwoHashData
    {
        #
        # Del current entry first;
        #
        my $k=""; # filepath
        my $l=""; # check data content
        my $c=""; # current data content
        my ($stval,$hashval,$filepath);
        my ($oldstval,$oldhashval,$oldfilepath);
        my ($inode,$fsize,$mode,$uid,$gid,$mtime);
        my @keyentries;
    
    # Debug print
        $dateofcheckdata;
        print "    Old Data:\t$dateofcheckdata\n";
        print "Current Data:\t$dateofcurrentdata\n";
    
    
        @keyentries = keys %hcheckdata;
        foreach $k (@keyentries) {
    	$l=$hcheckdata{$k};
    	$c=$hcurrentdata{$k};
    	($stval,$hashval,$filepath)=split('\s+',$c);
    	($oldstval,$oldhashval,$oldfilepath)=split('\s+',$l);
    
    	if ( ($l ne "" && $c ne "" ) &&
    	    ($stval ne $oldstval ||  $hashval ne $oldhashval)) {
    	    # miss much
    	    print "\nUnmatched: $filepath\n";
    	    print "    Hash(current): $hashval\n";
    	    print "    Hash    (old): $oldhashval\n";
    	    print "    Stat(current): $stval\n";
    	    print "    Stat    (old): $oldstval\n";
    	}
    	if ( $c ne "" ) {
    	    $hcheckdata{$k}="";	# file was deleted and couldn't be found.
    	}
    	if ( $l ne "" ) {
    	    $hcurrentdata{$k}=""; # file was found in current data.
    	}
        }
        # dump undeleted entry
        @keyentries = keys %hcheckdata;
        foreach $k (@keyentries) {
    	$l=$hcheckdata{$k};
    	if ( $l ne "") {
    	    ($oldstval,$oldhashval,$oldfilepath)=split('\s+',$l);
    	    ($inode,$fsize,$mode,$uid,$gid,$mtime)=split(':',$stval);
    	    print "\nDeleted: $oldfilepath\n";
    	    print "    Hash: $oldhashval\n";
    	    print "    Stat: $inode $mode $uid $gid $mtime\n";
    	}
        }
        @keyentries = keys %hcurrentdata;
        foreach $k (@keyentries) {
    	$c=$hcurrentdata{$k};
    	if ( $c ne "") {
    	    ($stval,$hashval,$filepath)=split('\s+',$c);
    	    ($inode,$mode,$uid,$gid,$mtime)=split(':',$stval);
    	    print "\nCreated: $filepath\n";
    	    print "    Date: ".scalar localtime($mtime)."\n";
    	    print "    Hash: $hashval\n";
    	    print "    Stat: $inode $mode $uid $gid $mtime\n";
    	}
        }
        
    }
    
    sub alreadyReadDirCheck
    {
        my($dirname)=@_;
        my($dev,$inode);
        if ( -d $dirname ) {
    	($dev,$inode)=stat($dirname);
    	if ( $dirnamehash{$inode} eq "" ) {
    	    $dirnamehash{$inode}="yes";
    	    return 1;		# not read yet.
    	}
    	else {
    	    return 0;		# already read;
    	}
        }
        else {
    	return -1;		# NOT directory
        }
    }