windows-nt/Source/XPSP1/NT/tools/sp/updater.cmd
2020-09-26 16:20:57 +08:00

985 lines
30 KiB
Batchfile

@REM -----------------------------------------------------------------
@REM
@REM updater.cmd
@REM Add entries to update.inf
@REM
@REM Copyright (c) Microsoft Corporation. All rights reserved.
@REM
@REM -----------------------------------------------------------------
@perl -x "%~f0" %*
@goto :EOF
#!perl
#line 13
use strict;
use Win32::OLE qw(in);
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
use lib $ENV{RAZZLETOOLPATH} . "\\sp";
use lib $ENV{RAZZLETOOLPATH};
use PbuildEnv;
use ParseArgs;
use Logmsg;
use InfData;
use InfParse;
use CanonDir;
# Clear error flag
$ENV{ERRORS} = 0;
sub Usage { print<<USAGE; exit(1) }
updater.cmd -entries:<files> [-trim] [-qfe] [-c <change>]
files: file containing list of files to search for
trim minimize size of resultant INF by compressing and removing entries
qfe build an inf for a qfe instead of a service pack
change: make changes listed in a change file
dirs: make a list of dirs of all of the files
USAGE
my ($file_list, $ftrim_inf, $change_file, $qfe);
parseargs('?' => \&Usage,
'entries:' => \$file_list,
'c:' => \$change_file,
'qfe' => \$qfe,
'trim' => \$ftrim_inf );
my $db_file = "$ENV{_NTPOSTBLD}\\idw\\srvpack\\infsect.tbl";
my $alt_file = "$ENV{_NTPOSTBLD}\\idw\\srvpack\\newinf.tbl";
my $diff_file = "$ENV{_NTPOSTBLD}\\idw\\srvpack\\infdiff.tbl";
my $inf_file = "$ENV{_NTPOSTBLD}\\idw\\srvpack\\" . ($qfe ? "hotfix1.inf":"update.inf");
my $dirs_file = "$ENV{_NTPOSTBLD}\\idw\\srvpack\\filelist.txt";
my $out_file = "$ENV{_NTPOSTBLD}\\update.inf";
#
# Data
#
my $archd = (lc$ENV{_BUILDARCH} eq "ia64") ? "ia64":"w32x86";
my $arch = (lc$ENV{_BUILDARCH} eq "ia64") ? "ia64":"i386";
CanonDir::setup( $archd, $arch );
my $type;
my $prod;
my $boot;
my %sects;
my %sections;
my %missing;
my %masks;
my %fdirs;
my %sectnames;
my %addentries;
my %catmasks = (
"ip" => 0x1,
"ic" => 0x2,
"is" => 0x4,
"ia" => 0x8,
"id" => 0x10,
"il" => 0x20,
"ib" => 0x40,
"" => 0x7f
);
my @skuletters = ("p", "c");
my $skumask = ($arch eq "ia64") ? 1:3;
my $skucount = ($arch eq "ia64") ? 1:2;
my $skumax = ($arch eq "ia64") ? 1:2;
# Matching between product names and sku combinations.
my %skus = (
"professional" => 0x1,
"consumer" => 0x2,
"server" => 0x4,
"advanced" => 0x8,
"datacenter" => 0x10,
"business" => 0x20,
"blade" => 0x40,
"" => 0x7f
);
my %revskus = CanonDir::reverseHash(%skus); # Reverse lookup for %skus.
my %shortskus = (
0x1 => "Prf",
0x2 => "Con",
0x4 => "Srv",
0x8 => "Adv",
0x10 => "Dtc",
0x20 => "Sbs",
0x40 => "Bld"
);
#
# Setup connection to InfGenerator
#
sub die_ole_errmsg( $ ) {
my $text = shift;
errmsg( "$text (". Win32::OLE->LastError(). ")" );
exit 1;
}
system("regsvr32 /s $ENV{RAZZLETOOLPATH}\\sp\\infgen.dll");
my $inf_generator = Win32::OLE->new('InfGenerator');
die_ole_errmsg "Could not instatiate InfGenerator" if ( !defined $inf_generator );
$inf_generator->SetDB( "", "", "", "" );
$inf_generator->InitGen( $inf_file, $out_file );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg "Error starting up InfGenerator (". ($errstr?$errstr:$save_ole_error). ")";
exit 1;
}
#
# Subroutines
#
# Parse a line from an install section of the inf template.
sub parseNames {
my ($cmd, $sect) = split(/\s*=\s*/);
if ( $cmd =~ /^(\w*)Files$/ ) {
$cmd = $1;
my $spec = "";
my $mask = lc $prod;
if ( !exists $skus{$mask} ) {
$spec = $mask;
$spec =~ s/\.[^\.]*$//;
$mask =~ s/^\Q$spec\E.?//;
}
($spec, $mask) = split(/\t/, lc $prod) if $prod =~ /\t/;
$mask = $skus{$mask};
$mask = 0 if !defined $mask;
$boot="dontdelayuntilreboot" if $sect =~ /drivers\.files$/i;
$sects{lc $sect} = InfSect->new($sect) if !exists $sects{lc $sect};
$sects{lc $sect}->setAtts( $type, $mask, $spec, $boot, $cmd );
}
}
# Parse a database file.
sub readDB {
my ($file) = @_;
my %db = ();
if ( !open (DBFILE, $file) ) {
errmsg( "Unable to read $file: $!" );
exit 1;
}
foreach ( <DBFILE> ) {
chomp;
my $line = InfData->new();
if ( !$line->readLine($_, \@skuletters) ) {
wrnmsg( "Unrecognized DB-file entry: $_" );
next;
}
my $dir = $line->getSrcDir();
my $key = $line->getSrc();
$key = "$dir$key" if $dir =~ /^wow\\/i;
$db{$key} = [ () ] if !exists $db{$key};
push @{ $db{$key} }, $line;
}
close DBFILE;
return %db;
}
# Subtract lists of entries.
sub subEnts {
my ($list1, $list2) = @_;
foreach my $entry ( @$list1 ) {
my @temp = ();
foreach my $ent ( @$list2 ) {
my $newent = $ent->delBit2($entry);
push @temp, $newent if defined $newent;
}
$list2 = \@temp;
}
return $list2;
}
# Add lists of entries.
sub addEnts {
my ($list1, $list2) = @_;
foreach my $entry ( @$list1 ) {
my $test = undef;
foreach my $ent ( @$list2 ) {
$test = $ent->addBit($entry);
last if $test;
}
push @$list2, $entry if !$test;
}
return $list2;
}
# Create a new inf section.
sub createSect {
my ($entry, $type) = @_;
# Figure out what sku(s) we are going to make this section for.
my $skubit = 0;
foreach my $sku (keys %revskus) {
$skubit = $sku if ($sku & $entry->{MASK}) == $sku;
}
$skubit = $skumask if ($skumask & $entry->{MASK}) == $skumask;
return undef if $skubit == 0;
return undef if $entry->{PATH} =~ /^\!/;
# Figure out the new section's name.
my $sectname = addPrefix($entry->{DIRID}, $entry->{PATH}, %CanonDir::updids);
if ( $entry->{CMD} ne "copy" ) {
$sectname .= ".Delfiles"
} else {
$sectname .= ".Files" if $sectname !~ /^\.\.\\/;
}
$sectname =~ s/^system32//i;
$sectname =~ s/^\.\.//;
$sectname =~ s/^\\//;
$sectname =~ s/\s/\_/g;
$sectname =~ s/\\/\./g;
$sectname =~ s/[\(\)\[\]\!]//g;
$sectname = ucfirst $sectname;
if ( $type eq "copyfilesalways" ) {
$sectname = $shortskus{$skubit}.".".$sectname if $skubit != $skumask;
$sectname = "CopyAlways." . $sectname;
} else {
$sectname = (ucfirst $revskus{$skubit}).".".$sectname if $skubit != $skumask;
}
if ( exists $sectnames{lc $sectname} ) {
my $num = 1;
while ( exists $sectnames{lc "$sectname\.$num"} ) {
++$num;
}
$sectname = "$sectname\.$num";
}
# Create the section object.
++$sectnames{lc $sectname};
my $sect = InfSect->new($sectname);
$sect->setAtts( $type, $skubit, "", "", $entry->{CMD} );
$sect->setPath( $entry->{DIRID}, $entry->{PATH} );
my $path = lc "$entry->{DIRID},\"$entry->{PATH}\"";
$sections{$path} = [] if !exists $sections{$path};
push @{ $sections{$path} }, $sect;
# Create the install section entry.
my $instsect = "ProductInstall.";
if ( $type eq "copyfilesalways" ) {
$instsect .= "CopyFilesAlways";
$instsect .= "." . (ucfirst $revskus{$skubit}) if $skubit != $skumask;
} else {
if ( $skubit == $skumask ) {
$instsect .= "ReplaceFilesIfExist";
} else {
$instsect .= (ucfirst $revskus{$skubit}) . "Files";
}
}
my $instline = " " . (ucfirst $entry->{CMD}) . "Files=" . $sectname . "\n";
$addentries{lc$instsect} = [ () ] if !exists $addentries{lc$instsect};
push @{ $addentries{lc$instsect} }, $instline;
# Create the DestinationDirs entry.
$inf_generator->AddEquality( "DestinationDirs", $sectname, $path );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section DestinationDirs" );
errmsg( "Content was: $sectname\=$path" );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
return $sect;
}
# Add lines to the inf.
sub addLines {
my ($list, $type)= @_;
foreach my $entry ( @$list ) {
my $path = lc $entry->{NAME};
$masks{$path} = InfData->new($path, 65621, "", "", 0) if !exists $masks{$path};
$masks{$path}->{MASK} |= $entry->{MASK};
$masks{$path}->{CMD} = "del" if $entry->{CMD} eq "del";
if ( $entry->{DIRID}==65619 and $entry->{PATH} eq "" ) {
#$masks{$path}->setDest($entry->getDest());
$masks{$path}->{SPEC} = $entry->{SPEC};
}
while ( $entry->{MASK} != 0 ) {
my $section = undef;
my $match = 0;
foreach my $sect ( @{ $sections{$entry->getFullPath()} } ) {
my $temp = $sect->match($entry, $type);
if ( $temp > $match ) {
$match = $temp;
$section = $sect;
}
}
if ( !defined $section ) {
$section = createSect($entry, $type);
}
if ( !defined $section ) {
wrnmsg( "No matching section for ".$entry->getLine(\@skuletters) );
last;
}
$entry->{MASK} &= ~$section->{MASK};
my $data = $entry->getInfLine($section->{FLAG});
if ( $data =~ /=/ ) {
errmsg( "Can't have '=' in entry: $entry" );
next;
}
$inf_generator->WriteSectionData( $section->{NAME}, $data );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section $section->{NAME}" );
errmsg( "Content was: ". $data );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
}
}
}
# Read out entries for a file.
sub getEntries {
my ($hash, $file, $path) = @_;
my @list;
my $dir = $path;
$dir = "" if $dir eq "\\";
foreach my $entry ( @{ $hash->{$file} } ) {
my $srcdir = $entry->getSrcDir();
next if $path !~ /^(lang\\)?$/i and $dir ne $srcdir;
push @list, $entry;
$fdirs{$srcdir}++;
}
return \@list;
}
# Get a file's compressed file name.
sub compName {
my $file = shift;
return $file if $file =~ /\_$/;
$file = $1 if $file =~ /^(.*\...).$/;
$file .= "." if $file !~ /\...?$/;
$file .= "_";
return $file;
}
#
# Read in DB files
#
my (%base, %new, %diff);
%diff = ();
%base = readDB($db_file);
%new = readDB($alt_file);
%diff = readDB($diff_file) if -f $diff_file;
#
# Get info on inf sections
#
logmsg( "Parsing template file..." );
if ( !open INF, $inf_file ) {
errmsg( "Unable to open $inf_file." );
die;
}
$_ = parseSect(sub { return; });
while ( /^\[/ ) {
my ($sectname) = /^\s*\[([^\]]*)\]\s*$/;
$sectnames{lc $sectname}++;
if ( /^\s*\[ProductInstall\.(\w*)\.(\w*)\]\s*$/ ) {
# Process a list of install section names.
$type = lc $1;
$prod = lc $2;
$boot = "";
if ( $type eq "dontdelayuntilreboot" ) {
$boot = $type;
$type = "replacefilesifexist";
}
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[ProductInstall\.(\w*)Files\]\s*$/ ) {
# Process a list of install section names.
$type = "replacefilesifexist";
$prod = lc $1;
$boot = "";
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[ProductInstall\.(\w*)\]\s*$/ ) {
# Process a list of install section names.
$type = lc $1;
$prod = "";
$boot = "";
if ( $type eq "dontdelayuntilreboot" ) {
$boot = $type;
$type = "replacefilesifexist";
}
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[(\w*)Section(\w*)\]\s*$/ ) {
# Process a product specific list of section names.
$type = "replacefilesifexist";
$prod = lc $1;
$prod .= lc "\t$2" if $2 ne "";
$boot = "";
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[BuildType\.([IM].)(\.[^\.]*)?\.Section\]\s*$/i ) {
# Process a list of section names for volume licensing.
$type = "";
$prod = lc $1;
$prod = "" if !defined $prod;
$prod = $revskus{$catmasks{$prod}};
$prod = "buildtype".(lc$2).".$prod";
$boot = "";
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[MSN\.no\.ver\]\s*$/ ) {
# Special install section.
$type = "replacefilesifexist";
$prod = "";
$boot = "";
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[JVMInstall\]\s*$/ ) {
# Special install section.
$type = "copyfilesalways";
$prod = "";
$boot = "";
$_ = parseSect( \&parseNames );
}
elsif ( /^\s*\[DestinationDirs\]\s*$/ ) {
# Find destinations for all these sections.
$_ = parseSect(sub {
my ($sect, $dir) = split(/\s*=\s*/,$_[0]);
if ( $dir !~ /^(\d+)(,\"?([^\"]*)\"?)?$/ ) { # "
logmsg "Template line omitted: $_";
return;
}
my $dirid;
my $subdir = addPrefix($1, lc $3, %CanonDir::updids);
($dirid, $subdir) = removePrefix($subdir, %CanonDir::revids);
$sects{lc $sect} = InfSect->new($sect) if !exists $sects{lc $sect};
$sects{lc $sect}->setPath( $dirid, $subdir );
} );
}
elsif ( /^\s*\[(ProductCatalogsToInstall(\.([^\]]*))?)\]\s*$/i ) {
# Add a section for catalog files.
my $sect = $1;
my $prod = $3;
$prod = "" if !defined $prod;
my $mask = $catmasks{lc $prod};
if ( defined $mask ) {
$sects{lc $sect} = InfSect->new($sect);
$sects{lc $sect}->setPath( 65535, ".cat" );
$sects{lc $sect}->setAtts( "", $mask, "", "", "Copy" );
}
$_ = parseSect(sub { return; });
}
elsif ( /^\s*\[Strings\]\s*$/ ) {
# Process a list of localization strings.
$_ = parseSect( \&parseStr );
}
else {
$_ = parseSect(sub { return; });
}
}
close INF;
# Add special sections.
$sects{"hals"} = InfSect->new("HALS");
$sects{"hals"}->setPath( 65535, "hals" );
$sects{"hals"}->setAtts( "", $skumask, "", "", "Copy" );
$sects{"windows.driver_cache.i386"} = InfSect->new("Windows.Driver_Cache.i386");
$sects{"windows.driver_cache.i386"}->setPath( 65535, "wdrvc" );
$sects{"windows.driver_cache.i386"}->setAtts( "", $skumask, "", "", "Copy" );
# Process the results.
foreach my $sect (values %sects) {
my $test = $sect->isComplete();
my $name = $sect->getName();
wrnmsg "Section omitted (sect. unused): $name" if $test & 1;
wrnmsg "Section omitted (no directory): $name" if $test & 2;
next if $test;
my ($dirid, $path) = $sect->getPath();
$sect->resetPath();
$path = addPrefix($dirid, strSub($path), %CanonDir::updids);
($dirid, $path) = removePrefix($path, %CanonDir::revids);
$sect->setPath($dirid, $path);
$path = lc "$dirid,\"$path\"";
$sections{$path} = [] if !exists $sections{$path};
push @{ $sections{$path} }, $sect;
}
#
# Read in a change file
#
my %oldfiles = ();
my %newfiles = ();
if ( defined $change_file ) {
if ( !open CHANGE, $change_file ) {
errmsg( "Unable to open $change_file." );
die;
}
while ( <CHANGE> ) {
next if /^\s*(\#.*)?$/;
if ( /^\s*([^\=]*\S)\s*=\s*(.*\S)\s*$/ ) {
my $filename = lc $1;
my $cmd = lc $2;
$filename =~ /^(.*\\)?([^\\]*)$/;
my $dir = $1;
my $file = $2;
$file = "$dir$file" if $dir ne "lang\\";
if ( defined $base{$file} or defined $new{$file} ) {
if ( $cmd eq "old" ) {
# This file is old, merge the new stuff into the old.
$oldfiles{$file}++;
}
elsif ( $cmd =~ /^renamed\s*:\s*(.*\\)?([^\\]*)$/ ) {
# This file has been renamed; move the data over to the new name.
my ($path, $name) = ($1, $2);
$newfiles{$file}++;
if ( exists $base{$name} ) {
my $list = $base{$name};
foreach my $entry ( @$list ) {
$entry->setSrc( $entry->getSrcDir() . $file );
}
delete $base{$name};
$base{$file} = [ () ] if !exists $base{$file};
push @{ $base{$file} }, @$list;
}
}
else {
wrnmsg "Unknown change file command: $cmd";
}
}
elsif ( $file =~ /^\[(.*)\]$/ and exists $sects{lc$1} ) {
my $sect = lc$1;
if ( $cmd =~ /^flag\s*:\s*(.*)$/ ) {
$sects{$sect}->{FLAG} = $1;
}
elsif ( $cmd =~ /^spec\s*:\s*(.*)$/ ) {
$sects{$sect}->{SPEC} = $1;
}
elsif ( $cmd =~ /^when\s*:\s*(.*)$/ ) {
$sects{$sect}->{WHEN} = $1;
}
elsif ( $cmd =~ /^type\s*:\s*(.*)$/ ) {
$sects{$sect}->{TYPE} = $1;
}
else {
wrnmsg "Unknown change file command: $cmd";
}
} else {
wrnmsg "Unknown entry in change file: $filename";
next;
}
}
}
close CHANGE;
}
#
# Read in list of files to find
#
if ( defined $dirs_file ) {
if ( !open (DIRS, ">>$dirs_file") ) {
errmsg( "Unable to read $dirs_file: $!" );
exit 1;
}
}
if ( !open (INFILE, "$file_list") ) {
errmsg( "Unable to read $file_list: $!" );
exit 1;
}
while ( <INFILE> ) {
chomp;
$_ = lc $_;
my ($tag, $dir, $key) = /^(\S*\s+)?(\S*\\)?([^\\]*)$/;
$dir = "" if $tag =~ /u/ or ($dir eq "new\\" and $tag !~ /m/);
my $path = $dir;
my $name = $key;
$dir =~ s/^\\$//;
%fdirs = ();
$fdirs{$dir}++ if $path !~ /^(lang\\)?$/i;
$key = "$dir$key" if $dir =~ /^wow\\/i;
# Get the install information for the file.
my $list1 = getEntries(\%base, $key, $path);
if ( $dir eq "lang\\" ) {
if ( exists $fdirs{""} and !exists $fdirs{"lang\\"} ) {
foreach my $entry ( @{ $new{$key} } ) {
$entry->clearSrcDir() if lc$entry->getSrcDir() eq "lang\\";
}
foreach my $entry ( @{ $diff{$key} } ) {
$entry->clearSrcDir() if lc$entry->getSrcDir() eq "lang\\";
}
}
$fdirs{"lang\\"}++;
}
my $list2 = getEntries(\%new, $key, $path);
my $list3 = getEntries(\%diff, $key, $path);
# Put everything into the right directory if it's a new file.
my $old = ($#$list1 >= 0) && !exists $newfiles{$key};
if ( !$old and exists $fdirs{""} ) {
delete $fdirs{""};
$fdirs{"new\\"}++;
foreach my $entry ( @$list1 ) {
$entry->setSrcDir("new\\") if lc$entry->getSrcDir() eq "";
}
foreach my $entry ( @$list2 ) {
$entry->setSrcDir("new\\") if lc$entry->getSrcDir() eq "";
}
foreach my $entry ( @$list3 ) {
$entry->setSrcDir("new\\") if lc$entry->getSrcDir() eq "";
}
}
if ( $tag =~ /u/i ) {
my @dirs = keys %fdirs;
if ( $#dirs == 0 and $dirs[0] =~ /^(([im].|new)\\)?$/i ) {
%fdirs = (""=>1);
foreach my $entry ( @$list1 ) {
$entry->clearSrcDir();
}
foreach my $entry ( @$list2 ) {
$entry->clearSrcDir();
}
foreach my $entry ( @$list3 ) {
$entry->clearSrcDir();
}
} else {
wrnmsg( "'u' tag not used: $path$name" ) if $#dirs >= 0;
}
}
# Handle file deletions.
my $del = ($tag =~ /d/i);
if ( $del ) {
if ( $#$list2 >= 0 ) {
wrnmsg "Delete file still in use, skipped: $path$name";
next;
}
if ( $path =~ /^wow\\/i ) {
if ( $#$list1 >= 0 or $#$list3 >= 0 ) {
logmsg "Deleting WOW file: $path$name";
} else {
next;
}
}
foreach my $entry ( @$list1 ) {
$entry->{CMD} = "del";
}
foreach my $entry ( @$list3 ) {
$entry->{CMD} = "del";
}
}
# If this is media only, do not attempt to install it.
my $med = ($tag =~ /m/i);
if ( $med ) {
my $file = "$dir$name";
my $mask = $skumask;
$mask = $catmasks{$1} if $dir =~ /^(.*)\\$/ and exists $catmasks{$1};
$masks{$file} = InfData->new($file, 65621, "", "", $mask);
if ( !$del ) {
print DIRS "$file\n";
next;
} else {
$masks{$file}->{CMD} = "del";
}
++$fdirs{$dir};
$list1 = [ () ];
$list2 = [ () ];
$list3 = [ () ];
}
# See what files we got.
if ( defined $dirs_file and !$del ) {
foreach my $key ( keys %fdirs ) {
my $file = "$key$name";
print DIRS "$file\n";
}
}
if ( $#$list1 < 0 and $#$list2 < 0 and $#$list3 < 0 and (!$del or !$med) ) {
logmsg "File omitted: $key";
next;
}
# Break the lists into copy always and replace if exists.
$list2 = subEnts($list1, $list2);
$list3 = subEnts($list2, $list3);
$list1 = addEnts($list3, $list1);
# Add lines for the file.
my $type = "copyfilesalways";
$type = "replacefilesifexist" if exists $oldfiles{$key};
addLines($list1, "replacefilesifexist");
addLines($list2, $type);
}
close INFILE;
close DIRS if defined $dirs_file;
# Generate SourceDisksFiles entries and ServicePackFiles entries.
my %delfiles;
my %catfiles;
foreach my $path ( keys %masks ) {
my $entry = $masks{$path};
if ( $entry->{CMD} ne "del" ) {
my $wow = ($entry->getSrcDir() =~ /^wow\\/i ) ? ".WOW":"";
my $lang = ($entry->getSrcDir() =~ /lang\\/i ) ? ".Lang":"";
my $data = $entry->getInfLine(0);
my $mask = $entry->{MASK};
if ( !$qfe and lc $entry->{NAME} ne "msjavx86.exe" ) {
foreach my $sku ( keys %catmasks ) {
next if $sku eq "";
next if ($mask & $catmasks{$sku}) == 0;
my $section = "ServicePackFiles$wow$lang\.".(uc $sku).".Files";
$inf_generator->WriteSectionData( $section, $data );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section $section" );
errmsg( "Content was: ". $data );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
}
}
$inf_generator->AddSourceDisksFilesEntry( $path, 1 );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section SourceDisksFiles" );
errmsg( "Content was: $path" );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
} else {
if ( !$qfe ) {
my $file = $entry->{NAME};
$file =~ s/^([im].|new)\\//i;
$file =~ s/^wow\\/..\\i386\\/i;
next if exists $delfiles{$file};
$delfiles{$file}++;
$inf_generator->WriteSectionData( "ServicePackFilesDelete.files", $file );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section ServicePackFilesDelete.files" );
errmsg( "Content was: ". $file );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
}
}
if ( $path =~ /^(.*\\)?([^\\]*\.cat)$/i ) {
my $file = $2;
next if exists $catfiles{$file};
++$catfiles{$file};
$inf_generator->WriteSectionData( "ArchiveCatalogFilesOnly", $file );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed writing to section ArchiveCatalogFilesOnly" );
errmsg( "Content was: ". $file );
errmsg( "Error was: ". ($errstr?$errstr:$save_ole_error) );
}
}
}
logmsg( "Saving new INF file ..." );
# Trim and save new INF file
$inf_generator->CloseGen( $ftrim_inf?1:0 );
if ( Win32::OLE->LastError() ) {
my $save_ole_error = Win32::OLE->LastError();
my $errstr = $inf_generator->{InfGenError}; chomp $errstr;
errmsg( "Failed trimming/saving file (". ($errstr?$errstr:$save_ole_error). ")" );
}
# Add final entries.
if ( !open OUT, $out_file ) {
errmsg( "Unable to find outputted update.inf." );
}
my @inf = <OUT>;
close OUT;
if ( !open OUT, ">$out_file" ) {
errmsg( "Unable to edit outputted update.inf." );
}
foreach (@inf) {
print OUT;
if ( /^\s*\[([^\]]*)\]\s*$/ ) {
my $sect = lc $1;
next if !exists $addentries{$sect};
foreach my $line ( @{ $addentries{$sect} } ) {
print OUT $line;
}
delete $addentries{$sect};
}
}
foreach my $sect (keys %addentries) {
print OUT "\n\[$sect\]\n";
foreach my $line ( @{ $addentries{$sect} } ) {
print OUT $line;
}
}
close OUT;
if ( $ENV{ERRORS} ) {
logmsg( "Errors during execution" );
exit 1;
} else {
logmsg( "Success" );
exit 0;
}
############################################################################
package InfSect;
use strict;
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
use lib $ENV{RAZZLETOOLPATH};
use Logmsg;
use InfData;
# Create new inf section with just a name.
sub new {
my $class = shift;
my ($name) = @_;
my $self = {};
$self->{NAME} = $name; # Section name.
$self->{TYPE} = undef; # Replace or copy always.
$self->{MASK} = 0; # Skus that applies to.
$self->{SPEC} = undef; # Special groups.
$self->{WHEN} = undef; # Before or after reboot.
$self->{CMD} = undef; # Copy or delete.
$self->{DIRID} = undef; # DirID for install directory.
$self->{PATH} = undef; # Rest of install path.
$self->{FLAG} = 0; # Flag to insert for files in this section.
return bless $self;
}
# Set the section's basic attributes.
sub setAtts {
my $self = shift;
my ($type, $mask, $spec, $when, $cmd) = @_;
if ( defined $self->{TYPE} and $self->{TYPE} ne $type) {
wrnmsg "Differing section type for $self->{NAME}: $self->{TYPE} $type";
}
if ( $self->{MASK} != 0 and $self->{MASK} ne $mask) {
wrnmsg "Differing sku set for $self->{NAME}: $self->{MASK} $mask";
}
if ( defined $self->{SPEC} and $self->{SPEC} ne $spec) {
wrnmsg "Differing section group for $self->{NAME}: $self->{SPEC} $spec";
}
if ( defined $self->{WHEN} and $self->{WHEN} ne $when) {
wrnmsg "Differing section install time for $self->{NAME}: $self->{WHEN} $when";
}
if ( defined $self->{CMD} and $self->{CMD} ne $cmd) {
wrnmsg "Differing section command for $self->{CMD}: $self->{CMD} $cmd";
}
$self->{TYPE} = $type;
$self->{MASK} = $mask;
$self->{SPEC} = $spec;
$self->{WHEN} = $when;
$self->{CMD} = $cmd;
}
# Set the section's installation directory.
sub setPath {
my $self = shift;
my ($dirid, $path) = @_;
if ( (defined $self->{DIRID} and $self->{DIRID} ne $dirid) or
(defined $self->{PATH} and $self->{PATH} ne $path) ) {
wrnmsg "Differing path for $self->{NAME}: $self->{DIRID},$self->{PATH} $dirid,$path";
}
$self->{DIRID} = $dirid;
$self->{PATH} = $path;
}
# Clear the section's directory information.
sub resetPath {
my $self = shift;
$self->{DIRID} = undef;
$self->{PATH} = undef;
}
# Find a mask for the product field.
sub getMask {
my $self = shift;
return $self->{MASK};
}
# Get the section's installation directory.
sub getPath {
my $self = shift;
return ($self->{DIRID}, $self->{PATH});
}
# Get the inf section's name.
sub getName {
my $self = shift;
return $self->{NAME};
}
# See if all the fields have been specified.
sub isComplete {
my $self = shift;
my $flags = 0;
$flags |= 1 if !defined $self->{CMD};
$flags |= 1 if !defined $self->{WHEN};
$flags |= 1 if !defined $self->{TYPE};
$flags |= 1 if $self->{MASK} == 0;
$flags |= 1 if !defined $self->{SPEC};
$flags |= 2 if !defined $self->{DIRID};
return $flags;
}
# See how well this item matches a template.
sub match {
my $self = shift;
my ($template, $type) = @_; # $skumask, $skumax, $skucount, $all
# Basic comparison.
return 0 if lc $self->{CMD} ne $template->{CMD};
return 0 if lc $self->{DIRID} ne lc $template->{DIRID};
return 0 if lc $self->{PATH} ne lc $template->{PATH};
return 0 if lc $self->{TYPE} ne $type and $self->{TYPE} ne "";
my $count = 1;
# Test to see if the skus match.
my $mask = $self->getMask();
return 0 if ($template->{MASK} & $mask & $skumask) == 0;
my $match = ($template->{MASK} ^ $mask) & $skumask;
if ( $match == 0 ) {
# Section matches.
$count += $skucount;
}
elsif ( ($match & $mask) != 0 ) {
# Section is a superset. Bad.
return 0;
}
elsif ( ($match & $template->{MASK}) != 0 && $mask != 0 ) {
# Section is a subset. Prefer the closest matches.
$mask = $match & $template->{MASK};
for (my $i=0; $i<$skumax; ++$i) {
$count -= 1 if ($mask & 1) == 0;
$mask = $mask >> 1;
}
$count += $skucount;
}
# Make sure they belong to the same group.
if ( lc $self->{SPEC} eq lc $template->{SPEC} ) {
$count += 0.5;
}
elsif ( $self->{SPEC} eq "" ) {
$count += 0.2;
}
# Are both copy before reboot?
if ( lc $self->{WHEN} eq lc $template->{WHEN} ) {
$count += 0.005;
}
# Prefer broader product groups.
if ( $self->{MASK} == $skus{""} ) {
$count += 0.0005;
}
return $count;
}
1;