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
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;
|
|
|