diff -r 820b22e13ff1 -r 39c28ec933dd bintools/evalid/EvalidMD5.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bintools/evalid/EvalidMD5.pm Mon May 10 19:54:49 2010 +0100 @@ -0,0 +1,499 @@ +# +# Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of the License "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# This module implements the MD5 version of the Evalid's compare +# + +package EvalidMD5; + +use strict; +use Carp; +use File::Find; +use IO::File; +use Sys::Hostname; + +use FindBin; +use lib "$FindBin::Bin"; +require Exporter; +use File::Basename; + +use vars qw($VERSION ); +$VERSION = 0.02; + +use EvalidCompare; + +# Public + +# MD5Generate +# +# Inputs +# $iLeftDir - Left side directory or File containing listing of left side +# $iResultsFile - Name of file to write the list of files and MD5 checksum to +# $iExclude - Reference to array of regular expression patterns to exclude +# $iInclude - Reference to array of regular expression patterns to include +# $iListFile - Filename to read for list of files from [Optional] +# $iDumpDir - Directory to generate dump of comparison data [Optional] +# +# Outputs +# +# Description +# This function generates the MD5 checksum file + +sub MD5Generate +{ + my ($iLeftDir, $iResultsFile, $iExclude, $iInclude, $iListFile, $iDumpDir) = @_; + + my (@iLeftFiles); + + # This should have been check before getting here but to be on the safe side + # check again, as it should never overwrite or append to the file + croak "$iResultsFile already exists" if (-e $iResultsFile); + croak "$iListFile does exist" if ((defined($iListFile) && (!-e $iListFile))); + + if (-d $iLeftDir){ + # Make sure all the \ are / for the RegEx + $iLeftDir =~ s/\\/\//g; + # Make sure it does not have a / on the end + $iLeftDir =~ s/\/$//; + # If $iFileList is defined then use the filelist to generate @iLeftFiles + if (defined($iListFile)) + { + # Generate list of files + @iLeftFiles = &FilterDir($iLeftDir,$iExclude,$iInclude, $iListFile); + } else { + # Generate the the directory listing + @iLeftFiles = &FilterDir($iLeftDir,$iExclude,$iInclude); + } + } else { + croak "$iLeftDir is not a directory"; + } + + # Open the results file for writing + my ($fResultsFile) = new IO::File; + croak "Cannot for $iResultsFile for writing" unless ($fResultsFile->open("> $iResultsFile")); + + # Write headers to the file + print $fResultsFile "Host:".&hostname()."\n"; + print $fResultsFile "Username:".$ENV{'USERNAME'}."\n"; + print $fResultsFile "Date-Time:".scalar(localtime)."\n"; + print $fResultsFile "Version:".$VERSION."\n"; + print $fResultsFile "Directory:".$iLeftDir."\n"; + print $fResultsFile "FileList:".$iListFile."\n" if (defined($iListFile)); + print $fResultsFile "Exclusion(s):"; + foreach my $iExc (sort @$iExclude) + { + print $fResultsFile "$iExc "; + } + print $fResultsFile "\n"; + + print $fResultsFile "Inclusion(s):"; + foreach my $iInc (@$iInclude) + { + print $fResultsFile "$iInc "; + } + print $fResultsFile "\n"; + + print $fResultsFile "----------------\n"; + + # Write out sorted list of files with MD5 Checksums + foreach my $iFile (sort @iLeftFiles) + { + my ($MD5, $type) = &EvalidCompare::GenerateSignature($iLeftDir."/".$iFile, $iDumpDir); + print $fResultsFile $iFile." TYPE=".$type." MD5=".$MD5."\n"; + } + + $fResultsFile->close; +} + + +# MD5Compare +# +# Inputs +# $iLeftFile - Left side File containing listing and MD5 of left side +# $iRightFile - Right side File containing listing and MD5 of right side +# $iVerbose - Verbose Flag +# $iLog - Logfile name +# +# Outputs +# %iCommon - hash relative filenames with values of file type that are in both directories and Compare results/types +# %iDiff - hash relative filenames with values of file type and directory side infomation +# +# Description + +sub MD5Compare +{ + my ($iLeftFile) = shift; + my ($iRightFile) = shift; + my ($iVerbose) = defined($_[0]) ? shift : 0; + my ($iLog) = defined($_[0]) ? shift : *STDOUT; + + my (%iCommon, %iDiff); + + my (%iLeftFiles, %iRightFiles); + my (%iLeftHeaders, %iRightHeaders); + + # Backup check the files are available to read. + croak "$iLeftFile is not a file" unless (-f $iLeftFile); + croak "$iRightFile is not a file" unless(-f $iRightFile); + + #Read the files + &ReadMD5File($iLeftFile, \%iLeftFiles, \%iLeftHeaders); + &ReadMD5File($iRightFile, \%iRightFiles, \%iRightHeaders); + + # Check Critical headers + foreach my $iHeader (sort keys %iLeftHeaders) + { + # Warning is certain headers are not identical + if ($iHeader =~ /^Version|Exclusion\(s\)|Inclusion\(s\)/) + { + print $iLog "WARNING:$iHeader is different\n" if ($iLeftHeaders{$iHeader} ne $iRightHeaders{$iHeader}); + } + } + + # A Hash is used to combine the two directory listing using the filename as the key + my %iCombinedFiles; + + # Enter the files from the left side listing and check the right side critical header are the same + # Note all filenames are turned to lower case as this is designed to only wotk on Windows + foreach my $iFile (sort keys %iLeftFiles) + { + $iCombinedFiles{$iFile} = "Left"; + } + + # Enter the files from the right side listing + # Note all filenames are turned to lower case as this is designed to only wotk on Windows + foreach my $iFile (sort keys %iRightFiles) + { + # Check to see if any entry for this file exists on the left side + if ((defined ($iCombinedFiles{$iFile})) && ( $iCombinedFiles{$iFile} eq "Left")) + { + # Yes, so add to the Common set + # Check if the MD5 checksum matches + # The [0] element is the file type + if ($iLeftFiles{$iFile}[0] ne $iRightFiles{$iFile}[0]) + { + $iCommon{$iFile} = [$iLeftFiles{$iFile}[0]." to ".$iRightFiles{$iFile}[0], "Type Changed"]; + } elsif ($iLeftFiles{$iFile}[1] eq $iRightFiles{$iFile}[1]) { + $iCommon{$iFile} = [$iLeftFiles{$iFile}[0],"OK"]; + } else { + $iCommon{$iFile} = [$iLeftFiles{$iFile}[0],"Different"]; + } + # The filename key is not needed any more as both sides have been processed, so delete the hash entry + delete $iCombinedFiles{$iFile}; + } elsif (!defined($iCombinedFiles{$iFile})) { + # No, the key is not defined, so this filename is only in the right side + $iDiff{$iFile} = [$iRightFiles{$iFile}[0],"Right"]; + # The filename key is not needed any more as both sides have been processed, so delete the hash entry + delete $iCombinedFiles{$iFile}; + } + } + + # Add the files left in the hash to the Left side only list + foreach my $iFile (sort keys %iCombinedFiles) + { + $iDiff{$iFile} = [$iLeftFiles{$iFile}[0],"Left"]; + } + + # Return References to the Arrays + return (\%iCommon, \%iLeftHeaders, \%iRightHeaders, \%iDiff); +} + +# FilterDir +# +# Inputs +# $iDir - Directory to process +# $iExclude - Reference to array of regular expression patterns to exclude +# $iInclude - Reference to array of regular expression patterns to include +# $iListFile - Filename to read for list of files from [Optional] +# +# Outputs +# @iFinalFileList - Filtered list relative filenames +# +# Description +# This function produces a filtered list of filenames in the specified directory or from file + +sub FilterDir +{ + my ($iDir,$iExclude,$iInclude, $iListFile) = @_; + + my (@iFileList, @iFinalFileList, $iFileName); + + if(defined($iListFile)) + { + open LIST, "$iListFile" or croak "Cannot open $iListFile\n"; + while() + { + next if /^\s+$/; # skip blank lines + my $iFileName = $iDir."/".$_; + chomp $iFileName; # Remove new line + if(-e $iFileName) + { + # The listed file exists add to the @iFileList + push @iFileList, $iFileName; + } else { + print "Warning: Cannot find $iFileName\n"; + } + } + close LIST; + } else { + # Produce full filelist listing without directory names + find sub { push @iFileList, $File::Find::name if (!-d) ;}, $iDir; + } + + foreach my $iFile ( @iFileList) + { + my $iExcludeFile = 0; + + # Remove the specified directory path from the front of the filename + $iFile =~ s#^$iDir/##; + + # Process all Exclude RegEx to see if this file matches + foreach my $iExcludeRegEx (@$iExclude) + { + if ($iFile =~ /$iExcludeRegEx/i) + { + # Mark this file to be excluded from the final list + $iExcludeFile = 1; + } + } + + # Process all Include RegEx to see if this file matches + foreach my $iIncludeRegEx (@$iInclude) + { + if ($iFile =~ /$iIncludeRegEx/i) + { + # Mark this file to be Included in the final list + $iExcludeFile = 0; + } + } + + # Added the file to the final list based on the flag + push @iFinalFileList, lc($iFile) unless $iExcludeFile; + } + + return @iFinalFileList; + +} + +# MD5ComparePrint +# +# Inputs +# $iCommon - Reference to Hash of common file names and the result the comparision +# $iLeftHeaders - Reference to Hash contain the left side +# $iRightHeaders - Reference to Hash contain the right side +# $iDiff - Reference to Hash of relative filenames with values of file type and left/right directory side +# $iLog - Logfile name +# +# Outputs +# +# Description +# This function prints the output of a Compare +sub MD5ComparePrint +{ + my ($iCommon) = shift; + my ($iLeftHeaders) = shift; + my ($iRightHeaders) = shift; + my ($iDiff) = shift; + my ($iLog) = shift; + + my ($iFailed) = 0; # Count of the failed comparisions + my ($iPassed) = 0; # Count of the Passed comparisions + my ($iLeft) = 0; # Count of the Passed comparisions + my ($iRight) = 0; # Count of the Passed comparisions + + + my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time); + printf $iLog "\n----------------\n%02d:%02d %02d/%02d/%04d\n", $hour, $min, $mday, $mon+1, $year+1900; + print $iLog "evalid\nLeft Side=$ARGV[0]\nRight Side=$ARGV[1]\n"; + print $iLog "\nLeft side information\n"; + foreach my $iHeader (sort keys %$iLeftHeaders) + { + print $iLog $iHeader.":".$$iLeftHeaders{$iHeader}."\n"; + } + print $iLog "\nRight side information\n"; + foreach my $iHeader (sort keys %$iRightHeaders) + { + print $iLog $iHeader.":".$$iRightHeaders{$iHeader}."\n"; + } + print $iLog "\n"; + + foreach my $iFile (sort keys %$iCommon) + { + if ($$iCommon{$iFile}[1] eq "OK") + { + print $iLog "Passed:$iFile (".$$iCommon{$iFile}[0].")\n"; + $iPassed++; + } + } + print $iLog "\n"; + + foreach my $iFile (sort keys %$iCommon) + { + if ($$iCommon{$iFile}[1] eq "Type Changed") + { + print $iLog "Type Changed:$iFile (".$$iCommon{$iFile}[0].")\n"; + $iFailed++; + } + } + print $iLog "\n"; + + foreach my $iFile (sort keys %$iCommon) + { + if ($$iCommon{$iFile}[1] eq "Different") + { + print $iLog "Failed:$iFile (".$$iCommon{$iFile}[0].")\n"; + $iFailed++; + } + } + print $iLog "\n"; + + foreach my $iFile (sort keys %$iDiff) + { + if ($$iDiff{$iFile}[1] eq "Left") + { + print $iLog "Missing Left:$iFile (".$$iDiff{$iFile}[0].")\n"; + $iLeft++; + } + } + print $iLog "\n"; + + foreach my $iFile (sort keys %$iDiff) + { + if ($$iDiff{$iFile}[1] eq "Right") + { + print $iLog "Missing Right:$iFile (".$$iDiff{$iFile}[0].")\n"; + $iRight++; + } + } + + print $iLog "\n\nSummary\n"; + print $iLog "Total files processed=".($iPassed+$iFailed+$iRight+$iLeft)."\n"; + print $iLog "Files Passed=$iPassed\n"; + print $iLog "Files Failed=$iFailed\n"; + print $iLog "Missing Files in Left=".$iRight."\n"; + print $iLog "Missing Files in Right=".$iLeft."\n"; + + return ($iFailed); +} +# NameOnly +# +# Inputs +# $filename - may contain path and file extension +# +# Outputs +# $nameOnly - filename without extension and path +# +# Description +# This routine is used to extract the name of the file +# only from a filename that may include a path and file extension +# +sub NameOnly +{ + my ($filename) = @_; + my $nameOnly = basename($filename); + $nameOnly =~ s/(\w+.*)\.\w+$/$1/; + return $nameOnly; +} + +# MD5CompareZipDel +# +# Inputs +# $iCommon - Reference to Hash of common file names and the result the comparision +# $iDiff - Reference to Hash of relative filenames with values of file type and left/right directory side +# $iLeft - filename of Left side directory +# $iRight - filename of Right side directory +# +# Outputs +# +# Description +# This function prints the output of a Compare results in a format ready for creating the a +# Zip and batch file to upgrade the left side to the equivalent of the right side. +sub MD5CompareZipDel +{ + my ($iCommon) = shift; + my ($iDiff) = shift; + my ($iLeft) = shift; + my ($iRight) = shift; + + # Build a suitable name for outputfiles based on input filenames + $iLeft = NameOnly($iLeft); + $iRight = NameOnly($iRight); + my ($iBasename) = $iLeft."_to_".$iRight; + + open DELLIST, ">del_$iBasename.bat"; + open ZIPLIST, ">zip_$iBasename.log"; + open ZIPBAT, ">zip_$iBasename.bat"; + + foreach my $iFile (sort keys %$iCommon) + { + if (($$iCommon{$iFile}[1] eq "Different") || ($$iCommon{$iFile}[1] eq "Type Changed")) + { + print ZIPLIST "$iFile\n"; + } + } + + foreach my $iFile (sort keys %$iDiff) + { + if ($$iDiff{$iFile}[1] eq "Right") + { + print ZIPLIST "$iFile\n"; + } else { + # DEL needs the / to be \ + $iFile =~ s/\//\\/g; + print DELLIST "del /F $iFile\n"; + } + } + + print ZIPBAT "zip $iBasename.zip -@) + { + if (/^(\S+?):(.*)/) + { + $$iHeaders{$1} = $2; + } elsif (/^(\S+?)\sTYPE=(.*?)\sMD5=(.*)/){ + $$iResults{$1} = [$2,$3]; + } + } + close INPUT; + +} + +1;