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

  1. #
  2. #
  3. # TODO NOTES:
  4. #
  5. # batch and perform MD5 checksum checks
  6. # output file of what we decided was golden
  7. # be sure we return a status that gets warning message sent if we are unhappy
  8. # check that we are setting the dates correctly
  9. # see if we can work with files under lang\ (or other sub-directories)
  10. # be sure Wade is happy
  11. #
  12. # FileName: PopFilter.pl
  13. #
  14. # Script for building Windows .Net Server builds and XP Client SP1 together.
  15. # Have any changes to this file reviewed by DavePr, BryanT, or BPerkins before checking in.
  16. #
  17. # Usage = PopFilter.pl [-fake]
  18. # Usage = PopFilter.pl [-fake] [-vbl=vblreleasedir] [-xpsp1=xpsp1dir] [-nttree=nttreedir] [-nocompare]
  19. #
  20. # Function: Populate missing files in nttreedir from vblreleaseddir so
  21. # 1) Find the XPSP1 directory, searching under
  22. # xpsp1dir
  23. # SDXROOT\..
  24. # VBL_RELEASE
  25. # \\winbuilds\release\main\usa
  26. # And read in the Version information and the GoldTimestamps
  27. # 2) Read in SDXROOT\dbdir\LockedDB and parse into several piles:
  28. # CheckFiles -- non-PE files that should be found to be completely unchanged -- measured by
  29. # an external date/size/checksum. .inf files are checked for size/date after
  30. # removing the DriverVer= line This check probably will just say UNICODE INFs miscompare.
  31. # CheckPEFiles -- PE files that should be found to be completely unchanged -- measured by
  32. # an internal date/checksum.
  33. # PEReplaceFiles -- PE files that are expected to have been re-built, but should be the same as measured
  34. # by xpsp1compdir /i /b /y [someday just /y].
  35. # 3) Check CheckFiles unless -nocompare.
  36. # 4) Check CheckPEFiles unless -nocompare.
  37. # 5) Check PEReplaceFiles against XPSP1\Reference\* -- unless -nocompare or CHK or ClientSDXRoot in version != SDXROOT
  38. # 6) Pick a source directory for PEReplaceFiles according to the following algorithm
  39. # XPSP1\Checked -- if this is a checked build, and this directory exists
  40. # XPSP1\Gold -- if this directory exists
  41. # XPSP1\Reference -- otherwise
  42. # 7) Replace files (unless check said not to).
  43. #
  44. # [-verbose] -- chatter while working
  45. # [-fake] -- don't actually make any changes
  46. # [-force] -- force copies even if errors on comparisons -- but miscompares never copied
  47. # [-filter] -- copy over the files from the client if no mismatches or -force
  48. # [-nofilter] -- do not copy over the client files (kind of an official -fake). The default is $NoFilter -- for now.
  49. # [-test] -- hook for special testing
  50. #
  51. # [-nodates] -- turn off date comparisons in non-PE files and rely on size and checksum
  52. #
  53. #######################################
  54. ### TEMPORARY -- REMOVE THESE LINES ###
  55. #######################################
  56. # [-ignoreinf] -- temporary flag to ignore INF files if sizes match, since the DriverVer issues wasn't fixed in the last test run
  57. # [-testfilter=flags] -- restrict testing to files with the specified flags (BN, BF, PF, ...)
  58. # [-testlimits=flags] -- limit testing to that specified by the flags {CF, PECF, RF)
  59. #
  60. #
  61. # VBLpath will be computed from BuildMachines.txt if not supplied either
  62. # on the command line, or in the VBL_RELEASE environment variable.
  63. #
  64. # WARNING:
  65. # WARNING: make sure pathname comparisons are case insensitive.
  66. # WARNING: Either convert the case (e.g. with 'lc') or do the comparisons like this:
  67. # WARNING: if ($foo =~ /^\Q$bar\E$/i) {}
  68. # WARNING: or if ($foo !~ /^\Q$bar\E$/i) {}
  69. # WARNING:
  70. $begintime = time();
  71. $VBLPathVariableName = 'VBL_RELEASE';
  72. $BuildMachinesFile = $ENV{ "RazzleToolPath" } . "\\BuildMachines.txt";
  73. $PopFilterDir = $ENV{ "RazzleToolPath" } . "\\PopFilter";
  74. $LogFile = "build.popfilter";
  75. $TestFile = "build.popfilter-test";
  76. $GoldFiles = "build.GoldFiles";
  77. $xpsp1dir = "";
  78. $Winbuilds = "\\\\winbuilds\\release\\main\\usa";
  79. $SERVERDIRNAME = "REPLACED_SERVER_FILES";
  80. $CLIENTDIRNAME = "INCOMING_CLIENT_FILES";
  81. $dbdir = "MergedComponents\\PopFilter";
  82. $LockedDatabase = "LockedDB";
  83. $SymbolFiles = "SymbolFiles";
  84. #$comptool = "tools\\PopFilter\\popcompdir.exe /y /i /b";
  85. $comptool = "tools\\PopFilter\\pecomp.exe /OnlyPE /Silent ";
  86. $PECOMPERROR = 999999999;
  87. #
  88. # Usage variables
  89. #
  90. $PGM='PopFilter: ';
  91. $Usage = $PGM . "Usage: PopFilter.pl [-fake] [-vbl=vblreleasedir] [-xpsp1=xpsp1dir] [-nttree=nttreedir] [-nocompare]\n";
  92. #
  93. # Get the current directory
  94. #
  95. open CWD, 'cd 2>&1|';
  96. $CurrDir = <CWD>;
  97. close CWD;
  98. chomp $CurrDir;
  99. $CurrDrive = substr($CurrDir, 0, 2);
  100. #
  101. # Check variables expected to be set in the environment.
  102. #
  103. $sdxroot = $ENV{'SDXROOT'} or die $PGM, "Error: SDXROOT not set in environment\n";
  104. $buildarch = $ENV{'_BuildArch'} or die $PGM, "Error: _BuildArch not set in environment\n";
  105. $computername = $ENV{'COMPUTERNAME'} or die $PGM, "Error: COMPUTERNAME not set in environment\n";
  106. $branchname = $ENV{'_BuildBranch'} or die $PGM, "Error: _BuildBranch not set in environment\n";
  107. $foo = $ENV{'NTDEBUG'} or die $PGM, "Error: NTDEBUG not set in environment\n";
  108. $dbgtype = 'chk';
  109. $dbgtype = 'fre' if $foo =~ /nodbg$/i;
  110. $chkbuild = ($dbgtype eq 'chk');
  111. $official = $ENV{'OFFICIAL_BUILD_MACHINE'};
  112. #
  113. # initialize argument variables
  114. #
  115. $Test = $ENV{'POPFILTER_TEST'};
  116. $Force = $ENV{'POPFILTER_FORCE'};
  117. $Fake = $ENV{'POPFILTER_FAKE'};
  118. $Verbose = $ENV{'POPFILTER_VERBOSE'};
  119. #
  120. # Reverse the order of the lines below to change default of $NoFilter
  121. #
  122. $NoFilter = !$ENV{'POPFILTER_FILTER'}; # default value for $NoFilter is TRUE.
  123. $NoFilter = $ENV{'POPFILTER_NOFILTER'}; # default value for $NoFilter is FALSE.
  124. $NoCompare = $ENV{'POPFILTER_NOCOMPARE'};
  125. $NoPECompare= $ENV{'POPFILTER_NOPECOMPARE'};
  126. $xpsp1dirarg= $ENV{'POPFILTER_XPSP1'};
  127. $NoDates = $ENV{'POPFILTER_NODATES'};
  128. $IgnoreINFs = $ENV{'POPFILTER_IGNOREINFS'};
  129. $TestLimits = $ENV{'POPFILTER_TESTLIMITS'};
  130. $TestFilters= $ENV{'POPFILTER_TESTFILTERS'};
  131. #
  132. # Debug routines for printing out variables
  133. #
  134. sub gvar {
  135. for (@_) {
  136. print "\$$_ = $$_\n";
  137. }
  138. }
  139. #
  140. # print on the various files
  141. #
  142. sub printall {
  143. print LOGFILE @_;
  144. print $PGM unless @_ == 1 and @_[0] eq "\n";
  145. print @_;
  146. }
  147. sub printfall {
  148. printf LOGFILE @_;
  149. print $PGM unless @_ == 1 and @_[0] eq "\n";
  150. printf @_;
  151. }
  152. #
  153. # Sub hms
  154. # Takes Argument time in seconds and returns as list of (hrs, mins, secs)
  155. #
  156. sub hms {
  157. $s = shift @_;
  158. $h = int ($s / 3600);
  159. $s -= 3600*$h;
  160. $m = int ($s / 60);
  161. $s -= 60*$m;
  162. return ($h, $m, $s);
  163. }
  164. #
  165. # signal catcher (at least this would work on unix)
  166. #
  167. sub catch_ctrlc {
  168. printall "Aborted.\n";
  169. die $PGM, "Error: Aborted.\n";
  170. }
  171. $SIG{INT} = \&catch_ctrlc;
  172. #
  173. # routine to fully qualify a pathname
  174. #
  175. sub fullyqualify {
  176. die $PGM . "Error: Internal error in fullpathname().\n" unless @_ == 1;
  177. $_ = @_[0];
  178. if (/\s/) { die $PGM, "Error: Spaces in pathnames not allowed: '", $_, "'\n"; }
  179. return $_ unless $_; # empty strings are a noop
  180. s/([^:])\\$/$1/; # get rid of trailing \
  181. while (s/\\\.\\/\\/) {} # get rid of \.\
  182. while (s/\\[^\\]+\\\.\.\\/\\/) {} # get rid of \foo\..\
  183. s/\\[^\\]+\\\.\.$/\\/; # get rid of \foo\..
  184. s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
  185. s/([^:])\\\.$/$1/; # get rid of foo\.
  186. s/:\\\.$/:\\/; # get rid of x:\.
  187. s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
  188. s/^$CurrDrive[^\\]/$CurrDir\\/i; # convert drive-relative on current drive
  189. if (/^[a-z]:\\/i) { return $_; } # full
  190. if (/^\\[^\\].*/) { return "$CurrDrive$_"; } # rooted
  191. if (/^\\\\[^\\]/) {
  192. # print $PGM, 'Warning: Use of UNC name bypasses safety checks: ', $_, "\n";
  193. return $_; # UNC
  194. }
  195. if (/^\.$/) { return "$CurrDir"; } # dot
  196. if (/^$CurrDrive\.$/i) { return "$CurrDir"; } # dot on current drive
  197. if (/^[^\\][^:].*/i) { return "$CurrDir\\$_"; } # relative
  198. if (/^([a-z]:)([^\\].*)/i) { $drp = $CurrDir; # this case handled above
  199. if ($1 ne $CurrDir) {
  200. # $drp = $ENV{"=$1"}; # doesn't work!
  201. die $PGM, "Error: Can't translate drive-relative pathnames: ", $_, "\n";
  202. }
  203. return "$drp\\$2"; # drive:relative
  204. }
  205. die $PGM, "Error: Unrecognized pathname format: $_\n";
  206. }
  207. #
  208. # Routine to copy a file -- avoiding win32::CopyFile
  209. #
  210. # Not currently used
  211. #
  212. use Fcntl;
  213. sub populatecopy {
  214. my $writesize = 64*4096;
  215. my($src, $dst) = @_;
  216. my($infile, $outfile, $buf, $n, $r, $o);
  217. if (not sysopen INFILE, $src, O_RDONLY() | O_BINARY()) {
  218. return 0;
  219. }
  220. if (not sysopen OUTFILE, $dst, O_WRONLY() | O_CREAT() | O_TRUNC() | O_BINARY(), 0777) {
  221. close INFILE;
  222. return 0;
  223. }
  224. $r = 0; # need this to be defined in case INFILE is empty
  225. ERR: while ($n = sysread INFILE, $buf, $writesize) {
  226. last ERR unless defined $n;
  227. $o = 0;
  228. while ($n) {
  229. $r = syswrite OUTFILE, $buf, $n, $o;
  230. last ERR unless defined $r;
  231. $n -= $r;
  232. $o += $r;
  233. }
  234. }
  235. close INFILE;
  236. close OUTFILE;
  237. return 0 if not defined $n or not defined $r or $n != 0;
  238. return 1;
  239. }
  240. # Given a path to a file, strip off the
  241. # file and check for the existence of
  242. # the directory. If it does not exist,
  243. # create it.
  244. sub verifydestdir($)
  245. {
  246. my $dest = shift;
  247. my $dest_dir, @dest_dir;
  248. # Check for existence of destination dir
  249. if ( $dest =~ /(.*)\\.*$/ && ! -d $1 ) {
  250. $dest_dir = fullyqualify( $1 );
  251. if ( $dest_dir =~ /^([a-zA-Z]\:\\[^\\]+)\\/ ||
  252. $dest_dir =~ /^(\\\\[^\\]\\[^\\])\\/ ) {
  253. my $initial = $1;
  254. my $final = $';
  255. @dest_dir = ( $initial, split /\\/, $final );
  256. }
  257. else {
  258. @dest_dir = split /\\/, $dest_dir;
  259. }
  260. # Create destination directory
  261. my $new_dir = "";
  262. foreach (@dest_dir) {
  263. $new_dir .= "$_\\";
  264. return if ( ! -d $new_dir && !mkdir $new_dir, 0777 );
  265. }
  266. }
  267. return 1;
  268. }
  269. use File::Copy;
  270. use File::Compare;
  271. use Win32::File qw(SetAttributes);
  272. sub copyex($$)
  273. {
  274. my ($src, $dest) = @_;
  275. return (verifydestdir($dest) && copy($src, $dest));
  276. }
  277. sub renameex($$)
  278. {
  279. my ($src, $dest) = @_;
  280. return (verifydestdir($dest) && rename($src,$dest));
  281. }
  282. #
  283. # Process and validate arguments
  284. #
  285. for (@ARGV) {
  286. if (/^[\/\-]test$/i) { $Test++; next; }
  287. if (/^[\/\-]fake$/i) { $Fake++; next; }
  288. if (/^[\/\-]verbose$/i) { $Verbose++; next; }
  289. if (/^[\/\-]force$/i) { $Force++; next; }
  290. if (/^[\/\-]filter$/i) { $NoFilter = 0; next; }
  291. if (/^[\/\-]nofilter$/i) { $NoFilter = 1; next; }
  292. if (/^[\/\-]nocompare$/i) { $NoCompare++; next; }
  293. if (/^[\/\-]nopecompare$/i) { $NoPECompare++; next; }
  294. if (/^[\/\-]nodates$/i) { $NoDates++; next; }
  295. if (/^[\/\-]ignoreinfs$/i) { $IgnoreINFs++; next; }
  296. if (/^[\/\-]vbl=(.+)$/i) { $VBL = $1; next; }
  297. if (/^[\/\-]nttree=(.+)$/i) { $nttree = $1; next; }
  298. if (/^[\/\-]xpsp1=(.+)$/i) { $xpsp1dirarg = $1; next; }
  299. if (/^[\/\-]testfilters=(.*)$/i) { $TestFilters = $1; next; }
  300. if (/^[\/\-]testlimits=(.*)$/i) { $TestLimits = $1; next; }
  301. if (/^[\/\-]?$/i) { die $Usage; }
  302. if (/^[\/\-]help$/i) { die $Usage; }
  303. die $Usage;
  304. }
  305. #
  306. # If we didn't get the NTTree directory from the command line,
  307. # get it from the _NTTREE environment variable.
  308. #
  309. $nttree = $ENV{'_NTTREE'} unless $nttree;
  310. $t = $NoFilter? 'NOFILTER' : 'FILTER';
  311. $t .= ' NOCOMPARE' if $NoCompare;
  312. $t .= ' NOPECOMPARE' if $NoPECompare;
  313. $t .= ' NODATES' if $NoDates;
  314. $t .= ' VERBOSE' if $Verbose;
  315. $t .= ' FORCE' if $Force;
  316. $t .= ' FAKE' if $Fake;
  317. $t .= ' TEST' if $Test;
  318. $t .= ' IGNOREINFs' if $IgnoreINFs;
  319. $t .= " XPSP1=$xpsp1dirarg" if $xpsp1dirarg;
  320. $t .= " LIMITS=$TestLimits" if $TestLimits;
  321. $t .= " LIMITS=$TestLimits" if $TestFilters;
  322. printall "OPTIONS: $t\n";
  323. if ($TestLimits) {
  324. $what = '';
  325. for (split /,/, $TestLimits) {
  326. $testlimitedto{$_}++;
  327. $what .= " $_";
  328. }
  329. printall "Limiting test to:$what\n";
  330. }
  331. if ($TestFilters) {
  332. $what = '';
  333. for (split /,/, $TestFilters) {
  334. $testfilteredto{$_}++;
  335. $what .= " $_";
  336. }
  337. printall "Filtering files by:$what\n";
  338. }
  339. #
  340. # Can only popfilter with the current directory the same as sdxroot.
  341. #
  342. die $PGM, "Error: Can only popfilter if CD <$CurrDir> is SDXROOT <$sdxroot>\n" unless $sdxroot =~ /^\Q$CurrDir\E$/io;
  343. #
  344. # If we didn't get the local target directory from the command line,
  345. # get it from the environment. If that fails, we parse BuildMachines.txt.
  346. #
  347. $VBL = $ENV{$VBLPathVariableName} unless $VBL;
  348. if ((not $VBL) || ($VBL =~ /^[\d\w_]+$/)) {
  349. $tbranchname = $branchname;
  350. $tbranchname = $VBL if $VBL =~ /^[\d\w_]+$/;
  351. $fname = $BuildMachinesFile;
  352. open BMFILE, $fname or die $PGM, "Error: Could not open: $fname\n";
  353. for (<BMFILE>) {
  354. s/\s+//g;
  355. s/;.*$//;
  356. next if /^$/;
  357. ($vblmach, $vblprime, $vblbranch, $vblarch, $vbldbgtype, $vbldl, $disttype, $alt_release ) = split /,/;
  358. if ($vblarch =~ /\Q$buildarch\E/io and $vbldbgtype =~ /\Q$dbgtype\E/io
  359. and $vblbranch =~ /\Q$tbranchname\E/io
  360. and $disttype !~ /distbuild/i) {
  361. if ( defined $alt_release) {
  362. $dname = $alt_release;
  363. last;
  364. }
  365. else {
  366. $dname = "\\\\$vblmach\\release";
  367. }
  368. opendir BDIR, "$dname\\" or die $PGM, "Error: Could not open directory: $dname\n";
  369. @reldirs = readdir BDIR;
  370. close BDIR;
  371. $rname = 0;
  372. $date = 0;
  373. for (@reldirs) {
  374. next unless /[0-9]+\.$vblarch$vbldbgtype\.$vblbranch\.(.+)$/io;
  375. ($date = $1, $rname = $_) unless $date gt $1
  376. or substr($date, 0, 2) eq '00' and substr($1, 0, 2) eq '99'; # Y2K trade-off
  377. }
  378. if (not $rname) {
  379. print $PGM, "Warning: No valid release shares found on $dname.\n";
  380. } else {
  381. $VBL = "$dname\\$rname";
  382. }
  383. last;
  384. }
  385. }
  386. close BMFILE;
  387. }
  388. die $PGM, "Error: Not a directory: ", $VBL, "\n" if $VBL and ! -d $VBL;
  389. die $Usage unless $nttree;
  390. die $PGM, "Error: Not a directory: ", $nttree, "\n" unless -d $nttree;
  391. die $PGM, "Error: Not writable: ", $nttree, "\n" unless -w $nttree;
  392. if (-d "$nttree\\$SERVERDIRNAME") {
  393. warn $PGM, "Skipping populate filtering: $SERVERDIRNAME directory already exists\n";
  394. exit 0;
  395. }
  396. die $PGM, "Error: $SERVERDIRNAME directory already exists\n" if -e "$nttree\\$SERVERDIRNAME";
  397. die $PGM, "Error: $CLIENTDIRNAME directory already exists\n" if -e "$nttree\\$CLIENTDIRNAME";
  398. #
  399. # Fully qualify the pathnames
  400. #
  401. $VBL = fullyqualify($VBL) if $VBL;
  402. $nttree = fullyqualify($nttree);
  403. #
  404. # Open the logfile, and maybe the testfile
  405. # Open the build.GoldFiles file.
  406. #
  407. $foo = "$nttree\\build_logs\\$LogFile";
  408. open LOGFILE, ">>$foo" or die $PGM, "Error: Could not create logfile: ", $foo, ": $!\n";
  409. open TSTFILE, ">$TestFile" or die $PGM, "Error: Could not create testfile: ", $TestFile, ": $!\n" if $Test;
  410. open GOLDFILESFILE, ">$GoldFiles" or die $PGM, "Error: Could not create testfile: ", $GoldFiles, ": $!\n";
  411. #
  412. # Find the XPSP1 directory
  413. #
  414. $t = $xpsp1dirarg;
  415. if (not $xpsp1dir and -d $t and -s "$t\\Version" and -d "$t\\Reference") {
  416. printall "WARNING: XPSP1DIR: $xpsp1dir invalid (Version or Reference\\ missing)\n";
  417. $xpsp1dir = "";
  418. }
  419. $xpsp1dir = "";
  420. $tries = 0;
  421. @slist = ();
  422. push @slist, ( "$xpsp1dirarg", "$xpsp1dirarg\\XPSP1" ) if $xpsp1dirarg;
  423. push @slist, ( "$sdxroot\\XPSP1", "$VBL\\XPSP1", "$Winbuilds\\XPSP1" );
  424. for ( @slist ) {
  425. $tries++;
  426. $xpsp1dir = $_ if -d $_ and -s "$_\\Version" and -d "$_\\Reference";
  427. last if $xpsp1dir;
  428. }
  429. die "Could not find XPSP1 (@slist)\n" unless $xpsp1dir;
  430. printall "WARNING: XPSP1DIR: $xpsp1dirarg invalid (Version or Reference\\ missing)\n" if $xpsp1dirarg and $tries > 2;
  431. printall "Comparing against: $xpsp1dir\n";
  432. #
  433. # Read in the Version information
  434. #
  435. $tname = "$xpsp1dir\\Version";
  436. open VERSION, "<$tname" or die "Could not open $tname\n";
  437. for (<VERSION>) {
  438. chop;
  439. s/\s*\#.*$//;
  440. next if /^\s*$/;
  441. s/^\s*//;
  442. s/\s*=\s*/=/;
  443. ($tkey, $tvalue) = split '=', $_, 2;
  444. $verinfo{lc $tkey} = $tvalue;
  445. }
  446. close VERSION;
  447. #
  448. # Read in the GoldTimestamps
  449. #
  450. $tname = "$xpsp1dir\\GoldTimestamps";
  451. open GOLDSTAMPS, "<$tname" or die "Could not open $tname\n";
  452. for (<GOLDSTAMPS>) {
  453. chop;
  454. s/\s*\#.*$//;
  455. next if /^\s*$/;
  456. s/^\s*//;
  457. s/\s*=\s*/=/;
  458. ($tfile, $tstamp, $tlen, $tmd5) = split ' ', $_, 4;
  459. $tfile = lc $tfile;
  460. $GoldStamp{$tfile} = $tstamp;
  461. $GoldMD5{$tfile} = $tmd5;
  462. $GoldLength{$tfile} = $tlen;
  463. }
  464. close VERSION;
  465. printall "ClientSDXRoot defaulting to D:\\NT because undefined in Version\n" unless $verinfo{lc ClientSDXRoot};
  466. @list = ( 'ClientFileVersion', 'ClientSDXRoot' );
  467. for ( @list ) {
  468. printall "Version Info: $_=$verinfo{lc $_}\n";
  469. }
  470. if ($Test) {
  471. print "Version info:\n";
  472. for (sort keys %verinfo) {
  473. print "$_ = $verinfo{$_}\n";
  474. }
  475. }
  476. #
  477. # Parse LockedDatabase into CheckFiles, CheckPEFiles and PEReplaceFiles.
  478. #
  479. $t = "$sdxroot\\$dbdir\\$LockedDatabase";
  480. open LOCKEDDB, "<$t" or die "Could not open: $t\n";
  481. $lineno = 0;
  482. for (<LOCKEDDB>) {
  483. $lineno++;
  484. chop;
  485. s/\s*[#;].*//;
  486. next if /^$/;
  487. s/\s+/ /g;
  488. ($fname, $rest) = split " ", $_, 2;
  489. $fname = lc $fname;
  490. $lockeddb{$fname} = $rest;
  491. #
  492. # act_plcy.htm
  493. # no @htm 3b634b0a 58548 - 106c - Sat_Jul_28_16:30:18_2001 F
  494. # fname
  495. # 0 drivercab (+no, +yes)
  496. # 1 filetype (EXE, DLL, @ext)
  497. # 2 timestamp
  498. # 3 PE checksum
  499. # 4 MD5 checksum
  500. # 5 --
  501. # 6 magic (size)
  502. # 7 --
  503. # 8 datestring
  504. # 9 category type ( BD BF BFI D F FI PD PF )
  505. #
  506. @fields = split " ", $rest;
  507. $category = $fields[9];
  508. next if $TestFilters and not $testfilteredto{$category};
  509. if ($category =~ /^P/) {
  510. push @PEReplaceFiles, $fname;
  511. } elsif ($fields[1] =~ /^\@/) {
  512. push @CheckFiles, $fname;
  513. } else {
  514. die "$LockedDatabase corrupt at line $lineno: (", $fname, @fields, ")\n" unless $category =~ /^B/;
  515. push @CheckPEFiles, $fname;
  516. }
  517. }
  518. close LOCKEDDB;
  519. printfall "%-5d files to just Check, %-5d files to maybe replace from client RTM.\n",
  520. @CheckFiles + @CheckPEFiles, scalar @PEReplaceFiles;
  521. $PEMismatches = 0;
  522. $OtherMismatches = 0;
  523. $OtherPEMismatches = 0;
  524. #
  525. # Check CheckFiles unless -nocompare.
  526. #
  527. unless ($NoCompare) {
  528. unless ($TestLimits and not $testlimitedto{'CF'}) {
  529. for (sort @CheckFiles) {
  530. $fname = "$nttree\\$_";
  531. $openstring = /\.inf$/i ? "findstr /B /V DriverVer $fname |" : "<$fname";
  532. $s = open CHKFD, "$openstring" or printall "Could not open for checking $openstring\n";
  533. next unless $s;
  534. @client = split " ", $lockeddb{$_};
  535. @s = stat $fname;
  536. $magic = $s[7]; # size
  537. $timestamp = $s[9];
  538. {
  539. local $/;
  540. $checksum = unpack ("%32C*", <CHKFD>);
  541. }
  542. close CHKFD;
  543. $client[2] = hex $client[2];
  544. $client[3] = hex $client[3];
  545. $client[6] = hex $client[6];
  546. $timestamp = $client[2] = 0 if $NoDates;
  547. $checksum = $client[3] = 0 if $IgnoreINFs and $magic == $client[6] and /\.inf$/i;
  548. if ($timestamp != $client[2] or $checksum != $client[3] or $magic != $client[6]) {
  549. printfall "LockedDB %-13s (%8s, %8s, %8s) -> (%8s, %8s, %8s)\n",
  550. '=> Built', 'timstamp', 'chksum', 'size(.)', 'timstamp', 'chksum', 'size(.)'
  551. unless $HeaderOutputCF++;
  552. $OtherMismatches++;
  553. printfall "MISMATCH: %-13s (%8x, %8x, %8d) -> <%8x, %8x, %8d>\n",
  554. $_, $client[2], $client[3], $client[6], $timestamp, $checksum, $magic;
  555. } else {
  556. push @FilesToStamp, $_;
  557. printall "$_ NC NPE\n" if $Test;
  558. }
  559. }
  560. }
  561. unless ($TestLimits and not $testlimitedto{'PECF'}) {
  562. for (sort @CheckPEFiles) {
  563. $fname = "$nttree\\$_";
  564. $s = open CHKFD, "<$fname" or printall "Could not open for checking $fname\n";
  565. next unless $s;
  566. $NoncopyCount++;
  567. @client = split " ", $lockeddb{$_};
  568. open FD, "link -dump -headers $fname|" or ($OtherPEErrors++, printall "Could not run link command on $fname\n");
  569. $type = $pefile = $timestamp = $checksum = $entrypoint = $magic = $machine = $datestring = "?";
  570. for (<FD>) {
  571. $pefile += m/PE signature found/;
  572. $timestamp = $1, $datestring = $2
  573. if m/\s*([\dA-Z]+)\s+time date stamp\s+(.+)/;
  574. $checksum = $1 if m/\s([\dA-Z]+)\s+checksum/;
  575. $entrypoint = $1 if m/entry point\s+\(([\dA-Z]+)\)/;
  576. }
  577. close FD;
  578. unless ($pefile) {
  579. printall "Not a PE file: $fname\n";
  580. $OtherPEMismatches++;
  581. next;
  582. }
  583. $checksum = hex $checksum;
  584. $timestamp = hex $timestamp;
  585. $client[2] = hex $client[2];
  586. $client[3] = hex $client[3];
  587. if ($timestamp != $client[2] or $checksum != $client[3]) {
  588. printfall "LockedDB %-13s (%8s, %8s) -> (%8s, %8s)\n",
  589. '=> Built', 'timstamp', 'chksum', 'timstamp', 'chksum'
  590. unless $HeaderOutputPECF++;
  591. $OtherPEMismatches++;
  592. printfall "MISMATCH: %-13s (%8x, %8x) -> <%8x, %8x>\n",
  593. $_, $client[2], $client[3], $timestamp, $checksum;
  594. } else {
  595. push @FilesToStamp, $_;
  596. printall "$_ NC PE\n" if $Test;
  597. }
  598. }
  599. }
  600. }
  601. #
  602. # Check PEReplaceFiles against XPSP1\Reference\* -- unless -nocompare or CHK or ClientSDXRoot in version != SDXROOT
  603. #
  604. $reason = "";
  605. $reason = "checked build.\n" if $chkbuild;
  606. $t = $verinfo{'clientsdxroot'};
  607. #
  608. # run even if there is an sdxroot mismatch, pecomp may still provide some benefit
  609. #
  610. #$reason = "sdxroot mismatch with comparison build ($t).\n" if $t ne $sdxroot;
  611. $reason = "POPFILTER_NOPECOMPARE set in the environment.\n" if $nopecompare;
  612. $reason = "Test limited to non PE files.\n" if not $reason and $TestLimits and not $testlimitedto{'RF'};
  613. printall "PE Comparison not done because $reason\n" if $reason;
  614. $PopFilterBytesSaved = 0;
  615. if ($reason or $NoCompare) {
  616. @filestocopy = @PEReplaceFiles;
  617. printall @filestocopy . " files from LockedFiles/LockedDrivers may be replaced -- without comparison\n";
  618. } else {
  619. @filestocopy = ();
  620. for (sort @PEReplaceFiles) {
  621. $t = "$sdxroot\\$comptool $xpsp1dir\\Reference\\$_ $nttree\\$_";
  622. #open COMP, "$t|" or die "Could not run $t\n";
  623. # for compdir /y
  624. # $realdifference = "";
  625. # for (<COMP>) {
  626. # $realdifference = $_ if /DIFFER/;
  627. # }
  628. # close COMP;
  629. # for PECOMP
  630. $realdifference = system($t);
  631. if ($realdifference == 0) {
  632. printall "SAME: $_\n" if $Test;
  633. $PopFilterBytesSaved += hex $GoldLength{$_};
  634. } elsif ($realdifference == $PECOMPERROR) {
  635. printall "ERROR: unexpected error: $t\n";
  636. $ToolProblems++;
  637. } else {
  638. printfall "DIFFER<%5d): $_\n", $realdifference if $Verbose;
  639. $PEMismatches++;
  640. }
  641. if ($realdifference) {
  642. } else {
  643. push @filestocopy, $_;
  644. push @FilesToStamp, $_;
  645. }
  646. }
  647. printall @filestocopy . " files from LockedFiles/LockedDrivers may be replaced -- based on comparison\n";
  648. }
  649. # Read in list of known symbols
  650. # on an official build machine
  651. if ( $official ) {
  652. $t = "$sdxroot\\$dbdir\\$SymbolFiles";
  653. open SYMBOLDB, "<$t" or die "Could not open: $t\n";
  654. $lineno = 0;
  655. for (<SYMBOLDB>) {
  656. $lineno++;
  657. chop;
  658. s/\s*[#;].*//;
  659. next if /^$/;
  660. my ($x, $y, $z) = split;
  661. die "$SymbolFiles Corrupt at line $lineno: ($_)\n" unless ( defined $x && defined $y && defined $z );
  662. $symbols{lc$x} = [$y, $z];
  663. }
  664. close SYMBOLDB;
  665. # Associate symbols and files marked to be copied
  666. @symbolstocopy = ();
  667. foreach ( @filestocopy ) {
  668. next unless ( exists $symbols{lc$_} );
  669. my $relpath = $symbols{lc$_}->[0];
  670. my $copypub = $symbols{lc$_}->[1];
  671. if ( $copypub ) {
  672. push @symbolstocopy, "symbols\\$relpath";
  673. $GoldStamp{"symbols\\". lc$relpath} = $GoldStamp{$_};
  674. push @FilesToStamp, "symbols\\". lc$relpath if @FilesToStamp;
  675. }
  676. push @symbolstocopy, "symbols.pri\\$relpath";
  677. $GoldStamp{"symbols.pri\\". lc$relpath} = $GoldStamp{$_};
  678. push @FilesToStamp, "symbols.pri\\". lc$relpath if @FilesToStamp;
  679. }
  680. }
  681. $TotalCompareErrors = $OtherMismatches + $DroppedPEMismatches + $PEMismatches;
  682. $checktime = time();
  683. #
  684. # Replace files on the list -- unless check says not to, or we had compare errors and we are not forcing.
  685. #
  686. printall "WARNING: Faking!!! Not really populating _NTTREE with client files\n" if $Fake and @filestocopy > 0;
  687. printall @filestocopy + @symbolstocopy. " Files to copy\n";
  688. $fatal = 0;
  689. unless ($NoFilter or $Fake or not $Force and $TotalCompareErrors > 0) {
  690. #
  691. # Make directories.
  692. #
  693. $serverdir = "$nttree\\$SERVERDIRNAME";
  694. $clientdir = "$nttree\\$CLIENTDIRNAME";
  695. mkdir "$serverdir", 0777 or die "Could not mkdir $serverdir\n";
  696. mkdir "$clientdir", 0777 or die "Could not mkdir $clientdir\n";
  697. printall "Created $serverdir to save replaced files.\n";
  698. printall "Created $clientdir to stage replacement files.\n";
  699. #
  700. # Pick a source directory for PEReplaceFiles according to the following algorithm
  701. # XPSP1\Checked -- if this is a checked build, and this directory exists
  702. # XPSP1\Gold -- if this directory exists
  703. # XPSP1\Reference -- otherwise
  704. # And check that all the files we need to replace exist there. And copy them down.
  705. # Check existence using a file from $PEReplaceFiles
  706. #
  707. $testfile = $PEReplaceFiles[0];
  708. @list = ();
  709. push @list, 'Checked' if $chkbuild;
  710. push @list, 'Gold';
  711. push @list, 'Reference';
  712. $sourcedir = "";
  713. for ( @list ) {
  714. $t = "$xpsp1dir\\$_";
  715. $sourcedir = "$t" if -s "$t\\$testfile";
  716. last if $sourcedir;
  717. }
  718. die "Could not find source directory for binaries under $xpsp1dir (using $testfile)\n" unless $sourcedir;
  719. printall "Source directory for client files: $sourcedir\n";
  720. #
  721. # Copy down all the client files
  722. #
  723. for (@filestocopy) {
  724. $succ = copy ("$sourcedir\\$_", "$clientdir\\$_");
  725. printall ("Error copying $_ from $sourcedir to $clientdir\n"), $fatal++ unless $succ;
  726. $CopyCount++;
  727. $CopyBytes += -s "$clientdir\\$_";
  728. }
  729. for $sym (@symbolstocopy) {
  730. $succ = copyex( $sourcedir."Symbols\\$sym", "$clientdir\\$sym");
  731. printall ("Error copying $sym from $sourcedir". "Symbols to $clientdir\n"), $fatal++ unless $succ;
  732. # Treat symbols same as other files now for rename
  733. push @filestocopy, $sym;
  734. $SymCopyCount++;
  735. $CopyBytes += -s "$clientdir\\$sym";
  736. }
  737. die $PGM, "Failure to copy down all the expected client files is fatal.\n" if $fatal;
  738. #
  739. # Move the server files out of the way.
  740. #
  741. for $f (@filestocopy) {
  742. if (-s "$nttree\\$f") {
  743. $succ = renameex ("$nttree\\$f", "$serverdir\\$f");
  744. printall ("Error moving $f from $nttree to $serverdir\n"), $fatal++ unless $succ;
  745. } else {
  746. $missingserverfiles++;
  747. printall "WARNING: $f does not exist in $nttree\n";
  748. }
  749. }
  750. printall "WARNING: $missingserverfiles files found missing from server\n" if $missingserverfiles;
  751. die $PGM, "Fatal error moving aside client files to $serverdir - Move them back manually.\n" if $fatal;
  752. #
  753. # Move in the client files.
  754. #
  755. for $f (@filestocopy) {
  756. $succ = renameex ("$clientdir\\$f", "$nttree\\$f");
  757. printall ("Error moving $f from $clientdir to $nttree\n"), $fatal++ unless $succ;
  758. }
  759. die $PGM, "Fatal error moving in client files from $clientdir."
  760. . " May need to put back server files ($serverdir) manually.\n" if $fatal;
  761. } else {
  762. printall "WARNING: Not populating _NTTREE with client files:\n";
  763. printall " NoFilter=$NoFilter Fake=$Fake Force=$Force TotalCompareErrors=$TotalCompareErrors\n";
  764. }
  765. #
  766. # Set the gold timestamp on the files which matches or were successfully compared file if there was no mismatch
  767. #
  768. unless (scalar @FilesToStamp) {
  769. push @FilesToStamp, @CheckFiles;
  770. push @FilesToStamp, @CheckPEFiles;
  771. push @FilesToStamp, @PEReplaceFiles;
  772. if ( $official ) {
  773. foreach ( @PEReplaceFiles ) {
  774. next unless ( exists $symbols{lc$_} );
  775. my $relpath = $symbols{lc$_}->[0];
  776. my $copypub = $symbols{lc$_}->[1];
  777. push @FilesToStamp, "symbols\\". lc$relpath if $copypub;
  778. push @FilesToStamp, "symbols.pri\\". lc$relpath;
  779. }
  780. }
  781. }
  782. #
  783. # set the timestamps on files
  784. # and write the gold files list
  785. #
  786. $BytesSaved = 0;
  787. unless ($Fake) {
  788. for (@FilesToStamp) {
  789. $stamp = lc $GoldStamp{$_};
  790. if ( !SetAttributes("$nttree\\$_", 0) )
  791. {
  792. printall "ERROR: Resetting file attributes on $_ failed\n";
  793. }
  794. if ( !utime($begintime, hex $stamp, "$nttree\\$_") )
  795. {
  796. printall "ERROR: Updating time-stamp for $nttree\\$_ failed\n";
  797. }
  798. printall "Could not find stamp for: $_\n" unless $stamp;
  799. printf GOLDFILESFILE "%s\n", $_;
  800. $BytesSaved += hex $GoldLength{$_};
  801. }
  802. }
  803. close GOLDFILESFILE;
  804. #=======================================================================================================================
  805. #=======================================================================================================================
  806. #
  807. # At this point we remember $begintime, $checktime, and have $CopyBytes, $CopyCount,
  808. # $PEMismatches, $OtherMismatches and $OtherPEMismatches.
  809. # $nttree and $sourcedir are also available.
  810. # LOGFILE and TSTFILE are open
  811. # $Fake and $Test may be set.
  812. #
  813. $t0 = $checktime - $begintime;
  814. $t1 = time() - $checktime;
  815. ($h0, $m0, $s0) = hms $t0;
  816. ($h1, $m1, $s1) = hms $t1;
  817. ($h2, $m2, $s2) = hms ($t0 + $t1);
  818. $KB = $CopyBytes/1024;
  819. $MB = $KB/1024;
  820. $kbrate = $KB/$t1 unless not $t1;
  821. printfall "Populated $nttree with $CopyCount CLIENT RTM files ".(@symbolstocopy?"and $SymCopyCount CLIENT RTM symbols ":"")."(%4.0f MB)"
  822. . " from $sourcedir".(@symbolstocopy?"[Symbols] ":"")." [%7.2f KB/S]\n" ,
  823. $MB, $kbrate;
  824. printall "Verified $NoncopyCount CLIENT RTM files.\n";
  825. if ($PEMismatches or $OtherMismatches or $OtherPEMismatches) {
  826. printall "ERROR: $PEMismatches mismatches in built PE files,\n";
  827. printall "ERROR: $OtherMismatches mismatches in other files, and\n";
  828. printall "ERROR: $OtherPEMismatches other PE files had unexpected mismatches!\n";
  829. }
  830. if ($ToolProblems) {
  831. printall "ERROR: $ToolProblems problems with the tools.\n";
  832. }
  833. printfall "Reused %5d XP/RTM files totalling %4d MB\n", scalar @FilesToStamp, $BytesSaved/1000000;
  834. printfall "Only %5d XP/RTM files totalling %4d MB due to popfilter\n", scalar $CopyCount, $PopFilterBytesSaved/1000000;
  835. printfall "Checking time %5d secs (%d:%02d:%02d)\n", $t0, $h0, $m0, $s0;
  836. printfall "CopyFile time %5d secs (%d:%02d:%02d)\n", $t1, $h1, $m1, $s1;
  837. printfall "TotalTime time %5d secs (%d:%02d:%02d)\n", $t0+$t1, $h2, $m2, $s2;
  838. #
  839. # Return an error if we were faking so timebuild doesn't proceed.
  840. #
  841. close LOGFILE;
  842. close TSTFILE if $Test;
  843. exit $Fake;