bintools/evalid/EvalidMD5.pm
changeset 0 044383f39525
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 #
       
     2 # Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of the License "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 # This module implements the MD5 version of the Evalid's compare
       
    16 #
       
    17 
       
    18 package EvalidMD5;
       
    19 
       
    20 use strict;
       
    21 use Carp;
       
    22 use File::Find;
       
    23 use IO::File;
       
    24 use Sys::Hostname;
       
    25 
       
    26 use FindBin;
       
    27 use lib "$FindBin::Bin";
       
    28 require Exporter;
       
    29 use File::Basename;
       
    30 
       
    31 use vars       qw($VERSION );
       
    32 $VERSION     = 0.02;
       
    33 
       
    34 use EvalidCompare;
       
    35 
       
    36 # Public
       
    37 
       
    38 # MD5Generate
       
    39 #
       
    40 # Inputs
       
    41 # $iLeftDir - Left side directory or File containing listing of left side
       
    42 # $iResultsFile - Name of file to write the list of files and MD5 checksum to
       
    43 # $iExclude - Reference to array of regular expression patterns to exclude
       
    44 # $iInclude - Reference to array of regular expression patterns to include
       
    45 # $iListFile - Filename to read for list of files from [Optional]
       
    46 # $iDumpDir - Directory to generate dump of comparison data [Optional]
       
    47 #
       
    48 # Outputs
       
    49 #
       
    50 # Description
       
    51 # This function generates the MD5 checksum file
       
    52 
       
    53 sub MD5Generate
       
    54 {
       
    55   my ($iLeftDir, $iResultsFile, $iExclude, $iInclude, $iListFile, $iDumpDir) = @_;
       
    56 
       
    57   my (@iLeftFiles);
       
    58 
       
    59   # This should have been check before getting here but to be on the safe side
       
    60   # check again, as it should never overwrite or append to the file
       
    61   croak "$iResultsFile already exists" if (-e $iResultsFile);
       
    62   croak "$iListFile does exist" if ((defined($iListFile) && (!-e $iListFile)));
       
    63 
       
    64   if (-d $iLeftDir){
       
    65     # Make sure all the \ are / for the RegEx
       
    66     $iLeftDir =~ s/\\/\//g;
       
    67     # Make sure it does not have a / on the end
       
    68     $iLeftDir =~ s/\/$//;
       
    69     # If $iFileList is defined then use the filelist to generate @iLeftFiles
       
    70     if (defined($iListFile))
       
    71     {
       
    72       # Generate list of files
       
    73       @iLeftFiles = &FilterDir($iLeftDir,$iExclude,$iInclude, $iListFile);
       
    74     } else {
       
    75       # Generate the the directory listing
       
    76       @iLeftFiles = &FilterDir($iLeftDir,$iExclude,$iInclude);
       
    77     }
       
    78   } else {
       
    79     croak "$iLeftDir is not a directory";
       
    80   }
       
    81 
       
    82   # Open the results file for writing
       
    83   my ($fResultsFile) = new IO::File;
       
    84   croak "Cannot for $iResultsFile for writing" unless ($fResultsFile->open("> $iResultsFile"));
       
    85 
       
    86   # Write headers to the file
       
    87   print $fResultsFile "Host:".&hostname()."\n";
       
    88   print $fResultsFile "Username:".$ENV{'USERNAME'}."\n";
       
    89   print $fResultsFile "Date-Time:".scalar(localtime)."\n";
       
    90   print $fResultsFile "Version:".$VERSION."\n";
       
    91   print $fResultsFile "Directory:".$iLeftDir."\n";
       
    92   print $fResultsFile "FileList:".$iListFile."\n" if (defined($iListFile));
       
    93   print $fResultsFile "Exclusion(s):";
       
    94   foreach my $iExc (sort @$iExclude)
       
    95   {
       
    96     print $fResultsFile "$iExc ";
       
    97   }
       
    98   print $fResultsFile "\n";
       
    99 
       
   100   print $fResultsFile "Inclusion(s):";
       
   101   foreach my $iInc (@$iInclude)
       
   102   {
       
   103     print $fResultsFile "$iInc ";
       
   104   }
       
   105   print $fResultsFile "\n";
       
   106 
       
   107   print $fResultsFile "----------------\n";
       
   108 
       
   109   # Write out sorted list of files with MD5 Checksums
       
   110   foreach my $iFile (sort @iLeftFiles)
       
   111   {
       
   112     my ($MD5, $type) = &EvalidCompare::GenerateSignature($iLeftDir."/".$iFile, $iDumpDir);
       
   113     print $fResultsFile $iFile." TYPE=".$type." MD5=".$MD5."\n";
       
   114   }
       
   115 
       
   116   $fResultsFile->close;
       
   117 }
       
   118 
       
   119 
       
   120 # MD5Compare
       
   121 #
       
   122 # Inputs
       
   123 # $iLeftFile - Left side File containing listing and MD5 of left side
       
   124 # $iRightFile - Right side File containing listing and MD5 of right side
       
   125 # $iVerbose - Verbose Flag
       
   126 # $iLog - Logfile name
       
   127 #
       
   128 # Outputs
       
   129 # %iCommon - hash relative filenames with values of file type that are in both directories and Compare results/types
       
   130 # %iDiff - hash relative filenames with values of file type and directory side infomation
       
   131 #
       
   132 # Description
       
   133 
       
   134 sub MD5Compare
       
   135 {
       
   136   my ($iLeftFile) = shift;
       
   137   my ($iRightFile) = shift;
       
   138   my ($iVerbose) = defined($_[0]) ? shift : 0;
       
   139   my ($iLog) = defined($_[0]) ? shift : *STDOUT;
       
   140 
       
   141   my (%iCommon, %iDiff);
       
   142 
       
   143   my (%iLeftFiles, %iRightFiles);
       
   144   my (%iLeftHeaders, %iRightHeaders);
       
   145 
       
   146   # Backup check the files are available to read.
       
   147   croak "$iLeftFile is not a file" unless (-f $iLeftFile);
       
   148   croak "$iRightFile is not a file" unless(-f $iRightFile);
       
   149 
       
   150   #Read the files
       
   151   &ReadMD5File($iLeftFile, \%iLeftFiles, \%iLeftHeaders);
       
   152   &ReadMD5File($iRightFile, \%iRightFiles, \%iRightHeaders);
       
   153 
       
   154   # Check Critical headers
       
   155   foreach my $iHeader (sort keys %iLeftHeaders)
       
   156   {
       
   157     # Warning is certain headers are not identical
       
   158     if ($iHeader =~ /^Version|Exclusion\(s\)|Inclusion\(s\)/)
       
   159     {
       
   160       print $iLog "WARNING:$iHeader is different\n" if ($iLeftHeaders{$iHeader} ne $iRightHeaders{$iHeader});
       
   161     }
       
   162   }
       
   163 
       
   164   # A Hash is used to combine the two directory listing using the filename as the key
       
   165   my %iCombinedFiles;
       
   166 
       
   167   # Enter the files from the left side listing and check the right side critical header are the same
       
   168   # Note all filenames are turned to lower case as this is designed to only wotk on Windows
       
   169   foreach my $iFile (sort keys %iLeftFiles)
       
   170   {
       
   171     $iCombinedFiles{$iFile} = "Left";
       
   172   }
       
   173 
       
   174   # Enter the files from the right side listing
       
   175   # Note all filenames are turned to lower case as this is designed to only wotk on Windows
       
   176   foreach my $iFile (sort keys %iRightFiles)
       
   177   {
       
   178     # Check to see if any entry for this file exists on the left side
       
   179     if ((defined ($iCombinedFiles{$iFile})) && ( $iCombinedFiles{$iFile} eq "Left"))
       
   180     {
       
   181       # Yes, so add to the Common set
       
   182       # Check if the MD5 checksum matches
       
   183       # The [0] element is the file type
       
   184       if ($iLeftFiles{$iFile}[0] ne $iRightFiles{$iFile}[0])
       
   185       {
       
   186         $iCommon{$iFile} = [$iLeftFiles{$iFile}[0]." to ".$iRightFiles{$iFile}[0], "Type Changed"]; 
       
   187       } elsif ($iLeftFiles{$iFile}[1] eq $iRightFiles{$iFile}[1]) {
       
   188         $iCommon{$iFile} = [$iLeftFiles{$iFile}[0],"OK"];
       
   189       } else {
       
   190         $iCommon{$iFile} = [$iLeftFiles{$iFile}[0],"Different"];
       
   191       }
       
   192       # The filename key is not needed any more as both sides have been processed, so delete the hash entry
       
   193       delete $iCombinedFiles{$iFile};
       
   194     } elsif (!defined($iCombinedFiles{$iFile})) {
       
   195       # No, the key is not defined, so this filename is only in the right side
       
   196       $iDiff{$iFile} = [$iRightFiles{$iFile}[0],"Right"];
       
   197       # The filename key is not needed any more as both sides have been processed, so delete the hash entry
       
   198       delete $iCombinedFiles{$iFile};
       
   199     }
       
   200   }
       
   201 
       
   202   # Add the files left in the hash to the Left side only list
       
   203   foreach my $iFile (sort keys %iCombinedFiles)
       
   204   {
       
   205     $iDiff{$iFile} = [$iLeftFiles{$iFile}[0],"Left"];
       
   206   }
       
   207 
       
   208   # Return References to the Arrays
       
   209   return (\%iCommon, \%iLeftHeaders, \%iRightHeaders, \%iDiff);
       
   210 }
       
   211 
       
   212 # FilterDir
       
   213 #
       
   214 # Inputs
       
   215 # $iDir - Directory to process
       
   216 # $iExclude - Reference to array of regular expression patterns to exclude
       
   217 # $iInclude - Reference to array of regular expression patterns to include
       
   218 # $iListFile - Filename to read for list of files from [Optional]
       
   219 #
       
   220 # Outputs
       
   221 # @iFinalFileList - Filtered list relative filenames
       
   222 #
       
   223 # Description
       
   224 # This function produces a filtered list of filenames in the specified directory or from file
       
   225 
       
   226 sub FilterDir
       
   227 {
       
   228   my ($iDir,$iExclude,$iInclude, $iListFile) = @_;
       
   229 
       
   230   my (@iFileList, @iFinalFileList, $iFileName);
       
   231 
       
   232   if(defined($iListFile))
       
   233   {
       
   234     open LIST, "$iListFile" or croak "Cannot open $iListFile\n";
       
   235     while(<LIST>)
       
   236     {
       
   237       next if /^\s+$/;  # skip blank lines 
       
   238       my $iFileName = $iDir."/".$_;
       
   239       chomp $iFileName; # Remove new line
       
   240       if(-e $iFileName)
       
   241       {
       
   242         # The listed file exists add to the @iFileList
       
   243         push @iFileList, $iFileName;
       
   244       } else {
       
   245         print "Warning: Cannot find $iFileName\n";
       
   246       }
       
   247     }
       
   248     close LIST;
       
   249   } else {
       
   250     # Produce full filelist listing without directory names
       
   251     find sub { push @iFileList, $File::Find::name if (!-d) ;}, $iDir;
       
   252   }
       
   253 
       
   254   foreach my $iFile ( @iFileList)
       
   255   {
       
   256     my $iExcludeFile = 0;
       
   257 
       
   258     # Remove the specified directory path from the front of the filename
       
   259     $iFile =~ s#^$iDir/##;
       
   260 
       
   261     # Process all Exclude RegEx to see if this file matches
       
   262     foreach my $iExcludeRegEx (@$iExclude)
       
   263     {
       
   264       if ($iFile =~ /$iExcludeRegEx/i)
       
   265       {
       
   266         # Mark this file to be excluded from the final list
       
   267         $iExcludeFile = 1;
       
   268       }
       
   269     }
       
   270 
       
   271     # Process all Include RegEx to see if this file matches
       
   272     foreach my $iIncludeRegEx (@$iInclude)
       
   273     {
       
   274       if ($iFile =~ /$iIncludeRegEx/i)
       
   275       {
       
   276         # Mark this file to be Included in the final list
       
   277         $iExcludeFile = 0;
       
   278       }
       
   279     }
       
   280 
       
   281     # Added the file to the final list based on the flag
       
   282     push @iFinalFileList, lc($iFile) unless $iExcludeFile;
       
   283   }
       
   284 
       
   285   return @iFinalFileList;
       
   286 
       
   287 }
       
   288 
       
   289 # MD5ComparePrint
       
   290 #
       
   291 # Inputs
       
   292 # $iCommon - Reference to Hash of common file names and the result the comparision
       
   293 # $iLeftHeaders - Reference to Hash contain the left side
       
   294 # $iRightHeaders - Reference to Hash contain the right side
       
   295 # $iDiff - Reference to Hash of relative filenames with values of file type and left/right directory side
       
   296 # $iLog - Logfile name
       
   297 #
       
   298 # Outputs
       
   299 #
       
   300 # Description
       
   301 # This function prints the output of a Compare
       
   302 sub MD5ComparePrint
       
   303 {
       
   304   my ($iCommon) = shift;
       
   305   my ($iLeftHeaders) = shift;
       
   306   my ($iRightHeaders) = shift;
       
   307   my ($iDiff) = shift;
       
   308   my ($iLog) = shift;
       
   309 
       
   310   my ($iFailed) = 0; # Count of the failed comparisions
       
   311   my ($iPassed) = 0; # Count of the Passed comparisions
       
   312   my ($iLeft) = 0; # Count of the Passed comparisions
       
   313   my ($iRight) = 0; # Count of the Passed comparisions
       
   314 
       
   315 
       
   316   my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
       
   317   printf $iLog "\n----------------\n%02d:%02d %02d/%02d/%04d\n", $hour, $min, $mday, $mon+1, $year+1900;
       
   318   print $iLog "evalid\nLeft Side=$ARGV[0]\nRight Side=$ARGV[1]\n";
       
   319   print $iLog "\nLeft side information\n";
       
   320   foreach my $iHeader (sort keys %$iLeftHeaders)
       
   321   {
       
   322     print $iLog $iHeader.":".$$iLeftHeaders{$iHeader}."\n";
       
   323   }
       
   324   print $iLog "\nRight side information\n";
       
   325   foreach my $iHeader (sort keys %$iRightHeaders)
       
   326   {
       
   327     print $iLog $iHeader.":".$$iRightHeaders{$iHeader}."\n";
       
   328   }
       
   329   print $iLog "\n";
       
   330 
       
   331   foreach my $iFile (sort keys %$iCommon)
       
   332   {
       
   333     if ($$iCommon{$iFile}[1] eq "OK")
       
   334     {
       
   335       print $iLog "Passed:$iFile (".$$iCommon{$iFile}[0].")\n";
       
   336       $iPassed++;
       
   337     }
       
   338   }
       
   339   print $iLog "\n";
       
   340 
       
   341   foreach my $iFile (sort keys %$iCommon)
       
   342   {
       
   343     if ($$iCommon{$iFile}[1] eq "Type Changed")
       
   344     {
       
   345       print $iLog "Type Changed:$iFile (".$$iCommon{$iFile}[0].")\n";
       
   346       $iFailed++;
       
   347     }
       
   348   }
       
   349   print $iLog "\n";
       
   350 
       
   351   foreach my $iFile (sort keys %$iCommon)
       
   352   {
       
   353     if ($$iCommon{$iFile}[1] eq "Different")
       
   354     {
       
   355       print $iLog "Failed:$iFile (".$$iCommon{$iFile}[0].")\n";
       
   356       $iFailed++;
       
   357     }
       
   358   }
       
   359   print $iLog "\n";
       
   360 
       
   361   foreach my $iFile (sort keys %$iDiff)
       
   362   {
       
   363     if ($$iDiff{$iFile}[1] eq "Left")
       
   364     {
       
   365       print $iLog "Missing Left:$iFile (".$$iDiff{$iFile}[0].")\n";
       
   366       $iLeft++;
       
   367     }
       
   368   }
       
   369   print $iLog "\n";
       
   370 
       
   371   foreach my $iFile (sort keys %$iDiff)
       
   372   {
       
   373     if ($$iDiff{$iFile}[1] eq "Right")
       
   374     {
       
   375       print $iLog "Missing Right:$iFile (".$$iDiff{$iFile}[0].")\n";
       
   376       $iRight++;
       
   377     }
       
   378   }
       
   379 
       
   380   print $iLog "\n\nSummary\n";
       
   381   print $iLog "Total files processed=".($iPassed+$iFailed+$iRight+$iLeft)."\n";
       
   382   print $iLog "Files Passed=$iPassed\n";
       
   383   print $iLog "Files Failed=$iFailed\n";
       
   384   print $iLog "Missing Files in Left=".$iRight."\n";
       
   385   print $iLog "Missing Files in Right=".$iLeft."\n";
       
   386 
       
   387   return ($iFailed);
       
   388 }
       
   389 # NameOnly
       
   390 # 
       
   391 # Inputs
       
   392 # $filename - may contain path and file extension
       
   393 #
       
   394 # Outputs
       
   395 # $nameOnly - filename without extension and path
       
   396 #
       
   397 # Description
       
   398 # This routine is used to extract the name of the file
       
   399 # only from a filename that may include a path and file extension
       
   400 # 
       
   401 sub NameOnly
       
   402 {
       
   403   my ($filename) = @_;
       
   404   my $nameOnly = basename($filename);
       
   405   $nameOnly =~ s/(\w+.*)\.\w+$/$1/;
       
   406   return $nameOnly;
       
   407 }
       
   408 
       
   409 # MD5CompareZipDel
       
   410 #
       
   411 # Inputs
       
   412 # $iCommon - Reference to Hash of common file names and the result the comparision
       
   413 # $iDiff - Reference to Hash of relative filenames with values of file type and left/right directory side
       
   414 # $iLeft - filename of Left side directory
       
   415 # $iRight - filename of Right side directory
       
   416 #
       
   417 # Outputs
       
   418 #
       
   419 # Description
       
   420 # This function prints the output of a Compare results in a format ready for creating the a
       
   421 # Zip and batch file to upgrade the left side to the equivalent of the right side.
       
   422 sub MD5CompareZipDel
       
   423 {
       
   424   my ($iCommon) = shift;
       
   425   my ($iDiff) = shift;
       
   426   my ($iLeft) = shift;
       
   427   my ($iRight) = shift;
       
   428 
       
   429   # Build a suitable name for outputfiles based on input filenames
       
   430   $iLeft = NameOnly($iLeft);
       
   431   $iRight = NameOnly($iRight);
       
   432   my ($iBasename) = $iLeft."_to_".$iRight;
       
   433 
       
   434   open DELLIST, ">del_$iBasename.bat";
       
   435   open ZIPLIST, ">zip_$iBasename.log";
       
   436   open ZIPBAT, ">zip_$iBasename.bat";
       
   437 
       
   438   foreach my $iFile (sort keys %$iCommon)
       
   439   {
       
   440     if (($$iCommon{$iFile}[1] eq "Different") || ($$iCommon{$iFile}[1] eq "Type Changed"))
       
   441     {
       
   442       print ZIPLIST "$iFile\n";
       
   443     }
       
   444   }
       
   445 
       
   446   foreach my $iFile (sort keys %$iDiff)
       
   447   {
       
   448     if ($$iDiff{$iFile}[1] eq "Right")
       
   449     {
       
   450       print ZIPLIST "$iFile\n";
       
   451     } else {
       
   452       # DEL needs the / to be \
       
   453       $iFile =~ s/\//\\/g;
       
   454       print DELLIST "del /F $iFile\n";
       
   455     }
       
   456   }
       
   457 
       
   458   print ZIPBAT "zip $iBasename.zip -@<zip_$iBasename.log\n";
       
   459 
       
   460   close DELLIST;
       
   461   close ZIPLIST;
       
   462   close ZIPBAT;
       
   463 
       
   464 }
       
   465 
       
   466 
       
   467 # Private
       
   468 
       
   469 # ReadMD5File
       
   470 #
       
   471 # Inputs
       
   472 # $iResultsFile - Results filename to process
       
   473 # $iResults - Reference to Results Hash
       
   474 # $iHeaders - Reference to Headers Hash
       
   475 #
       
   476 # Outputs
       
   477 #
       
   478 # Description
       
   479 # This function reads the conntent of the MD5 File in to a Hash
       
   480 sub ReadMD5File
       
   481 {
       
   482   my ($iResultsFile, $iResults, $iHeaders) = @_;
       
   483 
       
   484   # Open the results file for reading
       
   485   open (INPUT, "$iResultsFile") or croak "Cannot for $iResultsFile for reading";
       
   486   while (<INPUT>)
       
   487   {
       
   488     if (/^(\S+?):(.*)/)
       
   489     {
       
   490       $$iHeaders{$1} = $2;
       
   491     } elsif (/^(\S+?)\sTYPE=(.*?)\sMD5=(.*)/){
       
   492       $$iResults{$1} = [$2,$3];
       
   493     }
       
   494   }
       
   495   close INPUT;
       
   496 
       
   497 }
       
   498 
       
   499 1;