1*b1cdbd2cSJim Jagielski#************************************************************** 2*b1cdbd2cSJim Jagielski# 3*b1cdbd2cSJim Jagielski# Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski# or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski# distributed with this work for additional information 6*b1cdbd2cSJim Jagielski# regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski# to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski# "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski# with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski# 11*b1cdbd2cSJim Jagielski# http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski# 13*b1cdbd2cSJim Jagielski# Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski# software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski# KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski# specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski# under the License. 19*b1cdbd2cSJim Jagielski# 20*b1cdbd2cSJim Jagielski#************************************************************** 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielskipackage installer::windows::sign; 25*b1cdbd2cSJim Jagielski 26*b1cdbd2cSJim Jagielskiuse Cwd; 27*b1cdbd2cSJim Jagielskiuse installer::converter; 28*b1cdbd2cSJim Jagielskiuse installer::existence; 29*b1cdbd2cSJim Jagielskiuse installer::files; 30*b1cdbd2cSJim Jagielskiuse installer::globals; 31*b1cdbd2cSJim Jagielskiuse installer::scriptitems; 32*b1cdbd2cSJim Jagielskiuse installer::worker; 33*b1cdbd2cSJim Jagielskiuse installer::windows::admin; 34*b1cdbd2cSJim Jagielski 35*b1cdbd2cSJim Jagielski######################################################## 36*b1cdbd2cSJim Jagielski# Copying an existing Windows installation set. 37*b1cdbd2cSJim Jagielski######################################################## 38*b1cdbd2cSJim Jagielski 39*b1cdbd2cSJim Jagielskisub copy_install_set 40*b1cdbd2cSJim Jagielski{ 41*b1cdbd2cSJim Jagielski my ( $installsetpath ) = @_; 42*b1cdbd2cSJim Jagielski 43*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("Start: Copying installation set $installsetpath"); 44*b1cdbd2cSJim Jagielski 45*b1cdbd2cSJim Jagielski my $infoline = ""; 46*b1cdbd2cSJim Jagielski 47*b1cdbd2cSJim Jagielski my $dirname = $installsetpath; 48*b1cdbd2cSJim Jagielski installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname); 49*b1cdbd2cSJim Jagielski 50*b1cdbd2cSJim Jagielski my $path = $installsetpath; 51*b1cdbd2cSJim Jagielski installer::pathanalyzer::get_path_from_fullqualifiedname(\$path); 52*b1cdbd2cSJim Jagielski 53*b1cdbd2cSJim Jagielski $path =~ s/\Q$installer::globals::separator\E\s*$//; 54*b1cdbd2cSJim Jagielski 55*b1cdbd2cSJim Jagielski if ( $dirname =~ /\./ ) { $dirname =~ s/\./_signed_inprogress./; } 56*b1cdbd2cSJim Jagielski else { $dirname = $dirname . "_signed_inprogress"; } 57*b1cdbd2cSJim Jagielski 58*b1cdbd2cSJim Jagielski my $newpath = $path . $installer::globals::separator . $dirname; 59*b1cdbd2cSJim Jagielski my $removepath = $newpath; 60*b1cdbd2cSJim Jagielski $removepath =~ s/_inprogress/_witherror/; 61*b1cdbd2cSJim Jagielski 62*b1cdbd2cSJim Jagielski if ( -d $newpath ) { installer::systemactions::remove_complete_directory($newpath, 1); } 63*b1cdbd2cSJim Jagielski if ( -d $removepath ) { installer::systemactions::remove_complete_directory($removepath, 1); } 64*b1cdbd2cSJim Jagielski 65*b1cdbd2cSJim Jagielski $infoline = "Copy installation set from $installsetpath to $newpath\n"; 66*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 67*b1cdbd2cSJim Jagielski 68*b1cdbd2cSJim Jagielski $installsetpath = installer::systemactions::copy_complete_directory($installsetpath, $newpath); 69*b1cdbd2cSJim Jagielski 70*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("End: Copying installation set $installsetpath"); 71*b1cdbd2cSJim Jagielski 72*b1cdbd2cSJim Jagielski return $newpath; 73*b1cdbd2cSJim Jagielski} 74*b1cdbd2cSJim Jagielski 75*b1cdbd2cSJim Jagielski######################################################## 76*b1cdbd2cSJim Jagielski# Renaming an existing Windows installation set. 77*b1cdbd2cSJim Jagielski######################################################## 78*b1cdbd2cSJim Jagielski 79*b1cdbd2cSJim Jagielskisub rename_install_set 80*b1cdbd2cSJim Jagielski{ 81*b1cdbd2cSJim Jagielski my ( $installsetpath ) = @_; 82*b1cdbd2cSJim Jagielski 83*b1cdbd2cSJim Jagielski my $infoline = ""; 84*b1cdbd2cSJim Jagielski 85*b1cdbd2cSJim Jagielski my $dirname = $installsetpath; 86*b1cdbd2cSJim Jagielski installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname); 87*b1cdbd2cSJim Jagielski 88*b1cdbd2cSJim Jagielski my $path = $installsetpath; 89*b1cdbd2cSJim Jagielski installer::pathanalyzer::get_path_from_fullqualifiedname(\$path); 90*b1cdbd2cSJim Jagielski 91*b1cdbd2cSJim Jagielski $path =~ s/\Q$installer::globals::separator\E\s*$//; 92*b1cdbd2cSJim Jagielski 93*b1cdbd2cSJim Jagielski if ( $dirname =~ /\./ ) { $dirname =~ s/\./_inprogress./; } 94*b1cdbd2cSJim Jagielski else { $dirname = $dirname . "_inprogress"; } 95*b1cdbd2cSJim Jagielski 96*b1cdbd2cSJim Jagielski my $newpath = $path . $installer::globals::separator . $dirname; 97*b1cdbd2cSJim Jagielski my $removepath = $newpath; 98*b1cdbd2cSJim Jagielski $removepath =~ s/_inprogress/_witherror/; 99*b1cdbd2cSJim Jagielski 100*b1cdbd2cSJim Jagielski if ( -d $newpath ) { installer::systemactions::remove_complete_directory($newpath, 1); } 101*b1cdbd2cSJim Jagielski if ( -d $removepath ) { installer::systemactions::remove_complete_directory($removepath, 1); } 102*b1cdbd2cSJim Jagielski 103*b1cdbd2cSJim Jagielski $installsetpath = installer::systemactions::rename_directory($installsetpath, $newpath); 104*b1cdbd2cSJim Jagielski 105*b1cdbd2cSJim Jagielski return $newpath; 106*b1cdbd2cSJim Jagielski} 107*b1cdbd2cSJim Jagielski 108*b1cdbd2cSJim Jagielski######################################################### 109*b1cdbd2cSJim Jagielski# Checking the local system 110*b1cdbd2cSJim Jagielski# Checking existence of needed files in include path 111*b1cdbd2cSJim Jagielski######################################################### 112*b1cdbd2cSJim Jagielski 113*b1cdbd2cSJim Jagielskisub check_system_path 114*b1cdbd2cSJim Jagielski{ 115*b1cdbd2cSJim Jagielski # The following files have to be found in the environment variable PATH 116*b1cdbd2cSJim Jagielski # Only, if \"-sign\" is used. 117*b1cdbd2cSJim Jagielski # Windows : "msicert.exe", "diff.exe", "msidb.exe", "signtool.exe" 118*b1cdbd2cSJim Jagielski 119*b1cdbd2cSJim Jagielski my @needed_files_in_path = ("msicert.exe", "msidb.exe", "signtool.exe", "diff.exe"); 120*b1cdbd2cSJim Jagielski if ( $installer::globals::internal_cabinet_signing ) 121*b1cdbd2cSJim Jagielski { 122*b1cdbd2cSJim Jagielski push(@needed_files_in_path, "cabarc.exe"); 123*b1cdbd2cSJim Jagielski push(@needed_files_in_path, "makecab.exe"); 124*b1cdbd2cSJim Jagielski } 125*b1cdbd2cSJim Jagielski 126*b1cdbd2cSJim Jagielski my $onefile; 127*b1cdbd2cSJim Jagielski my $error = 0; 128*b1cdbd2cSJim Jagielski my $pathvariable = $ENV{'PATH'}; 129*b1cdbd2cSJim Jagielski my $local_pathseparator = $installer::globals::pathseparator; 130*b1cdbd2cSJim Jagielski 131*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 132*b1cdbd2cSJim Jagielski { # When using cygwin's perl the PATH variable is POSIX style and ... 133*b1cdbd2cSJim Jagielski $pathvariable = qx{cygpath -mp "$pathvariable"} ; 134*b1cdbd2cSJim Jagielski # has to be converted to DOS style for further use. 135*b1cdbd2cSJim Jagielski $local_pathseparator = ';'; 136*b1cdbd2cSJim Jagielski } 137*b1cdbd2cSJim Jagielski 138*b1cdbd2cSJim Jagielski my $patharrayref = installer::converter::convert_stringlist_into_array(\$pathvariable, $local_pathseparator); 139*b1cdbd2cSJim Jagielski 140*b1cdbd2cSJim Jagielski $installer::globals::patharray = $patharrayref; 141*b1cdbd2cSJim Jagielski 142*b1cdbd2cSJim Jagielski foreach my $onefile ( @needed_files_in_path ) 143*b1cdbd2cSJim Jagielski { 144*b1cdbd2cSJim Jagielski 145*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("...... searching %s ...\n", $onefile); 146*b1cdbd2cSJim Jagielski 147*b1cdbd2cSJim Jagielski my $fileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath_classic(\$onefile, $patharrayref , 0); 148*b1cdbd2cSJim Jagielski 149*b1cdbd2cSJim Jagielski if ( $$fileref eq "" ) 150*b1cdbd2cSJim Jagielski { 151*b1cdbd2cSJim Jagielski $error = 1; 152*b1cdbd2cSJim Jagielski installer::logger::print_error( "$onefile not found\n" ); 153*b1cdbd2cSJim Jagielski } 154*b1cdbd2cSJim Jagielski else 155*b1cdbd2cSJim Jagielski { 156*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("\tFound: %s\n", $$fileref); 157*b1cdbd2cSJim Jagielski } 158*b1cdbd2cSJim Jagielski } 159*b1cdbd2cSJim Jagielski 160*b1cdbd2cSJim Jagielski $installer::globals::signfiles_checked = 1; 161*b1cdbd2cSJim Jagielski 162*b1cdbd2cSJim Jagielski if ( $error ) { installer::exiter::exit_program("ERROR: Could not find all needed files in path!", "check_system_path"); } 163*b1cdbd2cSJim Jagielski} 164*b1cdbd2cSJim Jagielski 165*b1cdbd2cSJim Jagielski###################################################### 166*b1cdbd2cSJim Jagielski# Making systemcall 167*b1cdbd2cSJim Jagielski###################################################### 168*b1cdbd2cSJim Jagielski 169*b1cdbd2cSJim Jagielskisub make_systemcall 170*b1cdbd2cSJim Jagielski{ 171*b1cdbd2cSJim Jagielski my ($systemcall, $displaysystemcall) = @_; 172*b1cdbd2cSJim Jagielski 173*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... %s ...\n", $displaysystemcall); 174*b1cdbd2cSJim Jagielski 175*b1cdbd2cSJim Jagielski my $success = 1; 176*b1cdbd2cSJim Jagielski my $returnvalue = system($systemcall); 177*b1cdbd2cSJim Jagielski 178*b1cdbd2cSJim Jagielski my $infoline = "Systemcall: $displaysystemcall\n"; 179*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 180*b1cdbd2cSJim Jagielski 181*b1cdbd2cSJim Jagielski if ($returnvalue) 182*b1cdbd2cSJim Jagielski { 183*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute \"$displaysystemcall\"!\n"; 184*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 185*b1cdbd2cSJim Jagielski $success = 0; 186*b1cdbd2cSJim Jagielski } 187*b1cdbd2cSJim Jagielski else 188*b1cdbd2cSJim Jagielski { 189*b1cdbd2cSJim Jagielski $infoline = "Success: Executed \"$displaysystemcall\" successfully!\n"; 190*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 191*b1cdbd2cSJim Jagielski } 192*b1cdbd2cSJim Jagielski 193*b1cdbd2cSJim Jagielski return $success; 194*b1cdbd2cSJim Jagielski} 195*b1cdbd2cSJim Jagielski 196*b1cdbd2cSJim Jagielski###################################################### 197*b1cdbd2cSJim Jagielski# Making systemcall with warning 198*b1cdbd2cSJim Jagielski###################################################### 199*b1cdbd2cSJim Jagielski 200*b1cdbd2cSJim Jagielskisub make_systemcall_with_warning 201*b1cdbd2cSJim Jagielski{ 202*b1cdbd2cSJim Jagielski my ($systemcall, $displaysystemcall) = @_; 203*b1cdbd2cSJim Jagielski 204*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... %s ...\n", $displaysystemcall); 205*b1cdbd2cSJim Jagielski 206*b1cdbd2cSJim Jagielski my $success = 1; 207*b1cdbd2cSJim Jagielski my $returnvalue = system($systemcall); 208*b1cdbd2cSJim Jagielski 209*b1cdbd2cSJim Jagielski my $infoline = "Systemcall: $displaysystemcall\n"; 210*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 211*b1cdbd2cSJim Jagielski 212*b1cdbd2cSJim Jagielski if ($returnvalue) 213*b1cdbd2cSJim Jagielski { 214*b1cdbd2cSJim Jagielski $infoline = "WARNING: Could not execute \"$displaysystemcall\"!\n"; 215*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 216*b1cdbd2cSJim Jagielski $success = 0; 217*b1cdbd2cSJim Jagielski } 218*b1cdbd2cSJim Jagielski else 219*b1cdbd2cSJim Jagielski { 220*b1cdbd2cSJim Jagielski $infoline = "Success: Executed \"$displaysystemcall\" successfully!\n"; 221*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 222*b1cdbd2cSJim Jagielski } 223*b1cdbd2cSJim Jagielski 224*b1cdbd2cSJim Jagielski return $success; 225*b1cdbd2cSJim Jagielski} 226*b1cdbd2cSJim Jagielski 227*b1cdbd2cSJim Jagielski###################################################### 228*b1cdbd2cSJim Jagielski# Making systemcall with more return data 229*b1cdbd2cSJim Jagielski###################################################### 230*b1cdbd2cSJim Jagielski 231*b1cdbd2cSJim Jagielskisub execute_open_system_call 232*b1cdbd2cSJim Jagielski{ 233*b1cdbd2cSJim Jagielski my ( $systemcall ) = @_; 234*b1cdbd2cSJim Jagielski 235*b1cdbd2cSJim Jagielski my @openoutput = (); 236*b1cdbd2cSJim Jagielski my $success = 1; 237*b1cdbd2cSJim Jagielski 238*b1cdbd2cSJim Jagielski my $comspec = $ENV{COMSPEC}; 239*b1cdbd2cSJim Jagielski $comspec = $comspec . " -c "; 240*b1cdbd2cSJim Jagielski 241*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 242*b1cdbd2cSJim Jagielski { 243*b1cdbd2cSJim Jagielski # $comspec =~ s/\\/\\\\/g; 244*b1cdbd2cSJim Jagielski # $comspec = qx{cygpath -u "$comspec"}; 245*b1cdbd2cSJim Jagielski # $comspec =~ s/\s*$//g; 246*b1cdbd2cSJim Jagielski $comspec = ""; 247*b1cdbd2cSJim Jagielski } 248*b1cdbd2cSJim Jagielski 249*b1cdbd2cSJim Jagielski my $localsystemcall = "$comspec $systemcall 2>&1 |"; 250*b1cdbd2cSJim Jagielski 251*b1cdbd2cSJim Jagielski open( OPN, "$localsystemcall") or warn "Can't execute $localsystemcall\n"; 252*b1cdbd2cSJim Jagielski while (<OPN>) { push(@openoutput, $_); } 253*b1cdbd2cSJim Jagielski close (OPN); 254*b1cdbd2cSJim Jagielski 255*b1cdbd2cSJim Jagielski my $returnvalue = $?; # $? contains the return value of the systemcall 256*b1cdbd2cSJim Jagielski 257*b1cdbd2cSJim Jagielski if ($returnvalue) 258*b1cdbd2cSJim Jagielski { 259*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute \"$systemcall\"!\n"; 260*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 261*b1cdbd2cSJim Jagielski $success = 0; 262*b1cdbd2cSJim Jagielski } 263*b1cdbd2cSJim Jagielski else 264*b1cdbd2cSJim Jagielski { 265*b1cdbd2cSJim Jagielski $infoline = "Success: Executed \"$systemcall\" successfully!\n"; 266*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 267*b1cdbd2cSJim Jagielski } 268*b1cdbd2cSJim Jagielski 269*b1cdbd2cSJim Jagielski return ($success, \@openoutput); 270*b1cdbd2cSJim Jagielski} 271*b1cdbd2cSJim Jagielski 272*b1cdbd2cSJim Jagielski######################################################## 273*b1cdbd2cSJim Jagielski# Reading first line of pw file. 274*b1cdbd2cSJim Jagielski######################################################## 275*b1cdbd2cSJim Jagielski 276*b1cdbd2cSJim Jagielskisub get_pw 277*b1cdbd2cSJim Jagielski{ 278*b1cdbd2cSJim Jagielski my ( $file ) = @_; 279*b1cdbd2cSJim Jagielski 280*b1cdbd2cSJim Jagielski my $filecontent = installer::files::read_file($file); 281*b1cdbd2cSJim Jagielski 282*b1cdbd2cSJim Jagielski my $pw = ${$filecontent}[0]; 283*b1cdbd2cSJim Jagielski $pw =~ s/^\s*//; 284*b1cdbd2cSJim Jagielski $pw =~ s/\s*$//; 285*b1cdbd2cSJim Jagielski 286*b1cdbd2cSJim Jagielski return $pw; 287*b1cdbd2cSJim Jagielski} 288*b1cdbd2cSJim Jagielski 289*b1cdbd2cSJim Jagielski######################################################## 290*b1cdbd2cSJim Jagielski# Counting the keys of a hash. 291*b1cdbd2cSJim Jagielski######################################################## 292*b1cdbd2cSJim Jagielski 293*b1cdbd2cSJim Jagielskisub get_hash_count 294*b1cdbd2cSJim Jagielski{ 295*b1cdbd2cSJim Jagielski my ($hashref) = @_; 296*b1cdbd2cSJim Jagielski 297*b1cdbd2cSJim Jagielski my $counter = 0; 298*b1cdbd2cSJim Jagielski 299*b1cdbd2cSJim Jagielski foreach my $key ( keys %{$hashref} ) { $counter++; } 300*b1cdbd2cSJim Jagielski 301*b1cdbd2cSJim Jagielski return $counter; 302*b1cdbd2cSJim Jagielski} 303*b1cdbd2cSJim Jagielski 304*b1cdbd2cSJim Jagielski############################################################ 305*b1cdbd2cSJim Jagielski# Collect all last files in a cabinet file. This is 306*b1cdbd2cSJim Jagielski# necessary to control, if the cabinet file was damaged 307*b1cdbd2cSJim Jagielski# by calling signtool.exe. 308*b1cdbd2cSJim Jagielski############################################################ 309*b1cdbd2cSJim Jagielski 310*b1cdbd2cSJim Jagielskisub analyze_file_file 311*b1cdbd2cSJim Jagielski{ 312*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 313*b1cdbd2cSJim Jagielski 314*b1cdbd2cSJim Jagielski my %filenamehash = (); 315*b1cdbd2cSJim Jagielski 316*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 317*b1cdbd2cSJim Jagielski { 318*b1cdbd2cSJim Jagielski if ( $i < 3 ) { next; } 319*b1cdbd2cSJim Jagielski 320*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 321*b1cdbd2cSJim Jagielski { 322*b1cdbd2cSJim Jagielski my $name = $1; 323*b1cdbd2cSJim Jagielski my $sequence = $8; 324*b1cdbd2cSJim Jagielski 325*b1cdbd2cSJim Jagielski $filenamehash{$sequence} = $name; 326*b1cdbd2cSJim Jagielski } 327*b1cdbd2cSJim Jagielski } 328*b1cdbd2cSJim Jagielski 329*b1cdbd2cSJim Jagielski return ( \%filenamehash ); 330*b1cdbd2cSJim Jagielski} 331*b1cdbd2cSJim Jagielski 332*b1cdbd2cSJim Jagielski############################################################ 333*b1cdbd2cSJim Jagielski# Collect all DiskIds to the corresponding cabinet files. 334*b1cdbd2cSJim Jagielski############################################################ 335*b1cdbd2cSJim Jagielski 336*b1cdbd2cSJim Jagielskisub analyze_media_file 337*b1cdbd2cSJim Jagielski{ 338*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 339*b1cdbd2cSJim Jagielski 340*b1cdbd2cSJim Jagielski my %diskidhash = (); 341*b1cdbd2cSJim Jagielski my %lastsequencehash = (); 342*b1cdbd2cSJim Jagielski 343*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 344*b1cdbd2cSJim Jagielski { 345*b1cdbd2cSJim Jagielski if ( $i < 3 ) { next; } 346*b1cdbd2cSJim Jagielski 347*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 348*b1cdbd2cSJim Jagielski { 349*b1cdbd2cSJim Jagielski my $diskid = $1; 350*b1cdbd2cSJim Jagielski my $lastsequence = $2; 351*b1cdbd2cSJim Jagielski my $cabfile = $4; 352*b1cdbd2cSJim Jagielski 353*b1cdbd2cSJim Jagielski $diskidhash{$cabfile} = $diskid; 354*b1cdbd2cSJim Jagielski $lastsequencehash{$cabfile} = $lastsequence; 355*b1cdbd2cSJim Jagielski } 356*b1cdbd2cSJim Jagielski } 357*b1cdbd2cSJim Jagielski 358*b1cdbd2cSJim Jagielski return ( \%diskidhash, \%lastsequencehash ); 359*b1cdbd2cSJim Jagielski} 360*b1cdbd2cSJim Jagielski 361*b1cdbd2cSJim Jagielski######################################################## 362*b1cdbd2cSJim Jagielski# Collect all DiskIds from database table "Media". 363*b1cdbd2cSJim Jagielski######################################################## 364*b1cdbd2cSJim Jagielski 365*b1cdbd2cSJim Jagielskisub collect_diskid_from_media_table 366*b1cdbd2cSJim Jagielski{ 367*b1cdbd2cSJim Jagielski my ($msidatabase, $languagestring) = @_; 368*b1cdbd2cSJim Jagielski 369*b1cdbd2cSJim Jagielski # creating working directory 370*b1cdbd2cSJim Jagielski my $workdir = installer::systemactions::create_directories("media", \$languagestring); 371*b1cdbd2cSJim Jagielski installer::windows::admin::extract_tables_from_pcpfile($msidatabase, $workdir, "Media File"); 372*b1cdbd2cSJim Jagielski 373*b1cdbd2cSJim Jagielski # Reading tables 374*b1cdbd2cSJim Jagielski my $filename = $workdir . $installer::globals::separator . "Media.idt"; 375*b1cdbd2cSJim Jagielski if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find required file: $filename !", "collect_diskid_from_media_table"); } 376*b1cdbd2cSJim Jagielski my $filecontent = installer::files::read_file($filename); 377*b1cdbd2cSJim Jagielski my ( $diskidhash, $lastsequencehash ) = analyze_media_file($filecontent); 378*b1cdbd2cSJim Jagielski 379*b1cdbd2cSJim Jagielski $filename = $workdir . $installer::globals::separator . "File.idt"; 380*b1cdbd2cSJim Jagielski if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find required file: $filename !", "collect_diskid_from_media_table"); } 381*b1cdbd2cSJim Jagielski $filecontent = installer::files::read_file($filename); 382*b1cdbd2cSJim Jagielski my $filenamehash = analyze_file_file($filecontent); 383*b1cdbd2cSJim Jagielski 384*b1cdbd2cSJim Jagielski return ( $diskidhash, $filenamehash, $lastsequencehash ); 385*b1cdbd2cSJim Jagielski} 386*b1cdbd2cSJim Jagielski 387*b1cdbd2cSJim Jagielski######################################################## 388*b1cdbd2cSJim Jagielski# Check, if this installation set contains 389*b1cdbd2cSJim Jagielski# internal cabinet files included into the msi 390*b1cdbd2cSJim Jagielski# database. 391*b1cdbd2cSJim Jagielski######################################################## 392*b1cdbd2cSJim Jagielski 393*b1cdbd2cSJim Jagielskisub check_for_internal_cabfiles 394*b1cdbd2cSJim Jagielski{ 395*b1cdbd2cSJim Jagielski my ($cabfilehash) = @_; 396*b1cdbd2cSJim Jagielski 397*b1cdbd2cSJim Jagielski my $contains_internal_cabfiles = 0; 398*b1cdbd2cSJim Jagielski my %allcabfileshash = (); 399*b1cdbd2cSJim Jagielski 400*b1cdbd2cSJim Jagielski foreach my $filename ( keys %{$cabfilehash} ) 401*b1cdbd2cSJim Jagielski { 402*b1cdbd2cSJim Jagielski if ( $filename =~ /^\s*\#/ ) # starting with a hash 403*b1cdbd2cSJim Jagielski { 404*b1cdbd2cSJim Jagielski $contains_internal_cabfiles = 1; 405*b1cdbd2cSJim Jagielski # setting real filename without hash as key and name with hash as value 406*b1cdbd2cSJim Jagielski my $realfilename = $filename; 407*b1cdbd2cSJim Jagielski $realfilename =~ s/^\s*\#//; 408*b1cdbd2cSJim Jagielski $allcabfileshash{$realfilename} = $filename; 409*b1cdbd2cSJim Jagielski } 410*b1cdbd2cSJim Jagielski } 411*b1cdbd2cSJim Jagielski 412*b1cdbd2cSJim Jagielski return ( $contains_internal_cabfiles, \%allcabfileshash ); 413*b1cdbd2cSJim Jagielski} 414*b1cdbd2cSJim Jagielski 415*b1cdbd2cSJim Jagielski######################################################## 416*b1cdbd2cSJim Jagielski# Collecting all files in an installation set. 417*b1cdbd2cSJim Jagielski######################################################## 418*b1cdbd2cSJim Jagielski 419*b1cdbd2cSJim Jagielskisub analyze_installset_content 420*b1cdbd2cSJim Jagielski{ 421*b1cdbd2cSJim Jagielski my ( $installsetpath ) = @_; 422*b1cdbd2cSJim Jagielski 423*b1cdbd2cSJim Jagielski my @sourcefiles = (); 424*b1cdbd2cSJim Jagielski my $pathstring = ""; 425*b1cdbd2cSJim Jagielski installer::systemactions::read_complete_directory($installsetpath, $pathstring, \@sourcefiles); 426*b1cdbd2cSJim Jagielski 427*b1cdbd2cSJim Jagielski if ( ! ( $#sourcefiles > -1 )) { installer::exiter::exit_program("ERROR: No file in installation set. Path: $installsetpath !", "analyze_installset_content"); } 428*b1cdbd2cSJim Jagielski 429*b1cdbd2cSJim Jagielski my %allcabfileshash = (); 430*b1cdbd2cSJim Jagielski my %allmsidatabaseshash = (); 431*b1cdbd2cSJim Jagielski my %allfileshash = (); 432*b1cdbd2cSJim Jagielski my $contains_external_cabfiles = 0; 433*b1cdbd2cSJim Jagielski my $msidatabase = ""; 434*b1cdbd2cSJim Jagielski my $contains_msidatabase = 0; 435*b1cdbd2cSJim Jagielski 436*b1cdbd2cSJim Jagielski for ( my $j = 0; $j <= $#sourcefiles; $j++ ) 437*b1cdbd2cSJim Jagielski { 438*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.cab\s*$/ ) { $allcabfileshash{$sourcefiles[$j]} = 1; } 439*b1cdbd2cSJim Jagielski else 440*b1cdbd2cSJim Jagielski { 441*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.txt\s*$/ ) { next; } 442*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.html\s*$/ ) { next; } 443*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.ini\s*$/ ) { next; } 444*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.bmp\s*$/ ) { next; } 445*b1cdbd2cSJim Jagielski if ( $sourcefiles[$j] =~ /\.msi\s*$/ ) 446*b1cdbd2cSJim Jagielski { 447*b1cdbd2cSJim Jagielski if ( $msidatabase eq "" ) { $msidatabase = $sourcefiles[$j]; } 448*b1cdbd2cSJim Jagielski else { installer::exiter::exit_program("ERROR: There is more than one msi database in installation set. Path: $installsetpath !", "analyze_installset_content"); } 449*b1cdbd2cSJim Jagielski } 450*b1cdbd2cSJim Jagielski $allfileshash{$sourcefiles[$j]} = 1; 451*b1cdbd2cSJim Jagielski } 452*b1cdbd2cSJim Jagielski } 453*b1cdbd2cSJim Jagielski 454*b1cdbd2cSJim Jagielski # Is there at least one cab file in the installation set? 455*b1cdbd2cSJim Jagielski my $cabcounter = get_hash_count(\%allcabfileshash); 456*b1cdbd2cSJim Jagielski if ( $cabcounter > 0 ) { $contains_external_cabfiles = 1; } 457*b1cdbd2cSJim Jagielski 458*b1cdbd2cSJim Jagielski # How about a cab file without a msi database? 459*b1cdbd2cSJim Jagielski if (( $cabcounter > 0 ) && ( $msidatabase eq "" )) { installer::exiter::exit_program("ERROR: There is no msi database in the installation set, but an external cabinet file. Path: $installsetpath !", "collect_installset_content"); } 460*b1cdbd2cSJim Jagielski 461*b1cdbd2cSJim Jagielski if ( $msidatabase ne "" ) { $contains_msidatabase = 1; } 462*b1cdbd2cSJim Jagielski 463*b1cdbd2cSJim Jagielski return (\%allcabfileshash, \%allfileshash, $msidatabase, $contains_external_cabfiles, $contains_msidatabase, \@sourcefiles); 464*b1cdbd2cSJim Jagielski} 465*b1cdbd2cSJim Jagielski 466*b1cdbd2cSJim Jagielski######################################################## 467*b1cdbd2cSJim Jagielski# Adding content of external cabinet files into the 468*b1cdbd2cSJim Jagielski# msi database 469*b1cdbd2cSJim Jagielski######################################################## 470*b1cdbd2cSJim Jagielski 471*b1cdbd2cSJim Jagielskisub msicert_database 472*b1cdbd2cSJim Jagielski{ 473*b1cdbd2cSJim Jagielski my ($msidatabase, $allcabfiles, $cabfilehash, $internalcabfile) = @_; 474*b1cdbd2cSJim Jagielski 475*b1cdbd2cSJim Jagielski my $fullsuccess = 1; 476*b1cdbd2cSJim Jagielski 477*b1cdbd2cSJim Jagielski foreach my $cabfile ( keys %{$allcabfiles} ) 478*b1cdbd2cSJim Jagielski { 479*b1cdbd2cSJim Jagielski my $origfilesize = -s $cabfile; 480*b1cdbd2cSJim Jagielski 481*b1cdbd2cSJim Jagielski my $mediacabfilename = $cabfile; 482*b1cdbd2cSJim Jagielski if ( $internalcabfile ) { $mediacabfilename = "\#" . $mediacabfilename; } 483*b1cdbd2cSJim Jagielski if ( ! exists($cabfilehash->{$mediacabfilename}) ) { installer::exiter::exit_program("ERROR: Could not determine DiskId from media table for cabinet file \"$cabfile\" !", "msicert_database"); } 484*b1cdbd2cSJim Jagielski my $diskid = $cabfilehash->{$mediacabfilename}; 485*b1cdbd2cSJim Jagielski 486*b1cdbd2cSJim Jagielski my $systemcall = "msicert.exe -d $msidatabase -m $diskid -c $cabfile -h"; 487*b1cdbd2cSJim Jagielski $success = make_systemcall($systemcall, $systemcall); 488*b1cdbd2cSJim Jagielski if ( ! $success ) { $fullsuccess = 0; } 489*b1cdbd2cSJim Jagielski 490*b1cdbd2cSJim Jagielski # size of cabinet file must not change 491*b1cdbd2cSJim Jagielski my $finalfilesize = -s $cabfile; 492*b1cdbd2cSJim Jagielski 493*b1cdbd2cSJim Jagielski if ( $origfilesize != $finalfilesize ) { installer::exiter::exit_program("ERROR: msicert.exe changed size of cabinet file !", "msicert_database"); } 494*b1cdbd2cSJim Jagielski } 495*b1cdbd2cSJim Jagielski 496*b1cdbd2cSJim Jagielski return $fullsuccess; 497*b1cdbd2cSJim Jagielski} 498*b1cdbd2cSJim Jagielski 499*b1cdbd2cSJim Jagielski######################################################## 500*b1cdbd2cSJim Jagielski# Checking if cabinet file was broken by signtool. 501*b1cdbd2cSJim Jagielski######################################################## 502*b1cdbd2cSJim Jagielski 503*b1cdbd2cSJim Jagielskisub cabinet_cosistency_check 504*b1cdbd2cSJim Jagielski{ 505*b1cdbd2cSJim Jagielski my ( $onefile, $followmeinfohash, $filenamehash, $lastsequencehash, $temppath ) = @_; 506*b1cdbd2cSJim Jagielski 507*b1cdbd2cSJim Jagielski my $infoline = "Making consistency check of $onefile\n"; 508*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 509*b1cdbd2cSJim Jagielski my $expandfile = "expand.exe"; # Has to be in the path 510*b1cdbd2cSJim Jagielski 511*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) 512*b1cdbd2cSJim Jagielski { 513*b1cdbd2cSJim Jagielski $expandfile = qx(cygpath -u "$ENV{WINDIR}"/System32/expand.exe); 514*b1cdbd2cSJim Jagielski chomp $expandfile; 515*b1cdbd2cSJim Jagielski } 516*b1cdbd2cSJim Jagielski 517*b1cdbd2cSJim Jagielski if ( $filenamehash == 0 ) 518*b1cdbd2cSJim Jagielski { 519*b1cdbd2cSJim Jagielski $infoline = "Warning: Stopping consistency check: Important hash of filenames is empty!\n"; 520*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 521*b1cdbd2cSJim Jagielski } 522*b1cdbd2cSJim Jagielski elsif ( $lastsequencehash == 0 ) 523*b1cdbd2cSJim Jagielski { 524*b1cdbd2cSJim Jagielski $infoline = "Warning: Stopping consistency check; Important hash of last sequences is empty!\n"; 525*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 526*b1cdbd2cSJim Jagielski } 527*b1cdbd2cSJim Jagielski else # both hashes are available 528*b1cdbd2cSJim Jagielski { 529*b1cdbd2cSJim Jagielski # $onefile contains only the name of the cabinet file without path 530*b1cdbd2cSJim Jagielski my $sequence = $lastsequencehash->{$onefile}; 531*b1cdbd2cSJim Jagielski my $lastfile = $filenamehash->{$sequence}; 532*b1cdbd2cSJim Jagielski $infoline = "Check of $onefile: Sequence: $sequence is file: $lastfile\n"; 533*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 534*b1cdbd2cSJim Jagielski 535*b1cdbd2cSJim Jagielski # Therefore the file $lastfile need to be binary compared. 536*b1cdbd2cSJim Jagielski # It has to be expanded from the cabinet file 537*b1cdbd2cSJim Jagielski # of the original installation set and from the 538*b1cdbd2cSJim Jagielski # newly signed cabinet file. 539*b1cdbd2cSJim Jagielski 540*b1cdbd2cSJim Jagielski # How about cabinet files extracted from msi database? 541*b1cdbd2cSJim Jagielski my $finalinstalldir = $followmeinfohash->{'finalinstalldir'}; 542*b1cdbd2cSJim Jagielski 543*b1cdbd2cSJim Jagielski $finalinstalldir =~ s/\\\s*$//; 544*b1cdbd2cSJim Jagielski $finalinstalldir =~ s/\/\s*$//; 545*b1cdbd2cSJim Jagielski my $sourcecabfile = $finalinstalldir . $installer::globals::separator . $onefile; 546*b1cdbd2cSJim Jagielski my $currentpath = cwd(); 547*b1cdbd2cSJim Jagielski my $destcabfile = $currentpath . $installer::globals::separator . $onefile; 548*b1cdbd2cSJim Jagielski # my $destcabfile = $onefile; 549*b1cdbd2cSJim Jagielski 550*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) 551*b1cdbd2cSJim Jagielski { 552*b1cdbd2cSJim Jagielski chomp( $destcabfile = qx{cygpath -w "$destcabfile"} ); 553*b1cdbd2cSJim Jagielski $destcabfile =~ s/\\/\//g; 554*b1cdbd2cSJim Jagielski } 555*b1cdbd2cSJim Jagielski 556*b1cdbd2cSJim Jagielski if ( ! -f $sourcecabfile ) 557*b1cdbd2cSJim Jagielski { 558*b1cdbd2cSJim Jagielski $infoline = "WARNING: Check of cab file cannot happen, because source cabinet file was not found: $sourcecabfile\n"; 559*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 560*b1cdbd2cSJim Jagielski } 561*b1cdbd2cSJim Jagielski elsif ( ! -f $destcabfile ) 562*b1cdbd2cSJim Jagielski { 563*b1cdbd2cSJim Jagielski $infoline = "WARNING: Check of cab file cannot happen, because destination cabinet file was not found: $sourcecabfile\n"; 564*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 565*b1cdbd2cSJim Jagielski } 566*b1cdbd2cSJim Jagielski else # everything is okay for the check 567*b1cdbd2cSJim Jagielski { 568*b1cdbd2cSJim Jagielski my $diffpath = get_diff_path($temppath); 569*b1cdbd2cSJim Jagielski 570*b1cdbd2cSJim Jagielski my $origdiffpath = $diffpath . $installer::globals::separator . "orig"; 571*b1cdbd2cSJim Jagielski my $newdiffpath = $diffpath . $installer::globals::separator . "new"; 572*b1cdbd2cSJim Jagielski 573*b1cdbd2cSJim Jagielski if ( ! -d $origdiffpath ) { mkdir($origdiffpath); } 574*b1cdbd2cSJim Jagielski if ( ! -d $newdiffpath ) { mkdir($newdiffpath); } 575*b1cdbd2cSJim Jagielski 576*b1cdbd2cSJim Jagielski my $systemcall = "$expandfile $sourcecabfile $origdiffpath -f:$lastfile "; 577*b1cdbd2cSJim Jagielski $infoline = $systemcall . "\n"; 578*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 579*b1cdbd2cSJim Jagielski 580*b1cdbd2cSJim Jagielski my $success = make_systemcall($systemcall, $systemcall); 581*b1cdbd2cSJim Jagielski if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not successfully execute: $systemcall !", "cabinet_cosistency_check"); } 582*b1cdbd2cSJim Jagielski 583*b1cdbd2cSJim Jagielski $systemcall = "$expandfile $destcabfile $newdiffpath -f:$lastfile "; 584*b1cdbd2cSJim Jagielski $infoline = $systemcall . "\n"; 585*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 586*b1cdbd2cSJim Jagielski 587*b1cdbd2cSJim Jagielski $success = make_systemcall($systemcall, $systemcall); 588*b1cdbd2cSJim Jagielski if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not successfully execute: $systemcall !", "cabinet_cosistency_check"); } 589*b1cdbd2cSJim Jagielski 590*b1cdbd2cSJim Jagielski # and finally the two files can be diffed. 591*b1cdbd2cSJim Jagielski my $origfile = $origdiffpath . $installer::globals::separator . $lastfile; 592*b1cdbd2cSJim Jagielski my $newfile = $newdiffpath . $installer::globals::separator . $lastfile; 593*b1cdbd2cSJim Jagielski 594*b1cdbd2cSJim Jagielski if ( ! -f $origfile ) { installer::exiter::exit_program("ERROR: Unpacked original file not found: $origfile !", "cabinet_cosistency_check"); } 595*b1cdbd2cSJim Jagielski if ( ! -f $newfile ) { installer::exiter::exit_program("ERROR: Unpacked new file not found: $newfile !", "cabinet_cosistency_check"); } 596*b1cdbd2cSJim Jagielski 597*b1cdbd2cSJim Jagielski my $origsize = -s $origfile; 598*b1cdbd2cSJim Jagielski my $newsize = -s $newfile; 599*b1cdbd2cSJim Jagielski 600*b1cdbd2cSJim Jagielski if ( $origsize != $newsize ) # This shows an error! 601*b1cdbd2cSJim Jagielski { 602*b1cdbd2cSJim Jagielski $infoline = "ERROR: Different filesize after signtool.exe was used. Original: $origsize Bytes, new: $newsize. File: $lastfile\n"; 603*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 604*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: The cabinet file $destcabfile is broken after signtool.exe signed this file !", "cabinet_cosistency_check"); 605*b1cdbd2cSJim Jagielski } 606*b1cdbd2cSJim Jagielski else 607*b1cdbd2cSJim Jagielski { 608*b1cdbd2cSJim Jagielski $infoline = "Same size of last file in cabinet file after usage of signtool.exe: $newsize (File: $lastfile)\n"; 609*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 610*b1cdbd2cSJim Jagielski 611*b1cdbd2cSJim Jagielski # Also making a binary diff? 612*b1cdbd2cSJim Jagielski 613*b1cdbd2cSJim Jagielski my $difffile = "diff.exe"; # has to be in the path 614*b1cdbd2cSJim Jagielski # $systemcall = "$difffile $sourcecabfile $destcabfile"; # Test for differences 615*b1cdbd2cSJim Jagielski $systemcall = "$difffile $origfile $newfile"; 616*b1cdbd2cSJim Jagielski $infoline = $systemcall . "\n"; 617*b1cdbd2cSJim Jagielski $returnvalue = make_systemcall($systemcall, $systemcall); 618*b1cdbd2cSJim Jagielski 619*b1cdbd2cSJim Jagielski my $success = $?; 620*b1cdbd2cSJim Jagielski 621*b1cdbd2cSJim Jagielski if ( $success == 0 ) 622*b1cdbd2cSJim Jagielski { 623*b1cdbd2cSJim Jagielski $infoline = "Last files are identical after signing cabinet file (File: $lastfile)\n"; 624*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 625*b1cdbd2cSJim Jagielski } 626*b1cdbd2cSJim Jagielski elsif ( $success == 1 ) 627*b1cdbd2cSJim Jagielski { 628*b1cdbd2cSJim Jagielski $infoline = "ERROR: Last files are different after signing cabinet file (File: $lastfile)\n"; 629*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 630*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Last files are different after signing cabinet file (File: $lastfile)!", "cabinet_cosistency_check"); 631*b1cdbd2cSJim Jagielski } 632*b1cdbd2cSJim Jagielski else 633*b1cdbd2cSJim Jagielski { 634*b1cdbd2cSJim Jagielski $infoline = "ERROR: Problem occured calling diff.exe (File: $lastfile)\n"; 635*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 636*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Problem occured calling diff.exe (File: $lastfile) !", "cabinet_cosistency_check"); 637*b1cdbd2cSJim Jagielski } 638*b1cdbd2cSJim Jagielski } 639*b1cdbd2cSJim Jagielski } 640*b1cdbd2cSJim Jagielski } 641*b1cdbd2cSJim Jagielski 642*b1cdbd2cSJim Jagielski} 643*b1cdbd2cSJim Jagielski 644*b1cdbd2cSJim Jagielski######################################################## 645*b1cdbd2cSJim Jagielski# Signing a list of files 646*b1cdbd2cSJim Jagielski######################################################## 647*b1cdbd2cSJim Jagielski 648*b1cdbd2cSJim Jagielskisub sign_files 649*b1cdbd2cSJim Jagielski{ 650*b1cdbd2cSJim Jagielski my ( $followmeinfohash, $allfiles, $pw, $cabinternal, $filenamehash, $lastsequencehash, $temppath ) = @_; 651*b1cdbd2cSJim Jagielski 652*b1cdbd2cSJim Jagielski my $infoline = ""; 653*b1cdbd2cSJim Jagielski my $fullsuccess = 1; 654*b1cdbd2cSJim Jagielski my $maxcounter = 3; 655*b1cdbd2cSJim Jagielski 656*b1cdbd2cSJim Jagielski my $productname = ""; 657*b1cdbd2cSJim Jagielski if ( $followmeinfohash->{'allvariableshash'}->{'PRODUCTNAME'} ) { $productname = "/d " . "\"$followmeinfohash->{'allvariableshash'}->{'PRODUCTNAME'}\""; } 658*b1cdbd2cSJim Jagielski my $url = "/du " . "\"http://www.openoffice.org\""; 659*b1cdbd2cSJim Jagielski my $timestampurl = "http://timestamp.verisign.com/scripts/timestamp.dll"; 660*b1cdbd2cSJim Jagielski 661*b1cdbd2cSJim Jagielski my $pfxfilepath = $installer::globals::pfxfile; 662*b1cdbd2cSJim Jagielski 663*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 664*b1cdbd2cSJim Jagielski { 665*b1cdbd2cSJim Jagielski $pfxfilepath = qx{cygpath -w "$pfxfilepath"}; 666*b1cdbd2cSJim Jagielski $pfxfilepath =~ s/\\/\\\\/g; 667*b1cdbd2cSJim Jagielski $pfxfilepath =~ s/\s*$//g; 668*b1cdbd2cSJim Jagielski } 669*b1cdbd2cSJim Jagielski 670*b1cdbd2cSJim Jagielski foreach my $onefile ( reverse sort keys %{$allfiles} ) 671*b1cdbd2cSJim Jagielski { 672*b1cdbd2cSJim Jagielski if ( already_certified($onefile) ) 673*b1cdbd2cSJim Jagielski { 674*b1cdbd2cSJim Jagielski $infoline = "Already certified: Skipping file $onefile\n"; 675*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 676*b1cdbd2cSJim Jagielski next; 677*b1cdbd2cSJim Jagielski } 678*b1cdbd2cSJim Jagielski 679*b1cdbd2cSJim Jagielski my $counter = 1; 680*b1cdbd2cSJim Jagielski my $success = 0; 681*b1cdbd2cSJim Jagielski 682*b1cdbd2cSJim Jagielski while (( $counter <= $maxcounter ) && ( ! $success )) 683*b1cdbd2cSJim Jagielski { 684*b1cdbd2cSJim Jagielski if ( $counter > 1 ) 685*b1cdbd2cSJim Jagielski { 686*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("\n"); 687*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("\n"); 688*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... repeating file %s ...\n", $onefile); 689*b1cdbd2cSJim Jagielski } 690*b1cdbd2cSJim Jagielski if ( $cabinternal ) 691*b1cdbd2cSJim Jagielski { 692*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" Signing: %s\n", $onefile); 693*b1cdbd2cSJim Jagielski } 694*b1cdbd2cSJim Jagielski my $systemcall = "signtool.exe sign /f \"$pfxfilepath\" /p $pw $productname $url /t \"$timestampurl\" \"$onefile\""; 695*b1cdbd2cSJim Jagielski my $displaysystemcall = "signtool.exe sign /f \"$pfxfilepath\" /p ***** $productname $url /t \"$timestampurl\" \"$onefile\""; 696*b1cdbd2cSJim Jagielski $success = make_systemcall_with_warning($systemcall, $displaysystemcall); 697*b1cdbd2cSJim Jagielski $counter++; 698*b1cdbd2cSJim Jagielski } 699*b1cdbd2cSJim Jagielski 700*b1cdbd2cSJim Jagielski # Special check for cabinet files, that sometimes get damaged by signtool.exe 701*b1cdbd2cSJim Jagielski if (( $success ) && ( $onefile =~ /\.cab\s*$/ ) && ( ! $cabinternal )) 702*b1cdbd2cSJim Jagielski { 703*b1cdbd2cSJim Jagielski cabinet_cosistency_check($onefile, $followmeinfohash, $filenamehash, $lastsequencehash, $temppath); 704*b1cdbd2cSJim Jagielski } 705*b1cdbd2cSJim Jagielski 706*b1cdbd2cSJim Jagielski if ( ! $success ) 707*b1cdbd2cSJim Jagielski { 708*b1cdbd2cSJim Jagielski $fullsuccess = 0; 709*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Could not sign file: $onefile!", "sign_files"); 710*b1cdbd2cSJim Jagielski } 711*b1cdbd2cSJim Jagielski } 712*b1cdbd2cSJim Jagielski 713*b1cdbd2cSJim Jagielski return $fullsuccess; 714*b1cdbd2cSJim Jagielski} 715*b1cdbd2cSJim Jagielski 716*b1cdbd2cSJim Jagielski########################################################################## 717*b1cdbd2cSJim Jagielski# Lines in ddf files must not contain more than 256 characters 718*b1cdbd2cSJim Jagielski########################################################################## 719*b1cdbd2cSJim Jagielski 720*b1cdbd2cSJim Jagielskisub check_ddf_file 721*b1cdbd2cSJim Jagielski{ 722*b1cdbd2cSJim Jagielski my ( $ddffile, $ddffilename ) = @_; 723*b1cdbd2cSJim Jagielski 724*b1cdbd2cSJim Jagielski my $maxlength = 0; 725*b1cdbd2cSJim Jagielski my $maxline = 0; 726*b1cdbd2cSJim Jagielski my $linelength = 0; 727*b1cdbd2cSJim Jagielski my $linenumber = 0; 728*b1cdbd2cSJim Jagielski 729*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$ddffile}; $i++ ) 730*b1cdbd2cSJim Jagielski { 731*b1cdbd2cSJim Jagielski my $oneline = ${$ddffile}[$i]; 732*b1cdbd2cSJim Jagielski 733*b1cdbd2cSJim Jagielski $linelength = length($oneline); 734*b1cdbd2cSJim Jagielski $linenumber = $i + 1; 735*b1cdbd2cSJim Jagielski 736*b1cdbd2cSJim Jagielski if ( $linelength > 256 ) 737*b1cdbd2cSJim Jagielski { 738*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR \"$ddffilename\" line $linenumber: Lines in ddf files must not contain more than 256 characters!", "check_ddf_file"); 739*b1cdbd2cSJim Jagielski } 740*b1cdbd2cSJim Jagielski 741*b1cdbd2cSJim Jagielski if ( $linelength > $maxlength ) 742*b1cdbd2cSJim Jagielski { 743*b1cdbd2cSJim Jagielski $maxlength = $linelength; 744*b1cdbd2cSJim Jagielski $maxline = $linenumber; 745*b1cdbd2cSJim Jagielski } 746*b1cdbd2cSJim Jagielski } 747*b1cdbd2cSJim Jagielski 748*b1cdbd2cSJim Jagielski my $infoline = "Check of ddf file \"$ddffilename\": Maximum length \"$maxlength\" in line \"$maxline\" (allowed line length: 256 characters)\n"; 749*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 750*b1cdbd2cSJim Jagielski} 751*b1cdbd2cSJim Jagielski 752*b1cdbd2cSJim Jagielski################################################################# 753*b1cdbd2cSJim Jagielski# Setting the path, where the cab files are unpacked. 754*b1cdbd2cSJim Jagielski################################################################# 755*b1cdbd2cSJim Jagielski 756*b1cdbd2cSJim Jagielskisub get_cab_path 757*b1cdbd2cSJim Jagielski{ 758*b1cdbd2cSJim Jagielski my ($temppath) = @_; 759*b1cdbd2cSJim Jagielski 760*b1cdbd2cSJim Jagielski my $cabpath = "cabs_" . $$; 761*b1cdbd2cSJim Jagielski $cabpath = $temppath . $installer::globals::separator . $cabpath; 762*b1cdbd2cSJim Jagielski if ( ! -d $cabpath ) { installer::systemactions::create_directory($cabpath); } 763*b1cdbd2cSJim Jagielski 764*b1cdbd2cSJim Jagielski return $cabpath; 765*b1cdbd2cSJim Jagielski} 766*b1cdbd2cSJim Jagielski 767*b1cdbd2cSJim Jagielski################################################################# 768*b1cdbd2cSJim Jagielski# Setting the path, where the diff can happen. 769*b1cdbd2cSJim Jagielski################################################################# 770*b1cdbd2cSJim Jagielski 771*b1cdbd2cSJim Jagielskisub get_diff_path 772*b1cdbd2cSJim Jagielski{ 773*b1cdbd2cSJim Jagielski my ($temppath) = @_; 774*b1cdbd2cSJim Jagielski 775*b1cdbd2cSJim Jagielski my $diffpath = "diff_" . $$; 776*b1cdbd2cSJim Jagielski $diffpath = $temppath . $installer::globals::separator . $diffpath; 777*b1cdbd2cSJim Jagielski if ( ! -d $diffpath ) { installer::systemactions::create_directory($diffpath); } 778*b1cdbd2cSJim Jagielski 779*b1cdbd2cSJim Jagielski return $diffpath; 780*b1cdbd2cSJim Jagielski} 781*b1cdbd2cSJim Jagielski 782*b1cdbd2cSJim Jagielski################################################################# 783*b1cdbd2cSJim Jagielski# Exclude all cab files from the msi database. 784*b1cdbd2cSJim Jagielski################################################################# 785*b1cdbd2cSJim Jagielski 786*b1cdbd2cSJim Jagielskisub extract_cabs_from_database 787*b1cdbd2cSJim Jagielski{ 788*b1cdbd2cSJim Jagielski my ($msidatabase, $allcabfiles) = @_; 789*b1cdbd2cSJim Jagielski 790*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("Extracting cabs from msi database"); 791*b1cdbd2cSJim Jagielski 792*b1cdbd2cSJim Jagielski my $infoline = ""; 793*b1cdbd2cSJim Jagielski my $fullsuccess = 1; 794*b1cdbd2cSJim Jagielski my $msidb = "msidb.exe"; # Has to be in the path 795*b1cdbd2cSJim Jagielski 796*b1cdbd2cSJim Jagielski # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 797*b1cdbd2cSJim Jagielski $msidatabase =~ s/\//\\\\/g; 798*b1cdbd2cSJim Jagielski 799*b1cdbd2cSJim Jagielski foreach my $onefile ( keys %{$allcabfiles} ) 800*b1cdbd2cSJim Jagielski { 801*b1cdbd2cSJim Jagielski my $systemcall = $msidb . " -d " . $msidatabase . " -x " . $onefile; 802*b1cdbd2cSJim Jagielski my $success = make_systemcall($systemcall, $systemcall); 803*b1cdbd2cSJim Jagielski if ( ! $success ) { $fullsuccess = 0; } 804*b1cdbd2cSJim Jagielski 805*b1cdbd2cSJim Jagielski # and removing the stream from the database 806*b1cdbd2cSJim Jagielski $systemcall = $msidb . " -d " . $msidatabase . " -k " . $onefile; 807*b1cdbd2cSJim Jagielski $success = make_systemcall($systemcall, $systemcall); 808*b1cdbd2cSJim Jagielski if ( ! $success ) { $fullsuccess = 0; } 809*b1cdbd2cSJim Jagielski } 810*b1cdbd2cSJim Jagielski 811*b1cdbd2cSJim Jagielski return $fullsuccess; 812*b1cdbd2cSJim Jagielski} 813*b1cdbd2cSJim Jagielski 814*b1cdbd2cSJim Jagielski################################################################# 815*b1cdbd2cSJim Jagielski# Include cab files into the msi database. 816*b1cdbd2cSJim Jagielski################################################################# 817*b1cdbd2cSJim Jagielski 818*b1cdbd2cSJim Jagielskisub include_cabs_into_database 819*b1cdbd2cSJim Jagielski{ 820*b1cdbd2cSJim Jagielski my ($msidatabase, $allcabfiles) = @_; 821*b1cdbd2cSJim Jagielski 822*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("Including cabs into msi database"); 823*b1cdbd2cSJim Jagielski 824*b1cdbd2cSJim Jagielski my $infoline = ""; 825*b1cdbd2cSJim Jagielski my $fullsuccess = 1; 826*b1cdbd2cSJim Jagielski my $msidb = "msidb.exe"; # Has to be in the path 827*b1cdbd2cSJim Jagielski 828*b1cdbd2cSJim Jagielski # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 829*b1cdbd2cSJim Jagielski $msidatabase =~ s/\//\\\\/g; 830*b1cdbd2cSJim Jagielski 831*b1cdbd2cSJim Jagielski foreach my $onefile ( keys %{$allcabfiles} ) 832*b1cdbd2cSJim Jagielski { 833*b1cdbd2cSJim Jagielski my $systemcall = $msidb . " -d " . $msidatabase . " -a " . $onefile; 834*b1cdbd2cSJim Jagielski my $success = make_systemcall($systemcall, $systemcall); 835*b1cdbd2cSJim Jagielski if ( ! $success ) { $fullsuccess = 0; } 836*b1cdbd2cSJim Jagielski } 837*b1cdbd2cSJim Jagielski 838*b1cdbd2cSJim Jagielski return $fullsuccess; 839*b1cdbd2cSJim Jagielski} 840*b1cdbd2cSJim Jagielski 841*b1cdbd2cSJim Jagielski######################################################## 842*b1cdbd2cSJim Jagielski# Reading the order of the files inside the 843*b1cdbd2cSJim Jagielski# cabinet files. 844*b1cdbd2cSJim Jagielski######################################################## 845*b1cdbd2cSJim Jagielski 846*b1cdbd2cSJim Jagielskisub read_cab_file 847*b1cdbd2cSJim Jagielski{ 848*b1cdbd2cSJim Jagielski my ($cabfilename) = @_; 849*b1cdbd2cSJim Jagielski 850*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("\n"); 851*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... reading cabinet file %s ...\n", $cabfilename); 852*b1cdbd2cSJim Jagielski my $infoline = "Reading cabinet file $cabfilename\n"; 853*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 854*b1cdbd2cSJim Jagielski 855*b1cdbd2cSJim Jagielski my $systemcall = "cabarc.exe" . " L " . $cabfilename; 856*b1cdbd2cSJim Jagielski push(@logfile, "$systemcall\n"); 857*b1cdbd2cSJim Jagielski 858*b1cdbd2cSJim Jagielski my ($success, $fileorder) = execute_open_system_call($systemcall); 859*b1cdbd2cSJim Jagielski 860*b1cdbd2cSJim Jagielski my @allfiles = (); 861*b1cdbd2cSJim Jagielski 862*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$fileorder}; $i++ ) 863*b1cdbd2cSJim Jagielski { 864*b1cdbd2cSJim Jagielski my $line = ${$fileorder}[$i]; 865*b1cdbd2cSJim Jagielski if ( $line =~ /^\s*(.*?)\s+\d+\s+\d+\/\d+\/\d+\s+\d+\:\d+\:\d+\s+[\w-]+\s*$/ ) 866*b1cdbd2cSJim Jagielski { 867*b1cdbd2cSJim Jagielski my $filename = $1; 868*b1cdbd2cSJim Jagielski push(@allfiles, $filename); 869*b1cdbd2cSJim Jagielski } 870*b1cdbd2cSJim Jagielski } 871*b1cdbd2cSJim Jagielski 872*b1cdbd2cSJim Jagielski return \@allfiles; 873*b1cdbd2cSJim Jagielski} 874*b1cdbd2cSJim Jagielski 875*b1cdbd2cSJim Jagielski######################################################## 876*b1cdbd2cSJim Jagielski# Unpacking a cabinet file. 877*b1cdbd2cSJim Jagielski######################################################## 878*b1cdbd2cSJim Jagielski 879*b1cdbd2cSJim Jagielskisub unpack_cab_file 880*b1cdbd2cSJim Jagielski{ 881*b1cdbd2cSJim Jagielski my ($cabfilename, $temppath) = @_; 882*b1cdbd2cSJim Jagielski 883*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("\n"); 884*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... unpacking cabinet file %s ...\n", $cabfilename); 885*b1cdbd2cSJim Jagielski my $infoline = "Unpacking cabinet file $cabfilename\n"; 886*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 887*b1cdbd2cSJim Jagielski 888*b1cdbd2cSJim Jagielski my $dirname = $cabfilename; 889*b1cdbd2cSJim Jagielski $dirname =~ s/\.cab\s*$//; 890*b1cdbd2cSJim Jagielski my $workingpath = $temppath . $installer::globals::separator . "unpack_". $dirname . "_" . $$; 891*b1cdbd2cSJim Jagielski if ( ! -d $workingpath ) { installer::systemactions::create_directory($workingpath); } 892*b1cdbd2cSJim Jagielski 893*b1cdbd2cSJim Jagielski # changing into unpack directory 894*b1cdbd2cSJim Jagielski my $from = cwd(); 895*b1cdbd2cSJim Jagielski chdir($workingpath); 896*b1cdbd2cSJim Jagielski 897*b1cdbd2cSJim Jagielski my $fullcabfilename = $from . $installer::globals::separator . $cabfilename; 898*b1cdbd2cSJim Jagielski 899*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 900*b1cdbd2cSJim Jagielski { 901*b1cdbd2cSJim Jagielski $fullcabfilename = qx{cygpath -w "$fullcabfilename"}; 902*b1cdbd2cSJim Jagielski $fullcabfilename =~ s/\\/\\\\/g; 903*b1cdbd2cSJim Jagielski $fullcabfilename =~ s/\s*$//g; 904*b1cdbd2cSJim Jagielski } 905*b1cdbd2cSJim Jagielski 906*b1cdbd2cSJim Jagielski my $systemcall = "cabarc.exe" . " -p X " . $fullcabfilename; 907*b1cdbd2cSJim Jagielski $success = make_systemcall($systemcall, $systemcall); 908*b1cdbd2cSJim Jagielski if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not unpack cabinet file: $fullcabfilename!", "unpack_cab_file"); } 909*b1cdbd2cSJim Jagielski 910*b1cdbd2cSJim Jagielski # returning to directory 911*b1cdbd2cSJim Jagielski chdir($from); 912*b1cdbd2cSJim Jagielski 913*b1cdbd2cSJim Jagielski return $workingpath; 914*b1cdbd2cSJim Jagielski} 915*b1cdbd2cSJim Jagielski 916*b1cdbd2cSJim Jagielski######################################################## 917*b1cdbd2cSJim Jagielski# Returning the header of a ddf file. 918*b1cdbd2cSJim Jagielski######################################################## 919*b1cdbd2cSJim Jagielski 920*b1cdbd2cSJim Jagielskisub get_ddf_file_header 921*b1cdbd2cSJim Jagielski{ 922*b1cdbd2cSJim Jagielski my ($ddffileref, $cabinetfile, $installdir) = @_; 923*b1cdbd2cSJim Jagielski 924*b1cdbd2cSJim Jagielski my $oneline; 925*b1cdbd2cSJim Jagielski my $compressionlevel = 2; 926*b1cdbd2cSJim Jagielski 927*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 928*b1cdbd2cSJim Jagielski { 929*b1cdbd2cSJim Jagielski $installdir = qx{cygpath -w "$installdir"}; 930*b1cdbd2cSJim Jagielski $installdir =~ s/\s*$//g; 931*b1cdbd2cSJim Jagielski } 932*b1cdbd2cSJim Jagielski 933*b1cdbd2cSJim Jagielski $oneline = ".Set CabinetName1=" . $cabinetfile . "\n"; 934*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 935*b1cdbd2cSJim Jagielski $oneline = ".Set ReservePerCabinetSize=128\n"; # This reserves space for a digital signature. 936*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 937*b1cdbd2cSJim Jagielski $oneline = ".Set MaxDiskSize=2147483648\n"; # This allows the .cab file to get a size of 2 GB. 938*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 939*b1cdbd2cSJim Jagielski $oneline = ".Set CompressionType=LZX\n"; 940*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 941*b1cdbd2cSJim Jagielski $oneline = ".Set Compress=ON\n"; 942*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 943*b1cdbd2cSJim Jagielski $oneline = ".Set CompressionLevel=$compressionlevel\n"; 944*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 945*b1cdbd2cSJim Jagielski $oneline = ".Set Cabinet=ON\n"; 946*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 947*b1cdbd2cSJim Jagielski $oneline = ".Set DiskDirectoryTemplate=" . $installdir . "\n"; 948*b1cdbd2cSJim Jagielski push(@{$ddffileref} ,$oneline); 949*b1cdbd2cSJim Jagielski} 950*b1cdbd2cSJim Jagielski 951*b1cdbd2cSJim Jagielski######################################################## 952*b1cdbd2cSJim Jagielski# Writing content into ddf file. 953*b1cdbd2cSJim Jagielski######################################################## 954*b1cdbd2cSJim Jagielski 955*b1cdbd2cSJim Jagielskisub put_all_files_into_ddffile 956*b1cdbd2cSJim Jagielski{ 957*b1cdbd2cSJim Jagielski my ($ddffile, $allfiles, $workingpath) = @_; 958*b1cdbd2cSJim Jagielski 959*b1cdbd2cSJim Jagielski $workingpath =~ s/\//\\/g; 960*b1cdbd2cSJim Jagielski 961*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$allfiles}; $i++ ) 962*b1cdbd2cSJim Jagielski { 963*b1cdbd2cSJim Jagielski my $filename = ${$allfiles}[$i]; 964*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) { $filename =~ s/\//\\/g; } # Backslash for Cygwin! 965*b1cdbd2cSJim Jagielski if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file: $filename!", "put_all_files_into_ddffile"); } 966*b1cdbd2cSJim Jagielski my $infoline = "\"" . $filename . "\"" . " " . ${$allfiles}[$i] . "\n"; 967*b1cdbd2cSJim Jagielski push( @{$ddffile}, $infoline); 968*b1cdbd2cSJim Jagielski } 969*b1cdbd2cSJim Jagielski} 970*b1cdbd2cSJim Jagielski 971*b1cdbd2cSJim Jagielski######################################################## 972*b1cdbd2cSJim Jagielski# Packing a cabinet file. 973*b1cdbd2cSJim Jagielski######################################################## 974*b1cdbd2cSJim Jagielski 975*b1cdbd2cSJim Jagielskisub do_pack_cab_file 976*b1cdbd2cSJim Jagielski{ 977*b1cdbd2cSJim Jagielski my ($cabfilename, $allfiles, $workingpath, $temppath) = @_; 978*b1cdbd2cSJim Jagielski 979*b1cdbd2cSJim Jagielski $installer::logger::Info->print("\n"); 980*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... packing cabinet file %s ...\n", $cabfilename); 981*b1cdbd2cSJim Jagielski my $infoline = "Packing cabinet file $cabfilename\n"; 982*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 983*b1cdbd2cSJim Jagielski 984*b1cdbd2cSJim Jagielski if ( -f $cabfilename ) { unlink($cabfilename); } # removing cab file 985*b1cdbd2cSJim Jagielski if ( -f $cabfilename ) { installer::exiter::exit_program("ERROR: Failed to remove file: $cabfilename!", "do_pack_cab_file"); } 986*b1cdbd2cSJim Jagielski 987*b1cdbd2cSJim Jagielski # generate ddf file for makecab.exe 988*b1cdbd2cSJim Jagielski my @ddffile = (); 989*b1cdbd2cSJim Jagielski 990*b1cdbd2cSJim Jagielski my $dirname = $cabfilename; 991*b1cdbd2cSJim Jagielski $dirname =~ s/\.cab\s*$//; 992*b1cdbd2cSJim Jagielski my $ddfpath = $temppath . $installer::globals::separator . "ddf_". $dirname . "_" . $$; 993*b1cdbd2cSJim Jagielski 994*b1cdbd2cSJim Jagielski my $ddffilename = $cabfilename; 995*b1cdbd2cSJim Jagielski $ddffilename =~ s/.cab/.ddf/; 996*b1cdbd2cSJim Jagielski $ddffilename = $ddfpath . $installer::globals::separator . $ddffilename; 997*b1cdbd2cSJim Jagielski 998*b1cdbd2cSJim Jagielski if ( ! -d $ddfpath ) { installer::systemactions::create_directory($ddfpath); } 999*b1cdbd2cSJim Jagielski 1000*b1cdbd2cSJim Jagielski my $from = cwd(); 1001*b1cdbd2cSJim Jagielski 1002*b1cdbd2cSJim Jagielski chdir($workingpath); # changing into the directory with the unpacked files 1003*b1cdbd2cSJim Jagielski 1004*b1cdbd2cSJim Jagielski get_ddf_file_header(\@ddffile, $cabfilename, $from); 1005*b1cdbd2cSJim Jagielski put_all_files_into_ddffile(\@ddffile, $allfiles, $workingpath); 1006*b1cdbd2cSJim Jagielski # lines in ddf files must not be longer than 256 characters 1007*b1cdbd2cSJim Jagielski check_ddf_file(\@ddffile, $ddffilename); 1008*b1cdbd2cSJim Jagielski 1009*b1cdbd2cSJim Jagielski installer::files::save_file($ddffilename, \@ddffile); 1010*b1cdbd2cSJim Jagielski 1011*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 1012*b1cdbd2cSJim Jagielski { 1013*b1cdbd2cSJim Jagielski $ddffilename = qx{cygpath -w "$ddffilename"}; 1014*b1cdbd2cSJim Jagielski $ddffilename =~ s/\\/\\\\/g; 1015*b1cdbd2cSJim Jagielski $ddffilename =~ s/\s*$//g; 1016*b1cdbd2cSJim Jagielski } 1017*b1cdbd2cSJim Jagielski 1018*b1cdbd2cSJim Jagielski my $systemcall = "makecab.exe /V1 /F " . $ddffilename; 1019*b1cdbd2cSJim Jagielski my $success = make_systemcall($systemcall, $systemcall); 1020*b1cdbd2cSJim Jagielski if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not pack cabinet file!", "do_pack_cab_file"); } 1021*b1cdbd2cSJim Jagielski 1022*b1cdbd2cSJim Jagielski chdir($from); 1023*b1cdbd2cSJim Jagielski 1024*b1cdbd2cSJim Jagielski return ($success); 1025*b1cdbd2cSJim Jagielski} 1026*b1cdbd2cSJim Jagielski 1027*b1cdbd2cSJim Jagielski######################################################## 1028*b1cdbd2cSJim Jagielski# Extraction the file extension from a file 1029*b1cdbd2cSJim Jagielski######################################################## 1030*b1cdbd2cSJim Jagielski 1031*b1cdbd2cSJim Jagielskisub get_extension 1032*b1cdbd2cSJim Jagielski{ 1033*b1cdbd2cSJim Jagielski my ( $file ) = @_; 1034*b1cdbd2cSJim Jagielski 1035*b1cdbd2cSJim Jagielski my $extension = ""; 1036*b1cdbd2cSJim Jagielski 1037*b1cdbd2cSJim Jagielski if ( $file =~ /^\s*(.*)\.(\w+?)\s*$/ ) { $extension = $2; } 1038*b1cdbd2cSJim Jagielski 1039*b1cdbd2cSJim Jagielski return $extension; 1040*b1cdbd2cSJim Jagielski} 1041*b1cdbd2cSJim Jagielski 1042*b1cdbd2cSJim Jagielski######################################################## 1043*b1cdbd2cSJim Jagielski# Checking, if a file already contains a certificate. 1044*b1cdbd2cSJim Jagielski# This must not be overwritten. 1045*b1cdbd2cSJim Jagielski######################################################## 1046*b1cdbd2cSJim Jagielski 1047*b1cdbd2cSJim Jagielskisub already_certified 1048*b1cdbd2cSJim Jagielski{ 1049*b1cdbd2cSJim Jagielski my ( $filename ) = @_; 1050*b1cdbd2cSJim Jagielski 1051*b1cdbd2cSJim Jagielski my $success = 1; 1052*b1cdbd2cSJim Jagielski my $is_certified = 0; 1053*b1cdbd2cSJim Jagielski 1054*b1cdbd2cSJim Jagielski my $systemcall = "signtool.exe verify /q /pa \"$filename\""; 1055*b1cdbd2cSJim Jagielski my $returnvalue = system($systemcall); 1056*b1cdbd2cSJim Jagielski 1057*b1cdbd2cSJim Jagielski if ( $returnvalue ) { $success = 0; } 1058*b1cdbd2cSJim Jagielski 1059*b1cdbd2cSJim Jagielski # my $success = make_systemcall($systemcall, $systemcall); 1060*b1cdbd2cSJim Jagielski 1061*b1cdbd2cSJim Jagielski if ( $success ) 1062*b1cdbd2cSJim Jagielski { 1063*b1cdbd2cSJim Jagielski $is_certified = 1; 1064*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... already certified -> skipping %s ...\n", $filename); 1065*b1cdbd2cSJim Jagielski } 1066*b1cdbd2cSJim Jagielski 1067*b1cdbd2cSJim Jagielski return $is_certified; 1068*b1cdbd2cSJim Jagielski} 1069*b1cdbd2cSJim Jagielski 1070*b1cdbd2cSJim Jagielski######################################################## 1071*b1cdbd2cSJim Jagielski# Signing the files, that are included into 1072*b1cdbd2cSJim Jagielski# cabinet files. 1073*b1cdbd2cSJim Jagielski######################################################## 1074*b1cdbd2cSJim Jagielski 1075*b1cdbd2cSJim Jagielskisub sign_files_in_cabinet_files 1076*b1cdbd2cSJim Jagielski{ 1077*b1cdbd2cSJim Jagielski my ( $followmeinfohash, $allcabfiles, $pw, $temppath ) = @_; 1078*b1cdbd2cSJim Jagielski 1079*b1cdbd2cSJim Jagielski my $complete_success = 1; 1080*b1cdbd2cSJim Jagielski my $from = cwd(); 1081*b1cdbd2cSJim Jagielski 1082*b1cdbd2cSJim Jagielski foreach my $cabfilename ( keys %{$allcabfiles} ) 1083*b1cdbd2cSJim Jagielski { 1084*b1cdbd2cSJim Jagielski my $success = 1; 1085*b1cdbd2cSJim Jagielski 1086*b1cdbd2cSJim Jagielski # saving order of files in cab file 1087*b1cdbd2cSJim Jagielski my $fileorder = read_cab_file($cabfilename); 1088*b1cdbd2cSJim Jagielski 1089*b1cdbd2cSJim Jagielski # unpack into $working path 1090*b1cdbd2cSJim Jagielski my $workingpath = unpack_cab_file($cabfilename, $temppath); 1091*b1cdbd2cSJim Jagielski 1092*b1cdbd2cSJim Jagielski chdir($workingpath); 1093*b1cdbd2cSJim Jagielski 1094*b1cdbd2cSJim Jagielski # sign files 1095*b1cdbd2cSJim Jagielski my %allfileshash = (); 1096*b1cdbd2cSJim Jagielski foreach my $onefile ( @{$fileorder} ) 1097*b1cdbd2cSJim Jagielski { 1098*b1cdbd2cSJim Jagielski my $extension = get_extension($onefile); 1099*b1cdbd2cSJim Jagielski if ( exists( $installer::globals::sign_extensions{$extension} ) ) 1100*b1cdbd2cSJim Jagielski { 1101*b1cdbd2cSJim Jagielski $allfileshash{$onefile} = 1; 1102*b1cdbd2cSJim Jagielski } 1103*b1cdbd2cSJim Jagielski } 1104*b1cdbd2cSJim Jagielski $success = sign_files($followmeinfohash, \%allfileshash, $pw, 1, 0, 0, $temppath); 1105*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1106*b1cdbd2cSJim Jagielski 1107*b1cdbd2cSJim Jagielski chdir($from); 1108*b1cdbd2cSJim Jagielski 1109*b1cdbd2cSJim Jagielski # pack into new directory 1110*b1cdbd2cSJim Jagielski do_pack_cab_file($cabfilename, $fileorder, $workingpath, $temppath); 1111*b1cdbd2cSJim Jagielski } 1112*b1cdbd2cSJim Jagielski 1113*b1cdbd2cSJim Jagielski return $complete_success; 1114*b1cdbd2cSJim Jagielski} 1115*b1cdbd2cSJim Jagielski 1116*b1cdbd2cSJim Jagielski######################################################## 1117*b1cdbd2cSJim Jagielski# Comparing the content of two directories. 1118*b1cdbd2cSJim Jagielski# Only filesize is compared. 1119*b1cdbd2cSJim Jagielski######################################################## 1120*b1cdbd2cSJim Jagielski 1121*b1cdbd2cSJim Jagielskisub compare_directories 1122*b1cdbd2cSJim Jagielski{ 1123*b1cdbd2cSJim Jagielski my ( $dir1, $dir2, $files ) = @_; 1124*b1cdbd2cSJim Jagielski 1125*b1cdbd2cSJim Jagielski $dir1 =~ s/\\\s*//; 1126*b1cdbd2cSJim Jagielski $dir2 =~ s/\\\s*//; 1127*b1cdbd2cSJim Jagielski $dir1 =~ s/\/\s*//; 1128*b1cdbd2cSJim Jagielski $dir2 =~ s/\/\s*//; 1129*b1cdbd2cSJim Jagielski 1130*b1cdbd2cSJim Jagielski my $infoline = "Comparing directories: $dir1 and $dir2\n"; 1131*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 1132*b1cdbd2cSJim Jagielski 1133*b1cdbd2cSJim Jagielski foreach my $onefile ( @{$files} ) 1134*b1cdbd2cSJim Jagielski { 1135*b1cdbd2cSJim Jagielski my $file1 = $dir1 . $installer::globals::separator . $onefile; 1136*b1cdbd2cSJim Jagielski my $file2 = $dir2 . $installer::globals::separator . $onefile; 1137*b1cdbd2cSJim Jagielski 1138*b1cdbd2cSJim Jagielski if ( ! -f $file1 ) { installer::exiter::exit_program("ERROR: Missing file : $file1!", "compare_directories"); } 1139*b1cdbd2cSJim Jagielski if ( ! -f $file2 ) { installer::exiter::exit_program("ERROR: Missing file : $file2!", "compare_directories"); } 1140*b1cdbd2cSJim Jagielski 1141*b1cdbd2cSJim Jagielski my $size1 = -s $file1; 1142*b1cdbd2cSJim Jagielski my $size2 = -s $file2; 1143*b1cdbd2cSJim Jagielski 1144*b1cdbd2cSJim Jagielski $infoline = "Comparing files: $file1 ($size1) and $file2 ($size2)\n"; 1145*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 1146*b1cdbd2cSJim Jagielski 1147*b1cdbd2cSJim Jagielski if ( $size1 != $size2 ) 1148*b1cdbd2cSJim Jagielski { 1149*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: File defect after copy (different size) $file1 ($size1 bytes) and $file2 ($size2 bytes)!", "compare_directories"); 1150*b1cdbd2cSJim Jagielski } 1151*b1cdbd2cSJim Jagielski } 1152*b1cdbd2cSJim Jagielski} 1153*b1cdbd2cSJim Jagielski 1154*b1cdbd2cSJim Jagielski######################################################## 1155*b1cdbd2cSJim Jagielski# Signing an existing Windows installation set. 1156*b1cdbd2cSJim Jagielski######################################################## 1157*b1cdbd2cSJim Jagielski 1158*b1cdbd2cSJim Jagielskisub sign_install_set 1159*b1cdbd2cSJim Jagielski{ 1160*b1cdbd2cSJim Jagielski my ($followmeinfohash, $make_copy, $temppath) = @_; 1161*b1cdbd2cSJim Jagielski 1162*b1cdbd2cSJim Jagielski my $installsetpath = $followmeinfohash->{'finalinstalldir'}; 1163*b1cdbd2cSJim Jagielski 1164*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("Start: Signing installation set $installsetpath"); 1165*b1cdbd2cSJim Jagielski 1166*b1cdbd2cSJim Jagielski my $complete_success = 1; 1167*b1cdbd2cSJim Jagielski my $success = 1; 1168*b1cdbd2cSJim Jagielski 1169*b1cdbd2cSJim Jagielski my $infoline = "Signing installation set in $installsetpath\n"; 1170*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 1171*b1cdbd2cSJim Jagielski 1172*b1cdbd2cSJim Jagielski # check required files. 1173*b1cdbd2cSJim Jagielski if ( ! $installer::globals::signfiles_checked ) { check_system_path(); } 1174*b1cdbd2cSJim Jagielski 1175*b1cdbd2cSJim Jagielski # get cerficate information 1176*b1cdbd2cSJim Jagielski my $pw = get_pw($installer::globals::pwfile); 1177*b1cdbd2cSJim Jagielski 1178*b1cdbd2cSJim Jagielski # making a copy of the installation set, if required 1179*b1cdbd2cSJim Jagielski if ( $make_copy ) { $installsetpath = copy_install_set($installsetpath); } 1180*b1cdbd2cSJim Jagielski else { $installsetpath = rename_install_set($installsetpath); } 1181*b1cdbd2cSJim Jagielski 1182*b1cdbd2cSJim Jagielski # collecting all files in the installation set 1183*b1cdbd2cSJim Jagielski my ($allcabfiles, $allfiles, $msidatabase, $contains_external_cabfiles, $contains_msidatabase, $sourcefiles) = analyze_installset_content($installsetpath); 1184*b1cdbd2cSJim Jagielski 1185*b1cdbd2cSJim Jagielski if ( $make_copy ) { compare_directories($installsetpath, $followmeinfohash->{'finalinstalldir'}, $sourcefiles); } 1186*b1cdbd2cSJim Jagielski 1187*b1cdbd2cSJim Jagielski # changing into installation set 1188*b1cdbd2cSJim Jagielski my $from = cwd(); 1189*b1cdbd2cSJim Jagielski my $fullmsidatabase = $installsetpath . $installer::globals::separator . $msidatabase; 1190*b1cdbd2cSJim Jagielski 1191*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 1192*b1cdbd2cSJim Jagielski { 1193*b1cdbd2cSJim Jagielski $fullmsidatabase = qx{cygpath -w "$fullmsidatabase"}; 1194*b1cdbd2cSJim Jagielski $fullmsidatabase =~ s/\\/\\\\/g; 1195*b1cdbd2cSJim Jagielski $fullmsidatabase =~ s/\s*$//g; 1196*b1cdbd2cSJim Jagielski } 1197*b1cdbd2cSJim Jagielski 1198*b1cdbd2cSJim Jagielski chdir($installsetpath); 1199*b1cdbd2cSJim Jagielski 1200*b1cdbd2cSJim Jagielski if ( $contains_msidatabase ) 1201*b1cdbd2cSJim Jagielski { 1202*b1cdbd2cSJim Jagielski # exclude media table from msi database and get all diskids. 1203*b1cdbd2cSJim Jagielski my ( $cabfilehash, $filenamehash, $lastsequencehash ) = collect_diskid_from_media_table($msidatabase, $followmeinfohash->{'languagestring'}); 1204*b1cdbd2cSJim Jagielski 1205*b1cdbd2cSJim Jagielski # Check, if there are internal cab files 1206*b1cdbd2cSJim Jagielski my ( $contains_internal_cabfiles, $all_internal_cab_files) = check_for_internal_cabfiles($cabfilehash); 1207*b1cdbd2cSJim Jagielski 1208*b1cdbd2cSJim Jagielski if ( $contains_internal_cabfiles ) 1209*b1cdbd2cSJim Jagielski { 1210*b1cdbd2cSJim Jagielski my $cabpath = get_cab_path($temppath); 1211*b1cdbd2cSJim Jagielski chdir($cabpath); 1212*b1cdbd2cSJim Jagielski 1213*b1cdbd2cSJim Jagielski # Exclude all cabinet files from database 1214*b1cdbd2cSJim Jagielski $success = extract_cabs_from_database($fullmsidatabase, $all_internal_cab_files); 1215*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1216*b1cdbd2cSJim Jagielski 1217*b1cdbd2cSJim Jagielski if ( $installer::globals::internal_cabinet_signing ) { sign_files_in_cabinet_files($followmeinfohash, $all_internal_cab_files, $pw, $temppath); } 1218*b1cdbd2cSJim Jagielski 1219*b1cdbd2cSJim Jagielski $success = sign_files($followmeinfohash, $all_internal_cab_files, $pw, 0, $filenamehash, $lastsequencehash, $temppath); 1220*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1221*b1cdbd2cSJim Jagielski $success = msicert_database($fullmsidatabase, $all_internal_cab_files, $cabfilehash, 1); 1222*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1223*b1cdbd2cSJim Jagielski 1224*b1cdbd2cSJim Jagielski # Include all cabinet files into database 1225*b1cdbd2cSJim Jagielski $success = include_cabs_into_database($fullmsidatabase, $all_internal_cab_files); 1226*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1227*b1cdbd2cSJim Jagielski chdir($installsetpath); 1228*b1cdbd2cSJim Jagielski } 1229*b1cdbd2cSJim Jagielski 1230*b1cdbd2cSJim Jagielski # Warning: There might be a problem with very big cabinet files 1231*b1cdbd2cSJim Jagielski # signing all external cab files first 1232*b1cdbd2cSJim Jagielski if ( $contains_external_cabfiles ) 1233*b1cdbd2cSJim Jagielski { 1234*b1cdbd2cSJim Jagielski if ( $installer::globals::internal_cabinet_signing ) { sign_files_in_cabinet_files($followmeinfohash, $allcabfiles, $pw, $temppath); } 1235*b1cdbd2cSJim Jagielski 1236*b1cdbd2cSJim Jagielski $success = sign_files($followmeinfohash, $allcabfiles, $pw, 0, $filenamehash, $lastsequencehash, $temppath); 1237*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1238*b1cdbd2cSJim Jagielski $success = msicert_database($msidatabase, $allcabfiles, $cabfilehash, 0); 1239*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1240*b1cdbd2cSJim Jagielski } 1241*b1cdbd2cSJim Jagielski } 1242*b1cdbd2cSJim Jagielski 1243*b1cdbd2cSJim Jagielski # finally all other files can be signed 1244*b1cdbd2cSJim Jagielski $success = sign_files($followmeinfohash, $allfiles, $pw, 0, 0, 0, $temppath); 1245*b1cdbd2cSJim Jagielski if ( ! $success ) { $complete_success = 0; } 1246*b1cdbd2cSJim Jagielski 1247*b1cdbd2cSJim Jagielski # and changing back 1248*b1cdbd2cSJim Jagielski chdir($from); 1249*b1cdbd2cSJim Jagielski 1250*b1cdbd2cSJim Jagielski installer::logger::include_header_into_logfile("End: Signing installation set $installsetpath"); 1251*b1cdbd2cSJim Jagielski 1252*b1cdbd2cSJim Jagielski return ($installsetpath); 1253*b1cdbd2cSJim Jagielski} 1254*b1cdbd2cSJim Jagielski 1255*b1cdbd2cSJim Jagielski1; 1256