Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1050 lines
33 KiB

#
#
# TODO NOTES:
#
# batch and perform MD5 checksum checks
# output file of what we decided was golden
# be sure we return a status that gets warning message sent if we are unhappy
# check that we are setting the dates correctly
# see if we can work with files under lang\ (or other sub-directories)
# be sure Wade is happy
#
# FileName: PopFilter.pl
#
# Script for building Windows .Net Server builds and XP Client SP1 together.
# Have any changes to this file reviewed by DavePr, BryanT, or BPerkins before checking in.
#
# Usage = PopFilter.pl [-fake]
# Usage = PopFilter.pl [-fake] [-vbl=vblreleasedir] [-xpsp1=xpsp1dir] [-nttree=nttreedir] [-nocompare]
#
# Function: Populate missing files in nttreedir from vblreleaseddir so
# 1) Find the XPSP1 directory, searching under
# xpsp1dir
# SDXROOT\..
# VBL_RELEASE
# \\winbuilds\release\main\usa
# And read in the Version information and the GoldTimestamps
# 2) Read in SDXROOT\dbdir\LockedDB and parse into several piles:
# CheckFiles -- non-PE files that should be found to be completely unchanged -- measured by
# an external date/size/checksum. .inf files are checked for size/date after
# removing the DriverVer= line This check probably will just say UNICODE INFs miscompare.
# CheckPEFiles -- PE files that should be found to be completely unchanged -- measured by
# an internal date/checksum.
# PEReplaceFiles -- PE files that are expected to have been re-built, but should be the same as measured
# by xpsp1compdir /i /b /y [someday just /y].
# 3) Check CheckFiles unless -nocompare.
# 4) Check CheckPEFiles unless -nocompare.
# 5) Check PEReplaceFiles against XPSP1\Reference\* -- unless -nocompare or CHK or ClientSDXRoot in version != SDXROOT
# 6) Pick a source directory for PEReplaceFiles according to the following algorithm
# XPSP1\Checked -- if this is a checked build, and this directory exists
# XPSP1\Gold -- if this directory exists
# XPSP1\Reference -- otherwise
# 7) Replace files (unless check said not to).
#
# [-verbose] -- chatter while working
# [-fake] -- don't actually make any changes
# [-force] -- force copies even if errors on comparisons -- but miscompares never copied
# [-filter] -- copy over the files from the client if no mismatches or -force
# [-nofilter] -- do not copy over the client files (kind of an official -fake). The default is $NoFilter -- for now.
# [-test] -- hook for special testing
#
# [-nodates] -- turn off date comparisons in non-PE files and rely on size and checksum
#
#######################################
### TEMPORARY -- REMOVE THESE LINES ###
#######################################
# [-ignoreinf] -- temporary flag to ignore INF files if sizes match, since the DriverVer issues wasn't fixed in the last test run
# [-testfilter=flags] -- restrict testing to files with the specified flags (BN, BF, PF, ...)
# [-testlimits=flags] -- limit testing to that specified by the flags {CF, PECF, RF)
#
#
# VBLpath will be computed from BuildMachines.txt if not supplied either
# on the command line, or in the VBL_RELEASE environment variable.
#
# WARNING:
# WARNING: make sure pathname comparisons are case insensitive.
# WARNING: Either convert the case (e.g. with 'lc') or do the comparisons like this:
# WARNING: if ($foo =~ /^\Q$bar\E$/i) {}
# WARNING: or if ($foo !~ /^\Q$bar\E$/i) {}
# WARNING:
$begintime = time();
$VBLPathVariableName = 'VBL_RELEASE';
$BuildMachinesFile = $ENV{ "RazzleToolPath" } . "\\BuildMachines.txt";
$PopFilterDir = $ENV{ "RazzleToolPath" } . "\\PopFilter";
$LogFile = "build.popfilter";
$TestFile = "build.popfilter-test";
$GoldFiles = "build.GoldFiles";
$xpsp1dir = "";
$Winbuilds = "\\\\winbuilds\\release\\main\\usa";
$SERVERDIRNAME = "REPLACED_SERVER_FILES";
$CLIENTDIRNAME = "INCOMING_CLIENT_FILES";
$dbdir = "MergedComponents\\PopFilter";
$LockedDatabase = "LockedDB";
$SymbolFiles = "SymbolFiles";
#$comptool = "tools\\PopFilter\\popcompdir.exe /y /i /b";
$comptool = "tools\\PopFilter\\pecomp.exe /OnlyPE /Silent ";
$PECOMPERROR = 999999999;
#
# Usage variables
#
$PGM='PopFilter: ';
$Usage = $PGM . "Usage: PopFilter.pl [-fake] [-vbl=vblreleasedir] [-xpsp1=xpsp1dir] [-nttree=nttreedir] [-nocompare]\n";
#
# Get the current directory
#
open CWD, 'cd 2>&1|';
$CurrDir = <CWD>;
close CWD;
chomp $CurrDir;
$CurrDrive = substr($CurrDir, 0, 2);
#
# Check variables expected to be set in the environment.
#
$sdxroot = $ENV{'SDXROOT'} or die $PGM, "Error: SDXROOT not set in environment\n";
$buildarch = $ENV{'_BuildArch'} or die $PGM, "Error: _BuildArch not set in environment\n";
$computername = $ENV{'COMPUTERNAME'} or die $PGM, "Error: COMPUTERNAME not set in environment\n";
$branchname = $ENV{'_BuildBranch'} or die $PGM, "Error: _BuildBranch not set in environment\n";
$foo = $ENV{'NTDEBUG'} or die $PGM, "Error: NTDEBUG not set in environment\n";
$dbgtype = 'chk';
$dbgtype = 'fre' if $foo =~ /nodbg$/i;
$chkbuild = ($dbgtype eq 'chk');
$official = $ENV{'OFFICIAL_BUILD_MACHINE'};
#
# initialize argument variables
#
$Test = $ENV{'POPFILTER_TEST'};
$Force = $ENV{'POPFILTER_FORCE'};
$Fake = $ENV{'POPFILTER_FAKE'};
$Verbose = $ENV{'POPFILTER_VERBOSE'};
#
# Reverse the order of the lines below to change default of $NoFilter
#
$NoFilter = !$ENV{'POPFILTER_FILTER'}; # default value for $NoFilter is TRUE.
$NoFilter = $ENV{'POPFILTER_NOFILTER'}; # default value for $NoFilter is FALSE.
$NoCompare = $ENV{'POPFILTER_NOCOMPARE'};
$NoPECompare= $ENV{'POPFILTER_NOPECOMPARE'};
$xpsp1dirarg= $ENV{'POPFILTER_XPSP1'};
$NoDates = $ENV{'POPFILTER_NODATES'};
$IgnoreINFs = $ENV{'POPFILTER_IGNOREINFS'};
$TestLimits = $ENV{'POPFILTER_TESTLIMITS'};
$TestFilters= $ENV{'POPFILTER_TESTFILTERS'};
#
# Debug routines for printing out variables
#
sub gvar {
for (@_) {
print "\$$_ = $$_\n";
}
}
#
# print on the various files
#
sub printall {
print LOGFILE @_;
print $PGM unless @_ == 1 and @_[0] eq "\n";
print @_;
}
sub printfall {
printf LOGFILE @_;
print $PGM unless @_ == 1 and @_[0] eq "\n";
printf @_;
}
#
# Sub hms
# Takes Argument time in seconds and returns as list of (hrs, mins, secs)
#
sub hms {
$s = shift @_;
$h = int ($s / 3600);
$s -= 3600*$h;
$m = int ($s / 60);
$s -= 60*$m;
return ($h, $m, $s);
}
#
# signal catcher (at least this would work on unix)
#
sub catch_ctrlc {
printall "Aborted.\n";
die $PGM, "Error: Aborted.\n";
}
$SIG{INT} = \&catch_ctrlc;
#
# routine to fully qualify a pathname
#
sub fullyqualify {
die $PGM . "Error: Internal error in fullpathname().\n" unless @_ == 1;
$_ = @_[0];
if (/\s/) { die $PGM, "Error: Spaces in pathnames not allowed: '", $_, "'\n"; }
return $_ unless $_; # empty strings are a noop
s/([^:])\\$/$1/; # get rid of trailing \
while (s/\\\.\\/\\/) {} # get rid of \.\
while (s/\\[^\\]+\\\.\.\\/\\/) {} # get rid of \foo\..\
s/\\[^\\]+\\\.\.$/\\/; # get rid of \foo\..
s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
s/([^:])\\\.$/$1/; # get rid of foo\.
s/:\\\.$/:\\/; # get rid of x:\.
s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
s/^$CurrDrive[^\\]/$CurrDir\\/i; # convert drive-relative on current drive
if (/^[a-z]:\\/i) { return $_; } # full
if (/^\\[^\\].*/) { return "$CurrDrive$_"; } # rooted
if (/^\\\\[^\\]/) {
# print $PGM, 'Warning: Use of UNC name bypasses safety checks: ', $_, "\n";
return $_; # UNC
}
if (/^\.$/) { return "$CurrDir"; } # dot
if (/^$CurrDrive\.$/i) { return "$CurrDir"; } # dot on current drive
if (/^[^\\][^:].*/i) { return "$CurrDir\\$_"; } # relative
if (/^([a-z]:)([^\\].*)/i) { $drp = $CurrDir; # this case handled above
if ($1 ne $CurrDir) {
# $drp = $ENV{"=$1"}; # doesn't work!
die $PGM, "Error: Can't translate drive-relative pathnames: ", $_, "\n";
}
return "$drp\\$2"; # drive:relative
}
die $PGM, "Error: Unrecognized pathname format: $_\n";
}
#
# Routine to copy a file -- avoiding win32::CopyFile
#
# Not currently used
#
use Fcntl;
sub populatecopy {
my $writesize = 64*4096;
my($src, $dst) = @_;
my($infile, $outfile, $buf, $n, $r, $o);
if (not sysopen INFILE, $src, O_RDONLY() | O_BINARY()) {
return 0;
}
if (not sysopen OUTFILE, $dst, O_WRONLY() | O_CREAT() | O_TRUNC() | O_BINARY(), 0777) {
close INFILE;
return 0;
}
$r = 0; # need this to be defined in case INFILE is empty
ERR: while ($n = sysread INFILE, $buf, $writesize) {
last ERR unless defined $n;
$o = 0;
while ($n) {
$r = syswrite OUTFILE, $buf, $n, $o;
last ERR unless defined $r;
$n -= $r;
$o += $r;
}
}
close INFILE;
close OUTFILE;
return 0 if not defined $n or not defined $r or $n != 0;
return 1;
}
# Given a path to a file, strip off the
# file and check for the existence of
# the directory. If it does not exist,
# create it.
sub verifydestdir($)
{
my $dest = shift;
my $dest_dir, @dest_dir;
# Check for existence of destination dir
if ( $dest =~ /(.*)\\.*$/ && ! -d $1 ) {
$dest_dir = fullyqualify( $1 );
if ( $dest_dir =~ /^([a-zA-Z]\:\\[^\\]+)\\/ ||
$dest_dir =~ /^(\\\\[^\\]\\[^\\])\\/ ) {
my $initial = $1;
my $final = $';
@dest_dir = ( $initial, split /\\/, $final );
}
else {
@dest_dir = split /\\/, $dest_dir;
}
# Create destination directory
my $new_dir = "";
foreach (@dest_dir) {
$new_dir .= "$_\\";
return if ( ! -d $new_dir && !mkdir $new_dir, 0777 );
}
}
return 1;
}
use File::Copy;
use File::Compare;
use Win32::File qw(SetAttributes);
sub copyex($$)
{
my ($src, $dest) = @_;
return (verifydestdir($dest) && copy($src, $dest));
}
sub renameex($$)
{
my ($src, $dest) = @_;
return (verifydestdir($dest) && rename($src,$dest));
}
#
# Process and validate arguments
#
for (@ARGV) {
if (/^[\/\-]test$/i) { $Test++; next; }
if (/^[\/\-]fake$/i) { $Fake++; next; }
if (/^[\/\-]verbose$/i) { $Verbose++; next; }
if (/^[\/\-]force$/i) { $Force++; next; }
if (/^[\/\-]filter$/i) { $NoFilter = 0; next; }
if (/^[\/\-]nofilter$/i) { $NoFilter = 1; next; }
if (/^[\/\-]nocompare$/i) { $NoCompare++; next; }
if (/^[\/\-]nopecompare$/i) { $NoPECompare++; next; }
if (/^[\/\-]nodates$/i) { $NoDates++; next; }
if (/^[\/\-]ignoreinfs$/i) { $IgnoreINFs++; next; }
if (/^[\/\-]vbl=(.+)$/i) { $VBL = $1; next; }
if (/^[\/\-]nttree=(.+)$/i) { $nttree = $1; next; }
if (/^[\/\-]xpsp1=(.+)$/i) { $xpsp1dirarg = $1; next; }
if (/^[\/\-]testfilters=(.*)$/i) { $TestFilters = $1; next; }
if (/^[\/\-]testlimits=(.*)$/i) { $TestLimits = $1; next; }
if (/^[\/\-]?$/i) { die $Usage; }
if (/^[\/\-]help$/i) { die $Usage; }
die $Usage;
}
#
# If we didn't get the NTTree directory from the command line,
# get it from the _NTTREE environment variable.
#
$nttree = $ENV{'_NTTREE'} unless $nttree;
$t = $NoFilter? 'NOFILTER' : 'FILTER';
$t .= ' NOCOMPARE' if $NoCompare;
$t .= ' NOPECOMPARE' if $NoPECompare;
$t .= ' NODATES' if $NoDates;
$t .= ' VERBOSE' if $Verbose;
$t .= ' FORCE' if $Force;
$t .= ' FAKE' if $Fake;
$t .= ' TEST' if $Test;
$t .= ' IGNOREINFs' if $IgnoreINFs;
$t .= " XPSP1=$xpsp1dirarg" if $xpsp1dirarg;
$t .= " LIMITS=$TestLimits" if $TestLimits;
$t .= " LIMITS=$TestLimits" if $TestFilters;
printall "OPTIONS: $t\n";
if ($TestLimits) {
$what = '';
for (split /,/, $TestLimits) {
$testlimitedto{$_}++;
$what .= " $_";
}
printall "Limiting test to:$what\n";
}
if ($TestFilters) {
$what = '';
for (split /,/, $TestFilters) {
$testfilteredto{$_}++;
$what .= " $_";
}
printall "Filtering files by:$what\n";
}
#
# Can only popfilter with the current directory the same as sdxroot.
#
die $PGM, "Error: Can only popfilter if CD <$CurrDir> is SDXROOT <$sdxroot>\n" unless $sdxroot =~ /^\Q$CurrDir\E$/io;
#
# If we didn't get the local target directory from the command line,
# get it from the environment. If that fails, we parse BuildMachines.txt.
#
$VBL = $ENV{$VBLPathVariableName} unless $VBL;
if ((not $VBL) || ($VBL =~ /^[\d\w_]+$/)) {
$tbranchname = $branchname;
$tbranchname = $VBL if $VBL =~ /^[\d\w_]+$/;
$fname = $BuildMachinesFile;
open BMFILE, $fname or die $PGM, "Error: Could not open: $fname\n";
for (<BMFILE>) {
s/\s+//g;
s/;.*$//;
next if /^$/;
($vblmach, $vblprime, $vblbranch, $vblarch, $vbldbgtype, $vbldl, $disttype, $alt_release ) = split /,/;
if ($vblarch =~ /\Q$buildarch\E/io and $vbldbgtype =~ /\Q$dbgtype\E/io
and $vblbranch =~ /\Q$tbranchname\E/io
and $disttype !~ /distbuild/i) {
if ( defined $alt_release) {
$dname = $alt_release;
last;
}
else {
$dname = "\\\\$vblmach\\release";
}
opendir BDIR, "$dname\\" or die $PGM, "Error: Could not open directory: $dname\n";
@reldirs = readdir BDIR;
close BDIR;
$rname = 0;
$date = 0;
for (@reldirs) {
next unless /[0-9]+\.$vblarch$vbldbgtype\.$vblbranch\.(.+)$/io;
($date = $1, $rname = $_) unless $date gt $1
or substr($date, 0, 2) eq '00' and substr($1, 0, 2) eq '99'; # Y2K trade-off
}
if (not $rname) {
print $PGM, "Warning: No valid release shares found on $dname.\n";
} else {
$VBL = "$dname\\$rname";
}
last;
}
}
close BMFILE;
}
die $PGM, "Error: Not a directory: ", $VBL, "\n" if $VBL and ! -d $VBL;
die $Usage unless $nttree;
die $PGM, "Error: Not a directory: ", $nttree, "\n" unless -d $nttree;
die $PGM, "Error: Not writable: ", $nttree, "\n" unless -w $nttree;
if (-d "$nttree\\$SERVERDIRNAME") {
warn $PGM, "Skipping populate filtering: $SERVERDIRNAME directory already exists\n";
exit 0;
}
die $PGM, "Error: $SERVERDIRNAME directory already exists\n" if -e "$nttree\\$SERVERDIRNAME";
die $PGM, "Error: $CLIENTDIRNAME directory already exists\n" if -e "$nttree\\$CLIENTDIRNAME";
#
# Fully qualify the pathnames
#
$VBL = fullyqualify($VBL) if $VBL;
$nttree = fullyqualify($nttree);
#
# Open the logfile, and maybe the testfile
# Open the build.GoldFiles file.
#
$foo = "$nttree\\build_logs\\$LogFile";
open LOGFILE, ">>$foo" or die $PGM, "Error: Could not create logfile: ", $foo, ": $!\n";
open TSTFILE, ">$TestFile" or die $PGM, "Error: Could not create testfile: ", $TestFile, ": $!\n" if $Test;
open GOLDFILESFILE, ">$GoldFiles" or die $PGM, "Error: Could not create testfile: ", $GoldFiles, ": $!\n";
#
# Find the XPSP1 directory
#
$t = $xpsp1dirarg;
if (not $xpsp1dir and -d $t and -s "$t\\Version" and -d "$t\\Reference") {
printall "WARNING: XPSP1DIR: $xpsp1dir invalid (Version or Reference\\ missing)\n";
$xpsp1dir = "";
}
$xpsp1dir = "";
$tries = 0;
@slist = ();
push @slist, ( "$xpsp1dirarg", "$xpsp1dirarg\\XPSP1" ) if $xpsp1dirarg;
push @slist, ( "$sdxroot\\XPSP1", "$VBL\\XPSP1", "$Winbuilds\\XPSP1" );
for ( @slist ) {
$tries++;
$xpsp1dir = $_ if -d $_ and -s "$_\\Version" and -d "$_\\Reference";
last if $xpsp1dir;
}
die "Could not find XPSP1 (@slist)\n" unless $xpsp1dir;
printall "WARNING: XPSP1DIR: $xpsp1dirarg invalid (Version or Reference\\ missing)\n" if $xpsp1dirarg and $tries > 2;
printall "Comparing against: $xpsp1dir\n";
#
# Read in the Version information
#
$tname = "$xpsp1dir\\Version";
open VERSION, "<$tname" or die "Could not open $tname\n";
for (<VERSION>) {
chop;
s/\s*\#.*$//;
next if /^\s*$/;
s/^\s*//;
s/\s*=\s*/=/;
($tkey, $tvalue) = split '=', $_, 2;
$verinfo{lc $tkey} = $tvalue;
}
close VERSION;
#
# Read in the GoldTimestamps
#
$tname = "$xpsp1dir\\GoldTimestamps";
open GOLDSTAMPS, "<$tname" or die "Could not open $tname\n";
for (<GOLDSTAMPS>) {
chop;
s/\s*\#.*$//;
next if /^\s*$/;
s/^\s*//;
s/\s*=\s*/=/;
($tfile, $tstamp, $tlen, $tmd5) = split ' ', $_, 4;
$tfile = lc $tfile;
$GoldStamp{$tfile} = $tstamp;
$GoldMD5{$tfile} = $tmd5;
$GoldLength{$tfile} = $tlen;
}
close VERSION;
printall "ClientSDXRoot defaulting to D:\\NT because undefined in Version\n" unless $verinfo{lc ClientSDXRoot};
@list = ( 'ClientFileVersion', 'ClientSDXRoot' );
for ( @list ) {
printall "Version Info: $_=$verinfo{lc $_}\n";
}
if ($Test) {
print "Version info:\n";
for (sort keys %verinfo) {
print "$_ = $verinfo{$_}\n";
}
}
#
# Parse LockedDatabase into CheckFiles, CheckPEFiles and PEReplaceFiles.
#
$t = "$sdxroot\\$dbdir\\$LockedDatabase";
open LOCKEDDB, "<$t" or die "Could not open: $t\n";
$lineno = 0;
for (<LOCKEDDB>) {
$lineno++;
chop;
s/\s*[#;].*//;
next if /^$/;
s/\s+/ /g;
($fname, $rest) = split " ", $_, 2;
$fname = lc $fname;
$lockeddb{$fname} = $rest;
#
# act_plcy.htm
# no @htm 3b634b0a 58548 - 106c - Sat_Jul_28_16:30:18_2001 F
# fname
# 0 drivercab (+no, +yes)
# 1 filetype (EXE, DLL, @ext)
# 2 timestamp
# 3 PE checksum
# 4 MD5 checksum
# 5 --
# 6 magic (size)
# 7 --
# 8 datestring
# 9 category type ( BD BF BFI D F FI PD PF )
#
@fields = split " ", $rest;
$category = $fields[9];
next if $TestFilters and not $testfilteredto{$category};
if ($category =~ /^P/) {
push @PEReplaceFiles, $fname;
} elsif ($fields[1] =~ /^\@/) {
push @CheckFiles, $fname;
} else {
die "$LockedDatabase corrupt at line $lineno: (", $fname, @fields, ")\n" unless $category =~ /^B/;
push @CheckPEFiles, $fname;
}
}
close LOCKEDDB;
printfall "%-5d files to just Check, %-5d files to maybe replace from client RTM.\n",
@CheckFiles + @CheckPEFiles, scalar @PEReplaceFiles;
$PEMismatches = 0;
$OtherMismatches = 0;
$OtherPEMismatches = 0;
#
# Check CheckFiles unless -nocompare.
#
unless ($NoCompare) {
unless ($TestLimits and not $testlimitedto{'CF'}) {
for (sort @CheckFiles) {
$fname = "$nttree\\$_";
$openstring = /\.inf$/i ? "findstr /B /V DriverVer $fname |" : "<$fname";
$s = open CHKFD, "$openstring" or printall "Could not open for checking $openstring\n";
next unless $s;
@client = split " ", $lockeddb{$_};
@s = stat $fname;
$magic = $s[7]; # size
$timestamp = $s[9];
{
local $/;
$checksum = unpack ("%32C*", <CHKFD>);
}
close CHKFD;
$client[2] = hex $client[2];
$client[3] = hex $client[3];
$client[6] = hex $client[6];
$timestamp = $client[2] = 0 if $NoDates;
$checksum = $client[3] = 0 if $IgnoreINFs and $magic == $client[6] and /\.inf$/i;
if ($timestamp != $client[2] or $checksum != $client[3] or $magic != $client[6]) {
printfall "LockedDB %-13s (%8s, %8s, %8s) -> (%8s, %8s, %8s)\n",
'=> Built', 'timstamp', 'chksum', 'size(.)', 'timstamp', 'chksum', 'size(.)'
unless $HeaderOutputCF++;
$OtherMismatches++;
printfall "MISMATCH: %-13s (%8x, %8x, %8d) -> <%8x, %8x, %8d>\n",
$_, $client[2], $client[3], $client[6], $timestamp, $checksum, $magic;
} else {
push @FilesToStamp, $_;
printall "$_ NC NPE\n" if $Test;
}
}
}
unless ($TestLimits and not $testlimitedto{'PECF'}) {
for (sort @CheckPEFiles) {
$fname = "$nttree\\$_";
$s = open CHKFD, "<$fname" or printall "Could not open for checking $fname\n";
next unless $s;
$NoncopyCount++;
@client = split " ", $lockeddb{$_};
open FD, "link -dump -headers $fname|" or ($OtherPEErrors++, printall "Could not run link command on $fname\n");
$type = $pefile = $timestamp = $checksum = $entrypoint = $magic = $machine = $datestring = "?";
for (<FD>) {
$pefile += m/PE signature found/;
$timestamp = $1, $datestring = $2
if m/\s*([\dA-Z]+)\s+time date stamp\s+(.+)/;
$checksum = $1 if m/\s([\dA-Z]+)\s+checksum/;
$entrypoint = $1 if m/entry point\s+\(([\dA-Z]+)\)/;
}
close FD;
unless ($pefile) {
printall "Not a PE file: $fname\n";
$OtherPEMismatches++;
next;
}
$checksum = hex $checksum;
$timestamp = hex $timestamp;
$client[2] = hex $client[2];
$client[3] = hex $client[3];
if ($timestamp != $client[2] or $checksum != $client[3]) {
printfall "LockedDB %-13s (%8s, %8s) -> (%8s, %8s)\n",
'=> Built', 'timstamp', 'chksum', 'timstamp', 'chksum'
unless $HeaderOutputPECF++;
$OtherPEMismatches++;
printfall "MISMATCH: %-13s (%8x, %8x) -> <%8x, %8x>\n",
$_, $client[2], $client[3], $timestamp, $checksum;
} else {
push @FilesToStamp, $_;
printall "$_ NC PE\n" if $Test;
}
}
}
}
#
# Check PEReplaceFiles against XPSP1\Reference\* -- unless -nocompare or CHK or ClientSDXRoot in version != SDXROOT
#
$reason = "";
$reason = "checked build.\n" if $chkbuild;
$t = $verinfo{'clientsdxroot'};
#
# run even if there is an sdxroot mismatch, pecomp may still provide some benefit
#
#$reason = "sdxroot mismatch with comparison build ($t).\n" if $t ne $sdxroot;
$reason = "POPFILTER_NOPECOMPARE set in the environment.\n" if $nopecompare;
$reason = "Test limited to non PE files.\n" if not $reason and $TestLimits and not $testlimitedto{'RF'};
printall "PE Comparison not done because $reason\n" if $reason;
$PopFilterBytesSaved = 0;
if ($reason or $NoCompare) {
@filestocopy = @PEReplaceFiles;
printall @filestocopy . " files from LockedFiles/LockedDrivers may be replaced -- without comparison\n";
} else {
@filestocopy = ();
for (sort @PEReplaceFiles) {
$t = "$sdxroot\\$comptool $xpsp1dir\\Reference\\$_ $nttree\\$_";
#open COMP, "$t|" or die "Could not run $t\n";
# for compdir /y
# $realdifference = "";
# for (<COMP>) {
# $realdifference = $_ if /DIFFER/;
# }
# close COMP;
# for PECOMP
$realdifference = system($t);
if ($realdifference == 0) {
printall "SAME: $_\n" if $Test;
$PopFilterBytesSaved += hex $GoldLength{$_};
} elsif ($realdifference == $PECOMPERROR) {
printall "ERROR: unexpected error: $t\n";
$ToolProblems++;
} else {
printfall "DIFFER<%5d): $_\n", $realdifference if $Verbose;
$PEMismatches++;
}
if ($realdifference) {
} else {
push @filestocopy, $_;
push @FilesToStamp, $_;
}
}
printall @filestocopy . " files from LockedFiles/LockedDrivers may be replaced -- based on comparison\n";
}
# Read in list of known symbols
# on an official build machine
if ( $official ) {
$t = "$sdxroot\\$dbdir\\$SymbolFiles";
open SYMBOLDB, "<$t" or die "Could not open: $t\n";
$lineno = 0;
for (<SYMBOLDB>) {
$lineno++;
chop;
s/\s*[#;].*//;
next if /^$/;
my ($x, $y, $z) = split;
die "$SymbolFiles Corrupt at line $lineno: ($_)\n" unless ( defined $x && defined $y && defined $z );
$symbols{lc$x} = [$y, $z];
}
close SYMBOLDB;
# Associate symbols and files marked to be copied
@symbolstocopy = ();
foreach ( @filestocopy ) {
next unless ( exists $symbols{lc$_} );
my $relpath = $symbols{lc$_}->[0];
my $copypub = $symbols{lc$_}->[1];
if ( $copypub ) {
push @symbolstocopy, "symbols\\$relpath";
$GoldStamp{"symbols\\". lc$relpath} = $GoldStamp{$_};
push @FilesToStamp, "symbols\\". lc$relpath if @FilesToStamp;
}
push @symbolstocopy, "symbols.pri\\$relpath";
$GoldStamp{"symbols.pri\\". lc$relpath} = $GoldStamp{$_};
push @FilesToStamp, "symbols.pri\\". lc$relpath if @FilesToStamp;
}
}
$TotalCompareErrors = $OtherMismatches + $DroppedPEMismatches + $PEMismatches;
$checktime = time();
#
# Replace files on the list -- unless check says not to, or we had compare errors and we are not forcing.
#
printall "WARNING: Faking!!! Not really populating _NTTREE with client files\n" if $Fake and @filestocopy > 0;
printall @filestocopy + @symbolstocopy. " Files to copy\n";
$fatal = 0;
unless ($NoFilter or $Fake or not $Force and $TotalCompareErrors > 0) {
#
# Make directories.
#
$serverdir = "$nttree\\$SERVERDIRNAME";
$clientdir = "$nttree\\$CLIENTDIRNAME";
mkdir "$serverdir", 0777 or die "Could not mkdir $serverdir\n";
mkdir "$clientdir", 0777 or die "Could not mkdir $clientdir\n";
printall "Created $serverdir to save replaced files.\n";
printall "Created $clientdir to stage replacement files.\n";
#
# Pick a source directory for PEReplaceFiles according to the following algorithm
# XPSP1\Checked -- if this is a checked build, and this directory exists
# XPSP1\Gold -- if this directory exists
# XPSP1\Reference -- otherwise
# And check that all the files we need to replace exist there. And copy them down.
# Check existence using a file from $PEReplaceFiles
#
$testfile = $PEReplaceFiles[0];
@list = ();
push @list, 'Checked' if $chkbuild;
push @list, 'Gold';
push @list, 'Reference';
$sourcedir = "";
for ( @list ) {
$t = "$xpsp1dir\\$_";
$sourcedir = "$t" if -s "$t\\$testfile";
last if $sourcedir;
}
die "Could not find source directory for binaries under $xpsp1dir (using $testfile)\n" unless $sourcedir;
printall "Source directory for client files: $sourcedir\n";
#
# Copy down all the client files
#
for (@filestocopy) {
$succ = copy ("$sourcedir\\$_", "$clientdir\\$_");
printall ("Error copying $_ from $sourcedir to $clientdir\n"), $fatal++ unless $succ;
$CopyCount++;
$CopyBytes += -s "$clientdir\\$_";
}
for $sym (@symbolstocopy) {
$succ = copyex( $sourcedir."Symbols\\$sym", "$clientdir\\$sym");
printall ("Error copying $sym from $sourcedir". "Symbols to $clientdir\n"), $fatal++ unless $succ;
# Treat symbols same as other files now for rename
push @filestocopy, $sym;
$SymCopyCount++;
$CopyBytes += -s "$clientdir\\$sym";
}
die $PGM, "Failure to copy down all the expected client files is fatal.\n" if $fatal;
#
# Move the server files out of the way.
#
for $f (@filestocopy) {
if (-s "$nttree\\$f") {
$succ = renameex ("$nttree\\$f", "$serverdir\\$f");
printall ("Error moving $f from $nttree to $serverdir\n"), $fatal++ unless $succ;
} else {
$missingserverfiles++;
printall "WARNING: $f does not exist in $nttree\n";
}
}
printall "WARNING: $missingserverfiles files found missing from server\n" if $missingserverfiles;
die $PGM, "Fatal error moving aside client files to $serverdir - Move them back manually.\n" if $fatal;
#
# Move in the client files.
#
for $f (@filestocopy) {
$succ = renameex ("$clientdir\\$f", "$nttree\\$f");
printall ("Error moving $f from $clientdir to $nttree\n"), $fatal++ unless $succ;
}
die $PGM, "Fatal error moving in client files from $clientdir."
. " May need to put back server files ($serverdir) manually.\n" if $fatal;
} else {
printall "WARNING: Not populating _NTTREE with client files:\n";
printall " NoFilter=$NoFilter Fake=$Fake Force=$Force TotalCompareErrors=$TotalCompareErrors\n";
}
#
# Set the gold timestamp on the files which matches or were successfully compared file if there was no mismatch
#
unless (scalar @FilesToStamp) {
push @FilesToStamp, @CheckFiles;
push @FilesToStamp, @CheckPEFiles;
push @FilesToStamp, @PEReplaceFiles;
if ( $official ) {
foreach ( @PEReplaceFiles ) {
next unless ( exists $symbols{lc$_} );
my $relpath = $symbols{lc$_}->[0];
my $copypub = $symbols{lc$_}->[1];
push @FilesToStamp, "symbols\\". lc$relpath if $copypub;
push @FilesToStamp, "symbols.pri\\". lc$relpath;
}
}
}
#
# set the timestamps on files
# and write the gold files list
#
$BytesSaved = 0;
unless ($Fake) {
for (@FilesToStamp) {
$stamp = lc $GoldStamp{$_};
if ( !SetAttributes("$nttree\\$_", 0) )
{
printall "ERROR: Resetting file attributes on $_ failed\n";
}
if ( !utime($begintime, hex $stamp, "$nttree\\$_") )
{
printall "ERROR: Updating time-stamp for $nttree\\$_ failed\n";
}
printall "Could not find stamp for: $_\n" unless $stamp;
printf GOLDFILESFILE "%s\n", $_;
$BytesSaved += hex $GoldLength{$_};
}
}
close GOLDFILESFILE;
#=======================================================================================================================
#=======================================================================================================================
#
# At this point we remember $begintime, $checktime, and have $CopyBytes, $CopyCount,
# $PEMismatches, $OtherMismatches and $OtherPEMismatches.
# $nttree and $sourcedir are also available.
# LOGFILE and TSTFILE are open
# $Fake and $Test may be set.
#
$t0 = $checktime - $begintime;
$t1 = time() - $checktime;
($h0, $m0, $s0) = hms $t0;
($h1, $m1, $s1) = hms $t1;
($h2, $m2, $s2) = hms ($t0 + $t1);
$KB = $CopyBytes/1024;
$MB = $KB/1024;
$kbrate = $KB/$t1 unless not $t1;
printfall "Populated $nttree with $CopyCount CLIENT RTM files ".(@symbolstocopy?"and $SymCopyCount CLIENT RTM symbols ":"")."(%4.0f MB)"
. " from $sourcedir".(@symbolstocopy?"[Symbols] ":"")." [%7.2f KB/S]\n" ,
$MB, $kbrate;
printall "Verified $NoncopyCount CLIENT RTM files.\n";
if ($PEMismatches or $OtherMismatches or $OtherPEMismatches) {
printall "ERROR: $PEMismatches mismatches in built PE files,\n";
printall "ERROR: $OtherMismatches mismatches in other files, and\n";
printall "ERROR: $OtherPEMismatches other PE files had unexpected mismatches!\n";
}
if ($ToolProblems) {
printall "ERROR: $ToolProblems problems with the tools.\n";
}
printfall "Reused %5d XP/RTM files totalling %4d MB\n", scalar @FilesToStamp, $BytesSaved/1000000;
printfall "Only %5d XP/RTM files totalling %4d MB due to popfilter\n", scalar $CopyCount, $PopFilterBytesSaved/1000000;
printfall "Checking time %5d secs (%d:%02d:%02d)\n", $t0, $h0, $m0, $s0;
printfall "CopyFile time %5d secs (%d:%02d:%02d)\n", $t1, $h1, $m1, $s1;
printfall "TotalTime time %5d secs (%d:%02d:%02d)\n", $t0+$t1, $h2, $m2, $s2;
#
# Return an error if we were faking so timebuild doesn't proceed.
#
close LOGFILE;
close TSTFILE if $Test;
exit $Fake;