706 lines
21 KiB
Perl
706 lines
21 KiB
Perl
|
package SymMake;
|
||
|
|
||
|
use lib $ENV{RAZZLETOOLPATH} . "\\sp";
|
||
|
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
|
||
|
use lib $ENV{RAZZLETOOLPATH};
|
||
|
|
||
|
use strict;
|
||
|
use Carp;
|
||
|
use IO::File;
|
||
|
use Data::Dumper;
|
||
|
use File::Basename;
|
||
|
use File::Find;
|
||
|
use Logmsg;
|
||
|
|
||
|
# Data structure
|
||
|
# pdbname.binext => [(var)pdbpath,size,$binext]
|
||
|
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
#
|
||
|
# Package SymMake
|
||
|
# - create symbols.inf, symbols(n).ddf and symbols.cdf
|
||
|
#
|
||
|
# in this version, the symmake.pm creates full package's and update package's symbols.inf, symbols.ddf and symbols.cdf
|
||
|
#
|
||
|
# for doing this, the symmake.pm first reads the symbol list from arch, then reads another one from symbolscd.txt;
|
||
|
# every reading, it store the record to $self->{'SYM'} and store the new file extension to $self->{'EXT'}
|
||
|
#
|
||
|
# then, we according $pkinfoptr to write relate information to symbols.inf, symbols(n).ddf and symbols.cdf
|
||
|
#
|
||
|
# [Data Relations]
|
||
|
# $pkinfoptr and $self->{'SYM'} are the two mainly hash we operating with
|
||
|
# $pkinfoptr - the package information includes the cab, ddf, inf's file names and the file handles
|
||
|
# $self->{'SYM'} - the symbols records that are from archive or ntpostbld
|
||
|
#
|
||
|
# basically, we looping for each record in $self->{'SYM'},
|
||
|
# according the $self->{'SYM'}->{"$symbol\.$installpath"}->[0] to get the kb term ('ARCH' or 'NTPB')
|
||
|
# then, we use %revpktypes to get $pktype ('FULL' or 'UPDATE')
|
||
|
#
|
||
|
# or, we according $pktype ('FULL' or 'UPDATE') to get kb term from $pktypes
|
||
|
# then, we can access the root of arch or ntpostbld ($self->{'KB'}->{$pktype})
|
||
|
#
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
|
||
|
#
|
||
|
# $DDFHandle - the .ddf file handle for writing symbols(n).ddf
|
||
|
# $CATHandle - the .cat file handle for writing content to .cdf for creating .cat(alog)
|
||
|
# $INFHandle - the .inf file handle for writing symbols.inf
|
||
|
#
|
||
|
my ($DDFHandle, $CATHandle, $INFHandle);
|
||
|
|
||
|
|
||
|
#
|
||
|
# Package Types
|
||
|
# FULL - from ARCH
|
||
|
# UPDATE - from NTPOSTBLD
|
||
|
#
|
||
|
my %pktypes = (
|
||
|
FULL => 'ARCH',
|
||
|
UPDATE => 'NTPB'
|
||
|
);
|
||
|
|
||
|
#
|
||
|
# %revpktypes = ( # reverse the key - value relation for %pktypes
|
||
|
# 'ARCH' => 'FULL'
|
||
|
# 'NTPB' => 'UPDATE'
|
||
|
# )
|
||
|
#
|
||
|
my %revpktypes = reverse %pktypes;
|
||
|
|
||
|
|
||
|
#
|
||
|
# $obj = new SymMake $archpath, $ntpostbldpath
|
||
|
# - object creator
|
||
|
#
|
||
|
# ( we assign the root and use the relation path in symbolcd.txt and archiver dump list )
|
||
|
# return:
|
||
|
# $obj->
|
||
|
# 'KB' -> # Knowledge Base
|
||
|
# 'ARCH' => \\arch\archive\....
|
||
|
# 'NTPB' => %_NTPOSTBLD%
|
||
|
# 'SYM' -> (empty) # The file lists of symbols, hash structure is listed in below:
|
||
|
# # $self->{'SYM'}->
|
||
|
# # $symbol\.$installpath -> # such as 'ntoskrnl.pdb.exe'
|
||
|
# # [kbterm, symbol subpath, symbol filesize, $installpath] # such as ['ARCH', "\\symbols\\retail\\exe\\ntoskrnl.pdb", 4189184, 'exe']
|
||
|
# 'EXT' -> (empty) # The file lists of symbols' file extension, hash structu is listed in below:
|
||
|
# # $self->{'EXT'}->
|
||
|
# # $pktype -> #such as 'FULL'
|
||
|
# # $installpath -> 1 # such as 'EXE' -> 1
|
||
|
# 'HANDLE' -> (empty) # The file handles
|
||
|
# 'PKTYPE' -> undef # package type
|
||
|
#
|
||
|
|
||
|
sub new {
|
||
|
my $class = shift;
|
||
|
my $instance = {
|
||
|
KB => {
|
||
|
"$pktypes{'FULL'}" => $_[0],
|
||
|
"$pktypes{'UPDATE'}" => $_[1]
|
||
|
},
|
||
|
SYM => {},
|
||
|
EXT => {},
|
||
|
HANDLE => {},
|
||
|
PKTYPE => undef
|
||
|
};
|
||
|
return bless $instance, $class;
|
||
|
}
|
||
|
|
||
|
|
||
|
#
|
||
|
# $obj->ReadSource($symbolcd)
|
||
|
# - read the source file ($symbolcd) to $self->{'SYM'} and $self->{'EXT'}
|
||
|
# IN: $symbolcd
|
||
|
# REF: $self->{'PKTYPE'} : current package type
|
||
|
#
|
||
|
#
|
||
|
#
|
||
|
sub ReadSource
|
||
|
{
|
||
|
my ($self, $symbolcd) = @_;
|
||
|
my ($fh, $kbterm, $mykey, @mylist);
|
||
|
local $_;
|
||
|
|
||
|
$kbterm = $pktypes{$self->{'PKTYPE'}};
|
||
|
|
||
|
$symbolcd = "$self->{'KB'}->{$kbterm}\\symbolcd\\symbolcd.txt" if (!defined $symbolcd);
|
||
|
$symbolcd = "$ENV{'TEMP'}\\symbolcd.txt" if (!-e $symbolcd);
|
||
|
|
||
|
if ($self->{'PKTYPE'} =~ /FULL/i) {
|
||
|
#
|
||
|
# for full package, we look for $symbolcd exist
|
||
|
# if exist, we load it
|
||
|
#
|
||
|
if (-e $symbolcd) {
|
||
|
($self->{'SYM'}, $self->{'EXT'}) = @{do $symbolcd}; # do command will load the script and evaluate (similar as 'require' command)
|
||
|
} else {
|
||
|
#
|
||
|
# if not exist, we create one in run time from archive path ($self->{'KB'}->{$kbterm})
|
||
|
#
|
||
|
$self->HashArchServer($self->{'KB'}->{$kbterm});
|
||
|
|
||
|
#
|
||
|
# for reuse it next time, we store it to $ENV{'TEMP'}\\symbolcd.txt
|
||
|
#
|
||
|
# so, if we want to create one and store to archive server, we can do below:
|
||
|
# [a.pl]
|
||
|
# use SymMake;
|
||
|
# ($the_archived_source_root, $my_dump_path_in_archive) = @ARGV;
|
||
|
# $symmake = new SymMake $the_archived_source_root, $ENV{_NTPOSTBLD};
|
||
|
# $symmake->ReadSource("$ENV{'TEMP'}\\symbolcd.txt");
|
||
|
# sytem("copy \"$ENV{'TEMP'}\\symbolcd.txt\" $my_dump_path_in_archive
|
||
|
# and call something similar as:
|
||
|
# perl a.pl "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub" "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub\\symbolcd\\symbolcd.txt"
|
||
|
#
|
||
|
$Data::Dumper::Indent=1;
|
||
|
$Data::Dumper::Terse=1;
|
||
|
$fh = new IO::File $symbolcd, 'w';
|
||
|
if (!defined $fh) {
|
||
|
logmsg "Cannot open $symbolcd\.";
|
||
|
} else {
|
||
|
print $fh 'return [';
|
||
|
print $fh Dumper($self->{'SYM'});
|
||
|
print $fh ",\n";
|
||
|
print $fh Dumper($self->{'EXT'});
|
||
|
print $fh '];';
|
||
|
$fh->close();
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
#
|
||
|
# if is from update, we store $self->{'SYM'} and $self->{'EXT'} from symbolcd.txt
|
||
|
#
|
||
|
$self->HashSymbolCD($symbolcd);
|
||
|
}
|
||
|
return;
|
||
|
#
|
||
|
# $Data::Dumper::Indent=1;
|
||
|
# $Data::T
|
||
|
# print Dumper($self->{'SYM'}, qw(sym)
|
||
|
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# $obj->HashSymbolCD($file)
|
||
|
# - store symbolcd.txt($file) to $self->{'SYM'} hash and $self->{'EXT'} hash
|
||
|
#
|
||
|
# IN: $file - the full filespec of the symbolcd.txt
|
||
|
# OUT: none
|
||
|
#
|
||
|
sub HashSymbolCD
|
||
|
{
|
||
|
my ($self, $file) = @_;
|
||
|
my ($fh, $bin, $symbol, $subpath, $installpath, $kbterm);
|
||
|
local $_;
|
||
|
|
||
|
$kbterm = $pktypes{$self->{'PKTYPE'}};
|
||
|
|
||
|
$fh = new IO::File $file;
|
||
|
if (!defined $fh) {
|
||
|
logmsg "Cannot open symbolcd.txt ($file)";
|
||
|
return;
|
||
|
}
|
||
|
while(<$fh>) {
|
||
|
chomp;
|
||
|
($bin,$symbol,$subpath,$installpath)=split(/\,/,$_);
|
||
|
$self->{'SYM'}->{lc"$symbol\.$installpath"} = [$kbterm, "\\" . $subpath, (-s $self->{'KB'}->{$kbterm} . '\\' . $subpath), lc$installpath];
|
||
|
for (keys %pktypes) {
|
||
|
$self->{'EXT'}->{$_}->{lc$installpath} = 1;
|
||
|
}
|
||
|
}
|
||
|
$fh->close();
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# $obj->HashArchServer($path)
|
||
|
# - store the list of symbols under $path to $self->{'SYM'} hash and $self->{'EXT'} hash
|
||
|
#
|
||
|
# IN: $path - the full path of the symbols (such as "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub")
|
||
|
# OUT: none
|
||
|
#
|
||
|
sub HashArchServer
|
||
|
{
|
||
|
my ($self, $path) = @_;
|
||
|
my ($fh, $bin, $symbol, $subpath, $installpath, $kbterm, $pdbsize);
|
||
|
local $_;
|
||
|
|
||
|
$kbterm = $pktypes{$self->{'PKTYPE'}};
|
||
|
$fh = new IO::File "dir /s/b/a-d $path\\*.*|";
|
||
|
if (!defined $fh) {
|
||
|
logmsg "Cannot access to $path\.";
|
||
|
}
|
||
|
while (<$fh>) {
|
||
|
chomp;
|
||
|
$pdbsize = (-s);
|
||
|
$_ = substr($_, length($path) + 1);
|
||
|
/\\/;
|
||
|
($symbol, $subpath, $installpath) = ($',$_,$`);
|
||
|
$self->{'SYM'}->{lc"$symbol\.$installpath"} = [$kbterm, '\\' . $subpath, $pdbsize, $installpath];
|
||
|
$self->{'EXT'}->{$self->{'PKTYPE'}}->{$installpath} = 1;
|
||
|
}
|
||
|
$fh->close();
|
||
|
}
|
||
|
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
#
|
||
|
# for Create_Symbols_CDF, and Create_Symbols_INF
|
||
|
#
|
||
|
# we create two writer, one is writing to update's and full package's files,
|
||
|
# another is only writing to full package's file
|
||
|
#
|
||
|
# so, when we call &{$mywriter{'FULL'} - it only write to full package's file
|
||
|
# when we call &{$mywriter{'UPDATE'} - it write to both files
|
||
|
#
|
||
|
# and, $mysepwriter is for writing separately
|
||
|
# $mysepwriter{'FULL'} - write to full package
|
||
|
# $mysepwriter{'UPDATE'} - write to update package
|
||
|
#
|
||
|
# we base on the writer function to loop our big symbols hash ($self->{'SYM'}) one time to
|
||
|
# generate two documents
|
||
|
#
|
||
|
# for Create_Symbols_DDF
|
||
|
#
|
||
|
# we only need to write each record to one target file (that either in full package, or update
|
||
|
# package to create symbols.cab). So, we don't use writer to write the DDF
|
||
|
#
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
|
||
|
|
||
|
#
|
||
|
# Create_Symbols_CDF($pkinfoptr)
|
||
|
# - Create symbols.CDF which is for creating the symbols.cat
|
||
|
#
|
||
|
# IN: $pkinfoptr-> # see RegisterPackage()
|
||
|
# $pkname -> # such as 'FULL' or 'UPDATE'
|
||
|
# 'CDFHANDLE' -> cdf file handle
|
||
|
# 'CATNAME' -> the symbols catalog file name
|
||
|
# 'INFNAME' -> the symbols inf file name
|
||
|
#
|
||
|
|
||
|
sub Create_Symbols_CDF
|
||
|
{
|
||
|
my ($self, $pkinfoptr) = @_;
|
||
|
my ($mykbterm, $mypkname, $fhandle, $fullpdb, %mywriter);
|
||
|
local $_;
|
||
|
|
||
|
&Open_Private_Handle($pkinfoptr, 'CDF');
|
||
|
|
||
|
for $mypkname (keys %{$pkinfoptr}) {
|
||
|
# create the writer
|
||
|
if ($mypkname ne 'FULL') {
|
||
|
$mywriter{$mypkname} = &Writer($pkinfoptr->{$mypkname}->{'CDFHANDLE'}, $pkinfoptr->{'FULL'}->{'CDFHANDLE'});
|
||
|
} else {
|
||
|
$mywriter{$mypkname} = &Writer($pkinfoptr->{'FULL'}->{'CDFHANDLE'});
|
||
|
}
|
||
|
# write the head to each cdf file handle
|
||
|
&Create_CDF_Head($pkinfoptr->{$mypkname}->{'CDFHANDLE'}, $pkinfoptr->{$mypkname}->{'CATNAME'}, $pkinfoptr->{$mypkname}->{'INFNAME'});
|
||
|
}
|
||
|
|
||
|
# write each record
|
||
|
for (sort keys %{$self->{'SYM'}}) {
|
||
|
$mykbterm = $self->{'SYM'}->{$_}->[0];
|
||
|
$mypkname = $revpktypes{$mykbterm};
|
||
|
$fullpdb = $self->{'KB'}->{$mykbterm} . $self->{'SYM'}->{$_}->[1];
|
||
|
&{$mywriter{$mypkname}}("\<HASH\>" . $fullpdb . '=' . $fullpdb . "\n");
|
||
|
}
|
||
|
|
||
|
&Close_Private_Handle($pkinfoptr, 'CDF');
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Create_Symbols_DDF($pkinfoptr)
|
||
|
# - Create symbols.DDF which is for creating symbols.cab
|
||
|
#
|
||
|
# IN: $pkinfoptr-> # see RegisterPackage()
|
||
|
# $pkname ->
|
||
|
# 'CABNAME' =>
|
||
|
# 'CABDEST' =>
|
||
|
# 'CABSIZE' =>
|
||
|
# 'DDFNAME' =>
|
||
|
# 'CABCOUNT' =>
|
||
|
# 'DDFLIST' => (return cab list)
|
||
|
# 'DDFHANDLE' =>
|
||
|
#
|
||
|
|
||
|
sub Create_Symbols_DDF
|
||
|
{
|
||
|
my ($self, $pkinfoptr) = @_;
|
||
|
my ($symkey, $symptr, $kbterm, $subpath, $pktype, $mypkinfoptr, $cabname, $ddfname, $cabcount, $DDFHandle, $myddfname, $mycabname);
|
||
|
local $_;
|
||
|
|
||
|
# initialization
|
||
|
map({$_->{'CURSIZE'} = $_->{'CABSIZE'}} values %{$pkinfoptr});
|
||
|
|
||
|
for (sort keys %{$self->{'SYM'}}) {
|
||
|
$symkey = $_;
|
||
|
$symptr = $self->{'SYM'}->{$_};
|
||
|
|
||
|
# base on $self->{'SYM'}->{$symbol\.$installpath}->[0] to reference %revpktypes and get the package type ($pktype)
|
||
|
($kbterm, $subpath) = ($symptr->[0],$symptr->[1]);
|
||
|
$pktype = $revpktypes{$kbterm};
|
||
|
|
||
|
# don't generate something not specify
|
||
|
next if (!exists $pkinfoptr->{$pktype});
|
||
|
|
||
|
$mypkinfoptr = $pkinfoptr->{$pktype};
|
||
|
|
||
|
#
|
||
|
# According uncompressed files total size to seperate the cab
|
||
|
# 'CURSIZE' - current size
|
||
|
# 'CABSIZE' - is the approx. size
|
||
|
#
|
||
|
$mypkinfoptr->{'CURSIZE'}+=$symptr->[2];
|
||
|
|
||
|
# if this cab list (ddf) is full
|
||
|
if ($mypkinfoptr->{'CURSIZE'} >= $mypkinfoptr->{'CABSIZE'}) {
|
||
|
|
||
|
# initial the current size to the current symbol's file size
|
||
|
$mypkinfoptr->{'CURSIZE'} = $symptr->[2];
|
||
|
|
||
|
($cabname, $ddfname, $cabcount) = (
|
||
|
$mypkinfoptr->{'CABNAME'},
|
||
|
$mypkinfoptr->{'DDFNAME'},
|
||
|
++$mypkinfoptr->{'CABCOUNT'}
|
||
|
);
|
||
|
|
||
|
$myddfname = $ddfname . $cabcount . '.ddf';
|
||
|
$mycabname = $cabname . $cabcount . '.cab';
|
||
|
|
||
|
# create the new file and its DDF file head
|
||
|
# the old file will automatically close by Perl
|
||
|
$mypkinfoptr->{'DDFHANDLE'} = new IO::File $myddfname, 'w';
|
||
|
if (!defined $mypkinfoptr->{'DDFHANDLE'}) {
|
||
|
logmsg "Cannot open DDF file $myddfname\.";
|
||
|
}
|
||
|
&Create_DDF_Head($mypkinfoptr->{'DDFHANDLE'}, $mycabname);
|
||
|
$mypkinfoptr->{'DDFLIST'}->{$myddfname} = $mycabname;
|
||
|
}
|
||
|
|
||
|
# write the record to the ddf file handle
|
||
|
$DDFHandle = $mypkinfoptr->{'DDFHANDLE'};
|
||
|
print $DDFHandle '"' . $self->{'KB'}->{$kbterm} . $subpath . '" "' . $symkey . "\"\n";
|
||
|
}
|
||
|
|
||
|
&Close_Private_Handle($pkinfoptr, 'DDF');
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Create_Symbols_INF($pkinfoptr)
|
||
|
# - Create symbols.inf
|
||
|
#
|
||
|
#
|
||
|
# pkinfoptr-> # see RegisterPackage()
|
||
|
# $pkname ->
|
||
|
# INFNAME =>
|
||
|
# CDFNAME =>
|
||
|
# CABNAME =>
|
||
|
# CATNAME =>
|
||
|
# INFHANDLE =>
|
||
|
#
|
||
|
|
||
|
sub Create_Symbols_INF
|
||
|
{
|
||
|
my ($self, $pkinfoptr) = @_;
|
||
|
my ($mypkname, $mypkinfoptr, $INFHandle, %mywriter, %mysepwriter, %h, %cabnames);
|
||
|
local $_;
|
||
|
|
||
|
&Open_Private_Handle($pkinfoptr, 'INF');
|
||
|
|
||
|
for $mypkname (keys %{$pkinfoptr}) {
|
||
|
($mypkinfoptr, $INFHandle) = ($pkinfoptr->{$mypkname}, $pkinfoptr->{$mypkname}->{'INFHANDLE'});
|
||
|
|
||
|
# create the writer
|
||
|
if ($mypkname ne 'FULL') {
|
||
|
$mywriter{$mypkname} = &Writer($INFHandle, $pkinfoptr->{'FULL'}->{'INFHANDLE'});
|
||
|
} else {
|
||
|
$mywriter{$mypkname} = &Writer($INFHandle);
|
||
|
}
|
||
|
$mysepwriter{$mypkname} = &Writer($INFHandle);
|
||
|
|
||
|
&Create_INF_Version($INFHandle, $mypkinfoptr->{'CATNAME'});
|
||
|
&Create_INF_Install($INFHandle, $self->{'EXT'}->{$mypkname});
|
||
|
|
||
|
$cabnames{$mypkname} = (FileParse($mypkinfoptr->{'CABNAME'}))[0];
|
||
|
}
|
||
|
|
||
|
# the extension tag (ex. [FILES.EXE]) needs to write separately depends on update / full package has this extension's symbols or not
|
||
|
# so, we need to use separately writer for this kind information
|
||
|
&Create_INF_Files($self->{'SYM'}, \%mysepwriter, \%mywriter);
|
||
|
|
||
|
&Create_INF_SourceDisks($self->{'SYM'}, \%cabnames, \%mysepwriter, \%mywriter);
|
||
|
|
||
|
&Close_Private_Handle($pkinfoptr, 'INF');
|
||
|
}
|
||
|
|
||
|
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
#
|
||
|
# Create_DDF_Head - create the .ddf's file head for symbols(n).ddf
|
||
|
# Create_CDF_Head - create the .cdf's file head for symbols.cdf
|
||
|
# Create_INF_Version - create the .inf's Version section
|
||
|
# Create_INF_Install - create the .inf's [DefaultInstall], [DefaultInstall.Quiet]
|
||
|
# [BeginPromptSection], [EndPromptSection], [RegVersion]
|
||
|
# [SymCust], [CustDest], [CustDest.2], [DestinationDirs]
|
||
|
#
|
||
|
# Create_INF_Files - create the .inf's [Files.<extension>] sections
|
||
|
# Create_INF_SourceDisks - create the [SourceDisksNames], [SourceDisksFiles]
|
||
|
#
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
|
||
|
sub Create_DDF_Head
|
||
|
{
|
||
|
my ($DDFHandle, $cabname) = @_;
|
||
|
my ($mycabname, $mycabdest) = FileParse($cabname);
|
||
|
|
||
|
print $DDFHandle <<DDFHEAD;
|
||
|
.option explicit
|
||
|
.Set DiskDirectoryTemplate=$mycabdest
|
||
|
.Set RptFileName=nul
|
||
|
.Set InfFileName=nul
|
||
|
.Set CabinetNameTemplate=$mycabname\.cab
|
||
|
.Set CompressionType=MSZIP
|
||
|
.Set MaxDiskSize=CDROM
|
||
|
.Set ReservePerCabinetSize=0
|
||
|
.Set Compress=on
|
||
|
.Set CompressionMemory=21
|
||
|
.Set Cabinet=ON
|
||
|
.Set MaxCabinetSize=999999999
|
||
|
.Set FolderSizeThreshold=1000000
|
||
|
DDFHEAD
|
||
|
}
|
||
|
sub Create_CDF_Head
|
||
|
{
|
||
|
my ($CDFHandle, $catname, $infname) = @_;
|
||
|
$catname = (FileParse($catname))[0];
|
||
|
|
||
|
print $CDFHandle <<CDFHEAD;
|
||
|
[CatalogHeader]
|
||
|
Name=$catname
|
||
|
PublicVersion=0x00000001
|
||
|
EncodingType=0x00010001
|
||
|
CATATTR1=0x10010001:OSAttr:2:5.X
|
||
|
|
||
|
[CatalogFiles]
|
||
|
\<HASH\>$infname\.inf=$infname\.inf
|
||
|
CDFHEAD
|
||
|
}
|
||
|
|
||
|
sub Create_INF_Version
|
||
|
{
|
||
|
my ($INFHandle, $catname) = @_;
|
||
|
$catname = (FileParse($catname))[0];
|
||
|
|
||
|
print $INFHandle <<INFVERSION;
|
||
|
[Version]
|
||
|
AdvancedInf= 2.5
|
||
|
Signature= "\$CHICAGO\$"
|
||
|
CatalogFile= $catname\.CAT
|
||
|
INFVERSION
|
||
|
}
|
||
|
|
||
|
sub Create_INF_Install
|
||
|
{
|
||
|
my ($INFHandle, $exthptr) = @_;
|
||
|
my $CopyFiles = 'Files.' . join(", Files\.", sort keys %{$exthptr});
|
||
|
|
||
|
print $INFHandle <<INF_INSTALL;
|
||
|
[DefaultInstall]
|
||
|
CustomDestination= CustDest
|
||
|
AddReg= RegVersion
|
||
|
BeginPrompt= BeginPromptSection
|
||
|
EndPrompt= EndPromptSection
|
||
|
RequireEngine= Setupapi;
|
||
|
CopyFiles= $CopyFiles
|
||
|
|
||
|
[DefaultInstall.Quiet]
|
||
|
CustomDestination=CustDest.2
|
||
|
AddReg= RegVersion
|
||
|
RequireEngine= Setupapi;
|
||
|
CopyFiles= $CopyFiles
|
||
|
|
||
|
[BeginPromptSection]
|
||
|
Title= "Microsoft Windows Symbols"
|
||
|
|
||
|
[EndPromptSection]
|
||
|
Title= "Microsoft Windows Symbols"
|
||
|
Prompt= "Installation is complete"
|
||
|
|
||
|
[RegVersion]
|
||
|
"HKLM","SOFTWARE\\Microsoft\\Symbols\\Directories","Symbol Dir",0,"\%49100\%"
|
||
|
"HKCU","SOFTWARE\\Microsoft\\Symbols\\Directories","Symbol Dir",0,"\%49100\%"
|
||
|
"HKCU","SOFTWARE\\Microsoft\\Symbols\\SymbolInstall","Symbol Install",,"1"
|
||
|
|
||
|
[SymCust]
|
||
|
"HKCU", "Software\\Microsoft\\Symbols\\Directories","Symbol Dir","Symbols install directory","\%25\%\\Symbols"
|
||
|
|
||
|
[CustDest]
|
||
|
49100=SymCust,1
|
||
|
|
||
|
[CustDest.2]
|
||
|
49100=SymCust,5
|
||
|
|
||
|
[DestinationDirs]
|
||
|
;49100 is \%systemroot\%\\symbols
|
||
|
|
||
|
Files.inf = 17
|
||
|
Files.system32 = 11
|
||
|
INF_INSTALL
|
||
|
|
||
|
for (sort keys %{$exthptr}) {
|
||
|
printf $INFHandle ("Files\.%-6s\t\t\= 49100,\"%s\"\n", $_, $_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub Create_INF_Files
|
||
|
{
|
||
|
my ($symptr, $sepwriter, $popwriter) = @_;
|
||
|
my ($mykbterm, $mypkname, %tags);
|
||
|
local $_;
|
||
|
|
||
|
for (sort {($symptr->{$a}->[3] cmp $symptr->{$b}->[3]) or ($a cmp $b)} keys %{$symptr}) {
|
||
|
$mykbterm = $symptr->{$_}->[0];
|
||
|
$mypkname = $revpktypes{$mykbterm};
|
||
|
|
||
|
# if is a new tag name,
|
||
|
if ($symptr->{$_}->[3] ne $tags{$mypkname}->[0]) {
|
||
|
$tags{$mypkname} = [$symptr->{$_}->[3], - length($symptr->{$_}->[3]) -1];
|
||
|
&{$sepwriter->{$mypkname}}("\n\[Files\.$tags{$mypkname}->[0]\]\n");
|
||
|
}
|
||
|
# if its from update list and different with the current full list's file extension
|
||
|
# we need to create a new tag in full list
|
||
|
if ($symptr->{$_}->[3] ne $tags{'FULL'}->[0]) {
|
||
|
$tags{'FULL'} = [$symptr->{$_}->[3], - length($symptr->{$_}->[3]) -1];
|
||
|
&{$sepwriter->{'FULL'}}("\n\[Files\.$tags{'FULL'}->[0]\]\n");
|
||
|
}
|
||
|
# $popwriter will write update ($mypkname) to both files and full to full package list
|
||
|
&{$popwriter->{$mypkname}}(substr($_, 0, $tags{$mypkname}->[1]) . "\,$_\,\,4\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub Create_INF_SourceDisks
|
||
|
{
|
||
|
my ($symptr, $cabnameptr, $sepwriter, $popwriter) = @_; # $pkinfoptr) = @_;
|
||
|
my ($INFHandle, $cabname, $mypkname);
|
||
|
local $_;
|
||
|
|
||
|
for (keys %{$cabnameptr}) {
|
||
|
$cabname = $cabnameptr->{$_};
|
||
|
&{$sepwriter->{$_}}(<<SOURCE_DISKS);
|
||
|
|
||
|
[SourceDisksNames]
|
||
|
1="$cabname\.cab",$cabname\.cab,0
|
||
|
|
||
|
[SourceDisksFiles]
|
||
|
SOURCE_DISKS
|
||
|
}
|
||
|
|
||
|
for (sort keys %{$symptr}) {
|
||
|
$mypkname = $revpktypes{$symptr->{$_}->[0]};
|
||
|
&{$popwriter->{$mypkname}}($_ . "=1\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
#
|
||
|
# Reusable subruntines
|
||
|
#
|
||
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
|
||
|
#
|
||
|
# RegisterPackage($pkinfoptr, $pktype,$hptr)
|
||
|
# - register $hptr to $pkinfoptr->{$pktype}
|
||
|
# - registerpackage is the function to verify and store $pkinfoptr
|
||
|
# - the cabname, ddfname, infname, cdfname, catname - are equal to 'SYMBOLS' normally
|
||
|
# - cabsize is the total size for include files into one cab, we cannot compute the compressed
|
||
|
# file size, so we compute with the uncompress file size
|
||
|
#
|
||
|
# - cabhandle, ddfhandle, infhandle - the file handles for .cab, .ddf and .inf; we create them
|
||
|
# inside this module
|
||
|
# - DDFLIST - the lists of the ddf files we plan to create
|
||
|
#
|
||
|
# $pkinfoptr->
|
||
|
# $pktype ->
|
||
|
# CABNAME
|
||
|
# DDFNAME
|
||
|
# INFNAME
|
||
|
# CDFNAME
|
||
|
# CATNAME
|
||
|
# CABSIZE
|
||
|
#
|
||
|
# CABHANDLE - (reserved)
|
||
|
# DDFHANDLE - (reserved)
|
||
|
# INFHANDLE - (reserved)
|
||
|
#
|
||
|
# DDFLIST - (return)
|
||
|
#
|
||
|
sub RegisterPackage
|
||
|
{
|
||
|
my ($pkinfoptr, $pktype, $hptr) = @_;
|
||
|
|
||
|
my ($mykey);
|
||
|
my @chklists = qw(CABNAME DDFNAME INFNAME CDFNAME CATNAME CABSIZE);
|
||
|
|
||
|
# register to $pkinfoptr
|
||
|
$pkinfoptr->{$pktype} = $hptr;
|
||
|
|
||
|
# check we have enough information
|
||
|
for $mykey (@chklists) {
|
||
|
die "$mykey not defined in $pktype" if (!exists $pkinfoptr->{$pktype}->{$mykey});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#
|
||
|
# $obj = Writer(@handles)
|
||
|
# - the writer generator; generates a function to write one data to each @handles
|
||
|
# keep @handles in parent program and $_[0] in sub {....} is the data we send to &{$obj}($data)
|
||
|
#
|
||
|
sub Writer {
|
||
|
my (@handles) = @_;
|
||
|
my ($hptr)=\@handles;
|
||
|
return sub {
|
||
|
my ($myhandle);
|
||
|
for $myhandle (@{$hptr}) {
|
||
|
print $myhandle $_[0];
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Open_Private_Handle($pkinfoptr, $ftype)
|
||
|
# - open each pkname of each $ftype name's file and store the handle to $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}
|
||
|
# - for example, if we call Open_Private_Handle($pkinfoptr, 'DDF')
|
||
|
# - it open $pkinfoptr->{'FULL'}->{'DDFNAME'} and $pkinfoptr->{'UPDATE'}->{'DDFNAME'}
|
||
|
# - and store the file handle to $pkinfoptr->{'FULL'}->{'DDFHANDLE'} and $pkinfoptr->{'UPDATE'}->{'DDFHANDLE'}
|
||
|
#
|
||
|
sub Open_Private_Handle
|
||
|
{
|
||
|
my ($pkinfoptr, $ftype) = @_;
|
||
|
my ($pkname);
|
||
|
for $pkname (keys %{$pkinfoptr}) {
|
||
|
$pkinfoptr->{$pkname}->{$ftype . 'HANDLE'} = new IO::File $pkinfoptr->{$pkname}->{$ftype . 'NAME'} . '.' . $ftype, 'w';
|
||
|
if (!defined $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}) {
|
||
|
logmsg "Cannot open " . $pkinfoptr->{$pkname}->{$ftype . 'NAME'} . '.' . $ftype . ".";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub Close_Private_Handle
|
||
|
{
|
||
|
my ($pkinfoptr, $ftype) = @_;
|
||
|
my ($pkname);
|
||
|
for $pkname (keys %{$pkinfoptr}) {
|
||
|
$pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}->close() if (defined $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'});
|
||
|
delete $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub FileParse
|
||
|
{
|
||
|
my ($name, $path, $ext) = fileparse(shift, '\.[^\.]+$');
|
||
|
$ext =~ s/^\.//;
|
||
|
return $name, $path, $ext;
|
||
|
}
|
||
|
|
||
|
1;
|