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::admin; 25*b1cdbd2cSJim Jagielski 26*b1cdbd2cSJim Jagielskiuse File::Copy; 27*b1cdbd2cSJim Jagielskiuse installer::exiter; 28*b1cdbd2cSJim Jagielskiuse installer::files; 29*b1cdbd2cSJim Jagielskiuse installer::globals; 30*b1cdbd2cSJim Jagielskiuse installer::pathanalyzer; 31*b1cdbd2cSJim Jagielskiuse installer::systemactions; 32*b1cdbd2cSJim Jagielskiuse installer::worker; 33*b1cdbd2cSJim Jagielskiuse installer::windows::idtglobal; 34*b1cdbd2cSJim Jagielski 35*b1cdbd2cSJim Jagielski################################################################################# 36*b1cdbd2cSJim Jagielski# Unpacking cabinet files with expand 37*b1cdbd2cSJim Jagielski################################################################################# 38*b1cdbd2cSJim Jagielski 39*b1cdbd2cSJim Jagielskisub unpack_cabinet_file 40*b1cdbd2cSJim Jagielski{ 41*b1cdbd2cSJim Jagielski my ($cabfilename, $unpackdir) = @_; 42*b1cdbd2cSJim Jagielski 43*b1cdbd2cSJim Jagielski my $infoline = "Unpacking cabinet file: $cabfilename\n"; 44*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 45*b1cdbd2cSJim Jagielski 46*b1cdbd2cSJim Jagielski my $expandfile = "expand.exe"; # Has to be in the path 47*b1cdbd2cSJim Jagielski 48*b1cdbd2cSJim Jagielski # expand.exe has to be located in the system directory. 49*b1cdbd2cSJim Jagielski # Cygwin has another tool expand.exe, that converts tabs to spaces. This cannot be used of course. 50*b1cdbd2cSJim Jagielski # But this wrong expand.exe is typically in the PATH before this expand.exe, to unpack 51*b1cdbd2cSJim Jagielski # cabinet files. 52*b1cdbd2cSJim Jagielski 53*b1cdbd2cSJim Jagielski# if ( $^O =~ /cygwin/i ) 54*b1cdbd2cSJim Jagielski# { 55*b1cdbd2cSJim Jagielski# $expandfile = $ENV{'SYSTEMROOT'} . "/system32/expand.exe"; # Has to be located in the systemdirectory 56*b1cdbd2cSJim Jagielski# $expandfile =~ s/\\/\//; 57*b1cdbd2cSJim Jagielski# if ( ! -f $expandfile ) { exit_program("ERROR: Did not find file $expandfile in the Windows system folder!"); } 58*b1cdbd2cSJim Jagielski# } 59*b1cdbd2cSJim Jagielski 60*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) 61*b1cdbd2cSJim Jagielski { 62*b1cdbd2cSJim Jagielski $expandfile = qx(cygpath -u "$ENV{WINDIR}"/System32/expand.exe); 63*b1cdbd2cSJim Jagielski chomp $expandfile; 64*b1cdbd2cSJim Jagielski } 65*b1cdbd2cSJim Jagielski 66*b1cdbd2cSJim Jagielski my $expandlogfile = $unpackdir . $installer::globals::separator . "expand.log"; 67*b1cdbd2cSJim Jagielski 68*b1cdbd2cSJim Jagielski # exclude cabinet file 69*b1cdbd2cSJim Jagielski # my $systemcall = $cabarc . " -o X " . $mergemodulehash->{'cabinetfile'}; 70*b1cdbd2cSJim Jagielski 71*b1cdbd2cSJim Jagielski my $systemcall = ""; 72*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) { 73*b1cdbd2cSJim Jagielski my $localunpackdir = qx{cygpath -w "$unpackdir"}; 74*b1cdbd2cSJim Jagielski chomp ($localunpackdir); 75*b1cdbd2cSJim Jagielski $localunpackdir =~ s/\\/\\\\/g; 76*b1cdbd2cSJim Jagielski $cabfilename =~ s/\\/\\\\/g; 77*b1cdbd2cSJim Jagielski $cabfilename =~ s/\s*$//g; 78*b1cdbd2cSJim Jagielski $systemcall = $expandfile . " " . $cabfilename . " -F:\* " . $localunpackdir . " \> " . $expandlogfile; 79*b1cdbd2cSJim Jagielski } 80*b1cdbd2cSJim Jagielski else 81*b1cdbd2cSJim Jagielski { 82*b1cdbd2cSJim Jagielski $systemcall = $expandfile . " " . $cabfilename . " -F:\* " . $unpackdir . " \> " . $expandlogfile; 83*b1cdbd2cSJim Jagielski } 84*b1cdbd2cSJim Jagielski 85*b1cdbd2cSJim Jagielski my $returnvalue = system($systemcall); 86*b1cdbd2cSJim Jagielski $infoline = "Systemcall: $systemcall\n"; 87*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 88*b1cdbd2cSJim Jagielski 89*b1cdbd2cSJim Jagielski if ($returnvalue) 90*b1cdbd2cSJim Jagielski { 91*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute $systemcall !\n"; 92*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 93*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Could not extract cabinet file: $mergemodulehash->{'cabinetfile'} !", "change_file_table"); 94*b1cdbd2cSJim Jagielski } 95*b1cdbd2cSJim Jagielski else 96*b1cdbd2cSJim Jagielski { 97*b1cdbd2cSJim Jagielski $infoline = "Success: Executed $systemcall successfully!\n"; 98*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 99*b1cdbd2cSJim Jagielski } 100*b1cdbd2cSJim Jagielski} 101*b1cdbd2cSJim Jagielski 102*b1cdbd2cSJim Jagielski################################################################################# 103*b1cdbd2cSJim Jagielski# Include tables into a msi database 104*b1cdbd2cSJim Jagielski################################################################################# 105*b1cdbd2cSJim Jagielski 106*b1cdbd2cSJim Jagielskisub include_tables_into_pcpfile 107*b1cdbd2cSJim Jagielski{ 108*b1cdbd2cSJim Jagielski my ($fullmsidatabasepath, $workdir, $tables) = @_; 109*b1cdbd2cSJim Jagielski 110*b1cdbd2cSJim Jagielski my $msidb = "msidb.exe"; # Has to be in the path 111*b1cdbd2cSJim Jagielski my $infoline = ""; 112*b1cdbd2cSJim Jagielski my $systemcall = ""; 113*b1cdbd2cSJim Jagielski my $returnvalue = ""; 114*b1cdbd2cSJim Jagielski 115*b1cdbd2cSJim Jagielski # Make all table 8+3 conform 116*b1cdbd2cSJim Jagielski my $alltables = installer::converter::convert_stringlist_into_array(\$tables, " "); 117*b1cdbd2cSJim Jagielski 118*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$alltables}; $i++ ) 119*b1cdbd2cSJim Jagielski { 120*b1cdbd2cSJim Jagielski my $tablename = ${$alltables}[$i]; 121*b1cdbd2cSJim Jagielski $tablename =~ s/\s*$//; 122*b1cdbd2cSJim Jagielski my $namelength = length($tablename); 123*b1cdbd2cSJim Jagielski if ( $namelength > 8 ) 124*b1cdbd2cSJim Jagielski { 125*b1cdbd2cSJim Jagielski my $newtablename = substr($tablename, 0, 8); # name, offset, length 126*b1cdbd2cSJim Jagielski my $oldfile = $workdir . $installer::globals::separator . $tablename . ".idt"; 127*b1cdbd2cSJim Jagielski my $newfile = $workdir . $installer::globals::separator . $newtablename . ".idt"; 128*b1cdbd2cSJim Jagielski if ( -f $newfile ) { unlink $newfile; } 129*b1cdbd2cSJim Jagielski installer::systemactions::copy_one_file($oldfile, $newfile); 130*b1cdbd2cSJim Jagielski my $savfile = $oldfile . ".orig"; 131*b1cdbd2cSJim Jagielski installer::systemactions::copy_one_file($oldfile, $savfile); 132*b1cdbd2cSJim Jagielski } 133*b1cdbd2cSJim Jagielski } 134*b1cdbd2cSJim Jagielski 135*b1cdbd2cSJim Jagielski # Import of tables 136*b1cdbd2cSJim Jagielski 137*b1cdbd2cSJim Jagielski $systemcall = $msidb . " -d " . $fullmsidatabasepath . " -f " . $workdir . " -i " . $tables; 138*b1cdbd2cSJim Jagielski 139*b1cdbd2cSJim Jagielski $returnvalue = system($systemcall); 140*b1cdbd2cSJim Jagielski 141*b1cdbd2cSJim Jagielski $infoline = "Systemcall: $systemcall\n"; 142*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 143*b1cdbd2cSJim Jagielski 144*b1cdbd2cSJim Jagielski if ($returnvalue) 145*b1cdbd2cSJim Jagielski { 146*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute $systemcall !\n"; 147*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 148*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Could not include tables into msi database: $fullmsidatabasepath !", "include_tables_into_pcpfile"); 149*b1cdbd2cSJim Jagielski } 150*b1cdbd2cSJim Jagielski else 151*b1cdbd2cSJim Jagielski { 152*b1cdbd2cSJim Jagielski $infoline = "Success: Executed $systemcall successfully!\n"; 153*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 154*b1cdbd2cSJim Jagielski } 155*b1cdbd2cSJim Jagielski} 156*b1cdbd2cSJim Jagielski 157*b1cdbd2cSJim Jagielski################################################################################# 158*b1cdbd2cSJim Jagielski# Extracting tables from msi database 159*b1cdbd2cSJim Jagielski################################################################################# 160*b1cdbd2cSJim Jagielski 161*b1cdbd2cSJim Jagielskisub extract_tables_from_pcpfile 162*b1cdbd2cSJim Jagielski{ 163*b1cdbd2cSJim Jagielski my ($fullmsidatabasepath, $workdir, $tablelist) = @_; 164*b1cdbd2cSJim Jagielski 165*b1cdbd2cSJim Jagielski my $msidb = "msidb.exe"; # Has to be in the path 166*b1cdbd2cSJim Jagielski my $infoline = ""; 167*b1cdbd2cSJim Jagielski my $systemcall = ""; 168*b1cdbd2cSJim Jagielski my $returnvalue = ""; 169*b1cdbd2cSJim Jagielski 170*b1cdbd2cSJim Jagielski my $localfullmsidatabasepath = $fullmsidatabasepath; 171*b1cdbd2cSJim Jagielski 172*b1cdbd2cSJim Jagielski # Export of all tables by using "*" 173*b1cdbd2cSJim Jagielski 174*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) { 175*b1cdbd2cSJim Jagielski # Copying the msi database locally guarantees the format of the directory. 176*b1cdbd2cSJim Jagielski # Otherwise it is defined in the file of UPDATE_DATABASE_LISTNAME 177*b1cdbd2cSJim Jagielski 178*b1cdbd2cSJim Jagielski my $msifilename = $localfullmsidatabasepath; 179*b1cdbd2cSJim Jagielski installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$msifilename); 180*b1cdbd2cSJim Jagielski my $destdatabasename = $workdir . $installer::globals::separator . $msifilename; 181*b1cdbd2cSJim Jagielski installer::systemactions::copy_one_file($localfullmsidatabasepath, $destdatabasename); 182*b1cdbd2cSJim Jagielski $localfullmsidatabasepath = $destdatabasename; 183*b1cdbd2cSJim Jagielski 184*b1cdbd2cSJim Jagielski chomp( $localfullmsidatabasepath = qx{cygpath -w "$localfullmsidatabasepath"} ); 185*b1cdbd2cSJim Jagielski chomp( $workdir = qx{cygpath -w "$workdir"} ); 186*b1cdbd2cSJim Jagielski 187*b1cdbd2cSJim Jagielski # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 188*b1cdbd2cSJim Jagielski $localfullmsidatabasepath =~ s/\\/\\\\/g; 189*b1cdbd2cSJim Jagielski $workdir =~ s/\\/\\\\/g; 190*b1cdbd2cSJim Jagielski 191*b1cdbd2cSJim Jagielski # and if there are still slashes, they also need to be double backslash 192*b1cdbd2cSJim Jagielski $localfullmsidatabasepath =~ s/\//\\\\/g; 193*b1cdbd2cSJim Jagielski $workdir =~ s/\//\\\\/g; 194*b1cdbd2cSJim Jagielski } 195*b1cdbd2cSJim Jagielski 196*b1cdbd2cSJim Jagielski $systemcall = $msidb . " -d " . $localfullmsidatabasepath . " -f " . $workdir . " -e $tablelist"; 197*b1cdbd2cSJim Jagielski $returnvalue = system($systemcall); 198*b1cdbd2cSJim Jagielski 199*b1cdbd2cSJim Jagielski $infoline = "Systemcall: $systemcall\n"; 200*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 201*b1cdbd2cSJim Jagielski 202*b1cdbd2cSJim Jagielski if ($returnvalue) 203*b1cdbd2cSJim Jagielski { 204*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute $systemcall !\n"; 205*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 206*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: Could not exclude tables from pcp file: $localfullmsidatabasepath !", "extract_tables_from_pcpfile"); 207*b1cdbd2cSJim Jagielski } 208*b1cdbd2cSJim Jagielski else 209*b1cdbd2cSJim Jagielski { 210*b1cdbd2cSJim Jagielski $infoline = "Success: Executed $systemcall successfully!\n"; 211*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 212*b1cdbd2cSJim Jagielski } 213*b1cdbd2cSJim Jagielski} 214*b1cdbd2cSJim Jagielski 215*b1cdbd2cSJim Jagielski################################################################################ 216*b1cdbd2cSJim Jagielski# Analyzing the content of Directory.idt 217*b1cdbd2cSJim Jagielski################################################################################# 218*b1cdbd2cSJim Jagielski 219*b1cdbd2cSJim Jagielskisub analyze_directory_file 220*b1cdbd2cSJim Jagielski{ 221*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 222*b1cdbd2cSJim Jagielski 223*b1cdbd2cSJim Jagielski my %table = (); 224*b1cdbd2cSJim Jagielski 225*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 226*b1cdbd2cSJim Jagielski { 227*b1cdbd2cSJim Jagielski if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; } 228*b1cdbd2cSJim Jagielski 229*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\s*$/ ) 230*b1cdbd2cSJim Jagielski { 231*b1cdbd2cSJim Jagielski my $dir = $1; 232*b1cdbd2cSJim Jagielski my $parent = $2; 233*b1cdbd2cSJim Jagielski my $name = $3; 234*b1cdbd2cSJim Jagielski 235*b1cdbd2cSJim Jagielski if ( $name =~ /^\s*(.*?)\s*\:\s*(.*?)\s*$/ ) { $name = $2; } 236*b1cdbd2cSJim Jagielski if ( $name =~ /^\s*(.*?)\s*\|\s*(.*?)\s*$/ ) { $name = $2; } 237*b1cdbd2cSJim Jagielski 238*b1cdbd2cSJim Jagielski my %helphash = (); 239*b1cdbd2cSJim Jagielski $helphash{'Directory_Parent'} = $parent; 240*b1cdbd2cSJim Jagielski $helphash{'DefaultDir'} = $name; 241*b1cdbd2cSJim Jagielski $table{$dir} = \%helphash; 242*b1cdbd2cSJim Jagielski } 243*b1cdbd2cSJim Jagielski } 244*b1cdbd2cSJim Jagielski 245*b1cdbd2cSJim Jagielski return \%table; 246*b1cdbd2cSJim Jagielski} 247*b1cdbd2cSJim Jagielski 248*b1cdbd2cSJim Jagielski################################################################################# 249*b1cdbd2cSJim Jagielski# Analyzing the content of Component.idt 250*b1cdbd2cSJim Jagielski################################################################################# 251*b1cdbd2cSJim Jagielski 252*b1cdbd2cSJim Jagielskisub analyze_component_file 253*b1cdbd2cSJim Jagielski{ 254*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 255*b1cdbd2cSJim Jagielski 256*b1cdbd2cSJim Jagielski my %table = (); 257*b1cdbd2cSJim Jagielski 258*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 259*b1cdbd2cSJim Jagielski { 260*b1cdbd2cSJim Jagielski if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; } 261*b1cdbd2cSJim Jagielski 262*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 263*b1cdbd2cSJim Jagielski { 264*b1cdbd2cSJim Jagielski my $component = $1; 265*b1cdbd2cSJim Jagielski my $dir = $3; 266*b1cdbd2cSJim Jagielski 267*b1cdbd2cSJim Jagielski $table{$component} = $dir; 268*b1cdbd2cSJim Jagielski } 269*b1cdbd2cSJim Jagielski } 270*b1cdbd2cSJim Jagielski 271*b1cdbd2cSJim Jagielski return \%table; 272*b1cdbd2cSJim Jagielski} 273*b1cdbd2cSJim Jagielski 274*b1cdbd2cSJim Jagielski################################################################################# 275*b1cdbd2cSJim Jagielski# Analyzing the full content of Component.idt 276*b1cdbd2cSJim Jagielski################################################################################# 277*b1cdbd2cSJim Jagielski 278*b1cdbd2cSJim Jagielskisub analyze_keypath_component_file 279*b1cdbd2cSJim Jagielski{ 280*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 281*b1cdbd2cSJim Jagielski 282*b1cdbd2cSJim Jagielski my %keypathtable = (); 283*b1cdbd2cSJim Jagielski 284*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 285*b1cdbd2cSJim Jagielski { 286*b1cdbd2cSJim Jagielski if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; } 287*b1cdbd2cSJim Jagielski 288*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 289*b1cdbd2cSJim Jagielski { 290*b1cdbd2cSJim Jagielski my $component = $1; 291*b1cdbd2cSJim Jagielski my $keypath = $6; 292*b1cdbd2cSJim Jagielski 293*b1cdbd2cSJim Jagielski $keypathtable{$keypath} = $component; 294*b1cdbd2cSJim Jagielski } 295*b1cdbd2cSJim Jagielski } 296*b1cdbd2cSJim Jagielski 297*b1cdbd2cSJim Jagielski return (\%keypathtable); 298*b1cdbd2cSJim Jagielski 299*b1cdbd2cSJim Jagielski} 300*b1cdbd2cSJim Jagielski 301*b1cdbd2cSJim Jagielski################################################################################# 302*b1cdbd2cSJim Jagielski# Analyzing the content of Registry.idt 303*b1cdbd2cSJim Jagielski################################################################################# 304*b1cdbd2cSJim Jagielski 305*b1cdbd2cSJim Jagielskisub analyze_registry_file 306*b1cdbd2cSJim Jagielski{ 307*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 308*b1cdbd2cSJim Jagielski 309*b1cdbd2cSJim Jagielski my %table = (); 310*b1cdbd2cSJim Jagielski 311*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 312*b1cdbd2cSJim Jagielski { 313*b1cdbd2cSJim Jagielski if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; } 314*b1cdbd2cSJim Jagielski 315*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 316*b1cdbd2cSJim Jagielski { 317*b1cdbd2cSJim Jagielski my $registry = $1; 318*b1cdbd2cSJim Jagielski my $root = $2; 319*b1cdbd2cSJim Jagielski my $key = $3; 320*b1cdbd2cSJim Jagielski my $name = $4; 321*b1cdbd2cSJim Jagielski my $value = $5; 322*b1cdbd2cSJim Jagielski my $component = $6; 323*b1cdbd2cSJim Jagielski 324*b1cdbd2cSJim Jagielski my %helphash = (); 325*b1cdbd2cSJim Jagielski # $helphash{'Registry'} = $registry; 326*b1cdbd2cSJim Jagielski $helphash{'Root'} = $root; 327*b1cdbd2cSJim Jagielski $helphash{'Key'} = $key; 328*b1cdbd2cSJim Jagielski $helphash{'Name'} = $name; 329*b1cdbd2cSJim Jagielski $helphash{'Value'} = $value; 330*b1cdbd2cSJim Jagielski $helphash{'Component'} = $component; 331*b1cdbd2cSJim Jagielski 332*b1cdbd2cSJim Jagielski $table{$registry} = \%helphash; 333*b1cdbd2cSJim Jagielski } 334*b1cdbd2cSJim Jagielski } 335*b1cdbd2cSJim Jagielski 336*b1cdbd2cSJim Jagielski return \%table; 337*b1cdbd2cSJim Jagielski} 338*b1cdbd2cSJim Jagielski 339*b1cdbd2cSJim Jagielski################################################################################# 340*b1cdbd2cSJim Jagielski# Analyzing the content of File.idt 341*b1cdbd2cSJim Jagielski################################################################################# 342*b1cdbd2cSJim Jagielski 343*b1cdbd2cSJim Jagielskisub analyze_file_file 344*b1cdbd2cSJim Jagielski{ 345*b1cdbd2cSJim Jagielski my ($filecontent) = @_; 346*b1cdbd2cSJim Jagielski 347*b1cdbd2cSJim Jagielski my %table = (); 348*b1cdbd2cSJim Jagielski my %fileorder = (); 349*b1cdbd2cSJim Jagielski my $maxsequence = 0; 350*b1cdbd2cSJim Jagielski 351*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) 352*b1cdbd2cSJim Jagielski { 353*b1cdbd2cSJim Jagielski if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; } 354*b1cdbd2cSJim Jagielski 355*b1cdbd2cSJim Jagielski if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) 356*b1cdbd2cSJim Jagielski { 357*b1cdbd2cSJim Jagielski my $file = $1; 358*b1cdbd2cSJim Jagielski my $comp = $2; 359*b1cdbd2cSJim Jagielski my $filename = $3; 360*b1cdbd2cSJim Jagielski my $sequence = $8; 361*b1cdbd2cSJim Jagielski 362*b1cdbd2cSJim Jagielski if ( $filename =~ /^\s*(.*?)\s*\|\s*(.*?)\s*$/ ) { $filename = $2; } 363*b1cdbd2cSJim Jagielski 364*b1cdbd2cSJim Jagielski my %helphash = (); 365*b1cdbd2cSJim Jagielski $helphash{'Component'} = $comp; 366*b1cdbd2cSJim Jagielski $helphash{'FileName'} = $filename; 367*b1cdbd2cSJim Jagielski $helphash{'Sequence'} = $sequence; 368*b1cdbd2cSJim Jagielski 369*b1cdbd2cSJim Jagielski $table{$file} = \%helphash; 370*b1cdbd2cSJim Jagielski 371*b1cdbd2cSJim Jagielski $fileorder{$sequence} = $file; 372*b1cdbd2cSJim Jagielski 373*b1cdbd2cSJim Jagielski if ( $sequence > $maxsequence ) { $maxsequence = $sequence; } 374*b1cdbd2cSJim Jagielski } 375*b1cdbd2cSJim Jagielski } 376*b1cdbd2cSJim Jagielski 377*b1cdbd2cSJim Jagielski return (\%table, \%fileorder, $maxsequence); 378*b1cdbd2cSJim Jagielski} 379*b1cdbd2cSJim Jagielski 380*b1cdbd2cSJim Jagielski#################################################################################### 381*b1cdbd2cSJim Jagielski# Recursively creating the directory tree 382*b1cdbd2cSJim Jagielski#################################################################################### 383*b1cdbd2cSJim Jagielski 384*b1cdbd2cSJim Jagielskisub create_directory_tree 385*b1cdbd2cSJim Jagielski{ 386*b1cdbd2cSJim Jagielski my ($parent, $pathcollector, $fulldir, $dirhash) = @_; 387*b1cdbd2cSJim Jagielski 388*b1cdbd2cSJim Jagielski foreach my $dir ( keys %{$dirhash} ) 389*b1cdbd2cSJim Jagielski { 390*b1cdbd2cSJim Jagielski if (( $dirhash->{$dir}->{'Directory_Parent'} eq $parent ) && ( $dirhash->{$dir}->{'DefaultDir'} ne "." )) 391*b1cdbd2cSJim Jagielski { 392*b1cdbd2cSJim Jagielski my $dirname = $dirhash->{$dir}->{'DefaultDir'}; 393*b1cdbd2cSJim Jagielski # Create the directory 394*b1cdbd2cSJim Jagielski my $newdir = $fulldir . $installer::globals::separator . $dirname; 395*b1cdbd2cSJim Jagielski if ( ! -f $newdir ) { mkdir $newdir; } 396*b1cdbd2cSJim Jagielski # Saving in collector 397*b1cdbd2cSJim Jagielski $pathcollector->{$dir} = $newdir; 398*b1cdbd2cSJim Jagielski # Iteration 399*b1cdbd2cSJim Jagielski create_directory_tree($dir, $pathcollector, $newdir, $dirhash); 400*b1cdbd2cSJim Jagielski } 401*b1cdbd2cSJim Jagielski } 402*b1cdbd2cSJim Jagielski} 403*b1cdbd2cSJim Jagielski 404*b1cdbd2cSJim Jagielski#################################################################################### 405*b1cdbd2cSJim Jagielski# Creating the directory tree 406*b1cdbd2cSJim Jagielski#################################################################################### 407*b1cdbd2cSJim Jagielski 408*b1cdbd2cSJim Jagielskisub create_directory_structure 409*b1cdbd2cSJim Jagielski{ 410*b1cdbd2cSJim Jagielski my ($dirhash, $targetdir) = @_; 411*b1cdbd2cSJim Jagielski 412*b1cdbd2cSJim Jagielski my %fullpathhash = (); 413*b1cdbd2cSJim Jagielski 414*b1cdbd2cSJim Jagielski my @startparents = ("TARGETDIR", "INSTALLLOCATION"); 415*b1cdbd2cSJim Jagielski 416*b1cdbd2cSJim Jagielski foreach $dir (@startparents) { create_directory_tree($dir, \%fullpathhash, $targetdir, $dirhash); } 417*b1cdbd2cSJim Jagielski 418*b1cdbd2cSJim Jagielski # Also adding the pathes of the startparents 419*b1cdbd2cSJim Jagielski foreach $dir (@startparents) 420*b1cdbd2cSJim Jagielski { 421*b1cdbd2cSJim Jagielski if ( ! exists($fullpathhash{$dir}) ) { $fullpathhash{$dir} = $targetdir; } 422*b1cdbd2cSJim Jagielski } 423*b1cdbd2cSJim Jagielski 424*b1cdbd2cSJim Jagielski return \%fullpathhash; 425*b1cdbd2cSJim Jagielski} 426*b1cdbd2cSJim Jagielski 427*b1cdbd2cSJim Jagielski#################################################################################### 428*b1cdbd2cSJim Jagielski# Copying files into installation set 429*b1cdbd2cSJim Jagielski#################################################################################### 430*b1cdbd2cSJim Jagielski 431*b1cdbd2cSJim Jagielskisub copy_files_into_directory_structure 432*b1cdbd2cSJim Jagielski{ 433*b1cdbd2cSJim Jagielski my ($fileorder, $filehash, $componenthash, $fullpathhash, $maxsequence, $unpackdir, $installdir, $dirhash) = @_; 434*b1cdbd2cSJim Jagielski 435*b1cdbd2cSJim Jagielski my $unopkgfile = ""; 436*b1cdbd2cSJim Jagielski 437*b1cdbd2cSJim Jagielski for ( my $i = 1; $i <= $maxsequence; $i++ ) 438*b1cdbd2cSJim Jagielski { 439*b1cdbd2cSJim Jagielski if ( exists($fileorder->{$i}) ) 440*b1cdbd2cSJim Jagielski { 441*b1cdbd2cSJim Jagielski my $file = $fileorder->{$i}; 442*b1cdbd2cSJim Jagielski if ( ! exists($filehash->{$file}->{'Component'}) ) { installer::exiter::exit_program("ERROR: Did not find component for file: \"$file\".", "copy_files_into_directory_structure"); } 443*b1cdbd2cSJim Jagielski my $component = $filehash->{$file}->{'Component'}; 444*b1cdbd2cSJim Jagielski if ( ! exists($componenthash->{$component}) ) { installer::exiter::exit_program("ERROR: Did not find directory for component: \"$component\".", "copy_files_into_directory_structure"); } 445*b1cdbd2cSJim Jagielski my $dirname = $componenthash->{$component}; 446*b1cdbd2cSJim Jagielski if ( ! exists($fullpathhash->{$dirname}) ) { installer::exiter::exit_program("ERROR: Did not find full directory path for dir: \"$dirname\".", "copy_files_into_directory_structure"); } 447*b1cdbd2cSJim Jagielski my $destdir = $fullpathhash->{$dirname}; 448*b1cdbd2cSJim Jagielski if ( ! exists($filehash->{$file}->{'FileName'}) ) { installer::exiter::exit_program("ERROR: Did not find \"FileName\" for file: \"$file\".", "copy_files_into_directory_structure"); } 449*b1cdbd2cSJim Jagielski my $destfile = $filehash->{$file}->{'FileName'}; 450*b1cdbd2cSJim Jagielski 451*b1cdbd2cSJim Jagielski $destfile = $destdir . $installer::globals::separator . $destfile; 452*b1cdbd2cSJim Jagielski my $sourcefile = $unpackdir . $installer::globals::separator . $file; 453*b1cdbd2cSJim Jagielski 454*b1cdbd2cSJim Jagielski if ( ! -f $sourcefile ) 455*b1cdbd2cSJim Jagielski { 456*b1cdbd2cSJim Jagielski # It is possible, that this was an unpacked file 457*b1cdbd2cSJim Jagielski # Looking in the dirhash, to find the subdirectory in the installation set (the id is $dirname) 458*b1cdbd2cSJim Jagielski # subdir is not recursively analyzed, only one directory. 459*b1cdbd2cSJim Jagielski 460*b1cdbd2cSJim Jagielski my $oldsourcefile = $sourcefile; 461*b1cdbd2cSJim Jagielski my $subdir = ""; 462*b1cdbd2cSJim Jagielski if ( exists($dirhash->{$dirname}->{'DefaultDir'}) ) { $subdir = $dirhash->{$dirname}->{'DefaultDir'} . $installer::globals::separator; } 463*b1cdbd2cSJim Jagielski my $realfilename = $filehash->{$file}->{'FileName'}; 464*b1cdbd2cSJim Jagielski my $localinstalldir = $installdir; 465*b1cdbd2cSJim Jagielski 466*b1cdbd2cSJim Jagielski $localinstalldir =~ s/\\\s*$//; 467*b1cdbd2cSJim Jagielski $localinstalldir =~ s/\/\s*$//; 468*b1cdbd2cSJim Jagielski 469*b1cdbd2cSJim Jagielski $sourcefile = $localinstalldir . $installer::globals::separator . $subdir . $realfilename; 470*b1cdbd2cSJim Jagielski 471*b1cdbd2cSJim Jagielski if ( ! -f $sourcefile ) 472*b1cdbd2cSJim Jagielski { 473*b1cdbd2cSJim Jagielski installer::exiter::exit_program("ERROR: File not found: \"$oldsourcefile\" (or \"$sourcefile\").", "copy_files_into_directory_structure"); 474*b1cdbd2cSJim Jagielski } 475*b1cdbd2cSJim Jagielski } 476*b1cdbd2cSJim Jagielski 477*b1cdbd2cSJim Jagielski my $copyreturn = copy($sourcefile, $destfile); 478*b1cdbd2cSJim Jagielski 479*b1cdbd2cSJim Jagielski if ( ! $copyreturn) # only logging problems 480*b1cdbd2cSJim Jagielski { 481*b1cdbd2cSJim Jagielski my $infoline = "ERROR: Could not copy $sourcefile to $destfile (insufficient disc space for $destfile ?)\n"; 482*b1cdbd2cSJim Jagielski $returnvalue = 0; 483*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 484*b1cdbd2cSJim Jagielski installer::exiter::exit_program($infoline, "copy_files_into_directory_structure"); 485*b1cdbd2cSJim Jagielski } 486*b1cdbd2cSJim Jagielski 487*b1cdbd2cSJim Jagielski if ( $destfile =~ /unopkg\.exe\s*$/ ) { $unopkgfile = $destfile; } 488*b1cdbd2cSJim Jagielski 489*b1cdbd2cSJim Jagielski # installer::systemactions::copy_one_file($sourcefile, $destfile); 490*b1cdbd2cSJim Jagielski } 491*b1cdbd2cSJim Jagielski # else # allowing missing sequence numbers ? 492*b1cdbd2cSJim Jagielski # { 493*b1cdbd2cSJim Jagielski # installer::exiter::exit_program("ERROR: No file assigned to sequence $i", "copy_files_into_directory_structure"); 494*b1cdbd2cSJim Jagielski # } 495*b1cdbd2cSJim Jagielski } 496*b1cdbd2cSJim Jagielski 497*b1cdbd2cSJim Jagielski return $unopkgfile; 498*b1cdbd2cSJim Jagielski} 499*b1cdbd2cSJim Jagielski 500*b1cdbd2cSJim Jagielski 501*b1cdbd2cSJim Jagielski############################################################### 502*b1cdbd2cSJim Jagielski# Setting the time string for the 503*b1cdbd2cSJim Jagielski# Summary Information stream in the 504*b1cdbd2cSJim Jagielski# msi database of the admin installations. 505*b1cdbd2cSJim Jagielski############################################################### 506*b1cdbd2cSJim Jagielski 507*b1cdbd2cSJim Jagielskisub get_sis_time_string 508*b1cdbd2cSJim Jagielski{ 509*b1cdbd2cSJim Jagielski # Syntax: <yyyy/mm/dd hh:mm:ss> 510*b1cdbd2cSJim Jagielski my $second = (localtime())[0]; 511*b1cdbd2cSJim Jagielski my $minute = (localtime())[1]; 512*b1cdbd2cSJim Jagielski my $hour = (localtime())[2]; 513*b1cdbd2cSJim Jagielski my $day = (localtime())[3]; 514*b1cdbd2cSJim Jagielski my $month = (localtime())[4]; 515*b1cdbd2cSJim Jagielski my $year = 1900 + (localtime())[5]; 516*b1cdbd2cSJim Jagielski 517*b1cdbd2cSJim Jagielski $month++; # zero based month 518*b1cdbd2cSJim Jagielski 519*b1cdbd2cSJim Jagielski if ( $second < 10 ) { $second = "0" . $second; } 520*b1cdbd2cSJim Jagielski if ( $minute < 10 ) { $minute = "0" . $minute; } 521*b1cdbd2cSJim Jagielski if ( $hour < 10 ) { $hour = "0" . $hour; } 522*b1cdbd2cSJim Jagielski if ( $day < 10 ) { $day = "0" . $day; } 523*b1cdbd2cSJim Jagielski if ( $month < 10 ) { $month = "0" . $month; } 524*b1cdbd2cSJim Jagielski 525*b1cdbd2cSJim Jagielski my $timestring = $year . "/" . $month . "/" . $day . " " . $hour . ":" . $minute . ":" . $second; 526*b1cdbd2cSJim Jagielski 527*b1cdbd2cSJim Jagielski return $timestring; 528*b1cdbd2cSJim Jagielski} 529*b1cdbd2cSJim Jagielski 530*b1cdbd2cSJim Jagielski############################################################### 531*b1cdbd2cSJim Jagielski# Windows registry entries containing properties are not set 532*b1cdbd2cSJim Jagielski# correctly during msp patch process. The properties are 533*b1cdbd2cSJim Jagielski# empty or do get their default values. This destroys the 534*b1cdbd2cSJim Jagielski# values of many entries in Windows registry. 535*b1cdbd2cSJim Jagielski# This can be fixed by removing all entries in Registry table, 536*b1cdbd2cSJim Jagielski# containing a property before starting msimsp.exe. 537*b1cdbd2cSJim Jagielski############################################################### 538*b1cdbd2cSJim Jagielski 539*b1cdbd2cSJim Jagielskisub remove_properties_from_registry_table 540*b1cdbd2cSJim Jagielski{ 541*b1cdbd2cSJim Jagielski my ($registryhash, $componentkeypathhash, $registryfilecontent) = @_; 542*b1cdbd2cSJim Jagielski 543*b1cdbd2cSJim Jagielski $installer::logger::Lang->print("\n"); 544*b1cdbd2cSJim Jagielski $installer::logger::Lang->add_timestamp("Performance Info: Start remove_properties_from_registry_table"); 545*b1cdbd2cSJim Jagielski 546*b1cdbd2cSJim Jagielski my @registrytable = (); 547*b1cdbd2cSJim Jagielski 548*b1cdbd2cSJim Jagielski # Registry hash 549*b1cdbd2cSJim Jagielski # Collecting all RegistryItems with values containing a property: [...] 550*b1cdbd2cSJim Jagielski # To which component do they belong 551*b1cdbd2cSJim Jagielski # Is this after removal an empty component? Create a replacement, so that 552*b1cdbd2cSJim Jagielski # no Component has to be removed. 553*b1cdbd2cSJim Jagielski # Is this RegistryItem a KeyPath of a component. Then it cannot be removed. 554*b1cdbd2cSJim Jagielski 555*b1cdbd2cSJim Jagielski my %problemitems = (); 556*b1cdbd2cSJim Jagielski my %problemcomponents = (); 557*b1cdbd2cSJim Jagielski my %securecomponents = (); 558*b1cdbd2cSJim Jagielski my $changevalue = ""; 559*b1cdbd2cSJim Jagielski my $changeroot = ""; 560*b1cdbd2cSJim Jagielski my $infoline = ""; 561*b1cdbd2cSJim Jagielski 562*b1cdbd2cSJim Jagielski my $newitemcounter = 0; 563*b1cdbd2cSJim Jagielski my $olditemcounter = 0; 564*b1cdbd2cSJim Jagielski 565*b1cdbd2cSJim Jagielski foreach my $regitem ( keys %{$registryhash} ) 566*b1cdbd2cSJim Jagielski { 567*b1cdbd2cSJim Jagielski my $value = ""; 568*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Value'}) ) { $value = $registryhash->{$regitem}->{'Value'}; } 569*b1cdbd2cSJim Jagielski 570*b1cdbd2cSJim Jagielski if ( $value =~ /^.*(\[.*?\]).*$/ ) 571*b1cdbd2cSJim Jagielski { 572*b1cdbd2cSJim Jagielski my $property = $1; 573*b1cdbd2cSJim Jagielski 574*b1cdbd2cSJim Jagielski # Collecting registry item 575*b1cdbd2cSJim Jagielski $problemitems{$regitem} = 1; # "1" -> can be removed 576*b1cdbd2cSJim Jagielski if ( exists($componentkeypathhash->{$regitem}) ) { $problemitems{$regitem} = 2; } # "2" -> cannot be removed, KeyPath 577*b1cdbd2cSJim Jagielski 578*b1cdbd2cSJim Jagielski # Collecting component (and number of problematic registry items 579*b1cdbd2cSJim Jagielski # my $component = $registryhash->{$regitem}->{'Component'}; 580*b1cdbd2cSJim Jagielski # if ( exists($problemcomponents{$regitem}) ) { $problemcomponents{$regitem} = $problemcomponents{$regitem} + 1; } 581*b1cdbd2cSJim Jagielski # else { $problemcomponents{$regitem} = 1; } 582*b1cdbd2cSJim Jagielski } 583*b1cdbd2cSJim Jagielski else 584*b1cdbd2cSJim Jagielski { 585*b1cdbd2cSJim Jagielski # Collecting all components with secure regisry items 586*b1cdbd2cSJim Jagielski my $component = ""; 587*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Component'}) ) { $component = $registryhash->{$regitem}->{'Component'}; } 588*b1cdbd2cSJim Jagielski if ( $component eq "" ) { installer::exiter::exit_program("ERROR: Did not find component for registry item \"$regitem\".", "remove_properties_from_registry_table"); } 589*b1cdbd2cSJim Jagielski $securecomponents{$component} = 1; 590*b1cdbd2cSJim Jagielski } 591*b1cdbd2cSJim Jagielski 592*b1cdbd2cSJim Jagielski # Searching for change value 593*b1cdbd2cSJim Jagielski my $localkey = ""; 594*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Key'}) ) { $localkey = $registryhash->{$regitem}->{'Key'}; } 595*b1cdbd2cSJim Jagielski if (( $localkey =~ /^\s*(Software\\.*\\)StartMenu\s*$/ ) && ( $changevalue eq "" )) 596*b1cdbd2cSJim Jagielski { 597*b1cdbd2cSJim Jagielski $changevalue = $1; 598*b1cdbd2cSJim Jagielski $changeroot = $registryhash->{$regitem}->{'Root'}; 599*b1cdbd2cSJim Jagielski } 600*b1cdbd2cSJim Jagielski 601*b1cdbd2cSJim Jagielski $olditemcounter++; 602*b1cdbd2cSJim Jagielski } 603*b1cdbd2cSJim Jagielski 604*b1cdbd2cSJim Jagielski my $removecounter = 0; 605*b1cdbd2cSJim Jagielski my $renamecounter = 0; 606*b1cdbd2cSJim Jagielski 607*b1cdbd2cSJim Jagielski foreach my $regitem ( keys %{$registryhash} ) 608*b1cdbd2cSJim Jagielski { 609*b1cdbd2cSJim Jagielski my $value = ""; 610*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Value'}) ) { $value = $registryhash->{$regitem}->{'Value'}; } 611*b1cdbd2cSJim Jagielski 612*b1cdbd2cSJim Jagielski if ( $value =~ /^.*(\[.*?\]).*$/ ) 613*b1cdbd2cSJim Jagielski { 614*b1cdbd2cSJim Jagielski # Removing registry items, that are no KeyPath and that belong to components, 615*b1cdbd2cSJim Jagielski # that have other secure registry items. 616*b1cdbd2cSJim Jagielski 617*b1cdbd2cSJim Jagielski my $component = ""; 618*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Component'}) ) { $component = $registryhash->{$regitem}->{'Component'}; } 619*b1cdbd2cSJim Jagielski if ( $component eq "" ) { installer::exiter::exit_program("ERROR: Did not find component for registry item (2) \"$regitem\".", "remove_properties_from_registry_table"); } 620*b1cdbd2cSJim Jagielski 621*b1cdbd2cSJim Jagielski if (( $problemitems{$regitem} == 1 ) && ( exists($securecomponents{$component}) )) 622*b1cdbd2cSJim Jagielski { 623*b1cdbd2cSJim Jagielski # remove complete registry item 624*b1cdbd2cSJim Jagielski delete($registryhash->{$regitem}); 625*b1cdbd2cSJim Jagielski $removecounter++; 626*b1cdbd2cSJim Jagielski $infoline = "Removing registry item: $regitem : $value\n"; 627*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 628*b1cdbd2cSJim Jagielski } 629*b1cdbd2cSJim Jagielski else 630*b1cdbd2cSJim Jagielski { 631*b1cdbd2cSJim Jagielski # Changing values of registry items, that are KeyPath or that contain to 632*b1cdbd2cSJim Jagielski # components with only unsecure registry items. 633*b1cdbd2cSJim Jagielski 634*b1cdbd2cSJim Jagielski if (( $problemitems{$regitem} == 2 ) || ( ! exists($securecomponents{$component}) )) 635*b1cdbd2cSJim Jagielski { 636*b1cdbd2cSJim Jagielski # change value of registry item 637*b1cdbd2cSJim Jagielski if ( $changevalue eq "" ) { installer::exiter::exit_program("ERROR: Did not find good change value for registry items", "remove_properties_from_registry_table"); } 638*b1cdbd2cSJim Jagielski 639*b1cdbd2cSJim Jagielski my $oldkey = ""; 640*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Key'}) ) { $oldkey = $registryhash->{$regitem}->{'Key'}; }; 641*b1cdbd2cSJim Jagielski my $oldname = ""; 642*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Name'}) ) { $oldname = $registryhash->{$regitem}->{'Name'}; } 643*b1cdbd2cSJim Jagielski my $oldvalue = ""; 644*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Value'}) ) { $oldvalue = $registryhash->{$regitem}->{'Value'}; } 645*b1cdbd2cSJim Jagielski 646*b1cdbd2cSJim Jagielski $registryhash->{$regitem}->{'Key'} = $changevalue . "RegistryItem"; 647*b1cdbd2cSJim Jagielski $registryhash->{$regitem}->{'Root'} = $changeroot; 648*b1cdbd2cSJim Jagielski $registryhash->{$regitem}->{'Name'} = $regitem; 649*b1cdbd2cSJim Jagielski $registryhash->{$regitem}->{'Value'} = 1; 650*b1cdbd2cSJim Jagielski $renamecounter++; 651*b1cdbd2cSJim Jagielski 652*b1cdbd2cSJim Jagielski $infoline = "Changing registry item: $regitem\n"; 653*b1cdbd2cSJim Jagielski $infoline = "Old: $oldkey : $oldname : $oldvalue\n"; 654*b1cdbd2cSJim Jagielski $infoline = "New: $registryhash->{$regitem}->{'Key'} : $registryhash->{$regitem}->{'Name'} : $registryhash->{$regitem}->{'Value'}\n"; 655*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 656*b1cdbd2cSJim Jagielski } 657*b1cdbd2cSJim Jagielski } 658*b1cdbd2cSJim Jagielski } 659*b1cdbd2cSJim Jagielski } 660*b1cdbd2cSJim Jagielski 661*b1cdbd2cSJim Jagielski $infoline = "Number of removed registry items: $removecounter\n"; 662*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 663*b1cdbd2cSJim Jagielski $infoline = "Number of changed registry items: $renamecounter\n"; 664*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 665*b1cdbd2cSJim Jagielski 666*b1cdbd2cSJim Jagielski # Creating the new content of Registry table 667*b1cdbd2cSJim Jagielski # First three lines from $registryfilecontent 668*b1cdbd2cSJim Jagielski # All further files from changed $registryhash 669*b1cdbd2cSJim Jagielski 670*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= 2; $i++ ) { push(@registrytable, ${$registryfilecontent}[$i]); } 671*b1cdbd2cSJim Jagielski 672*b1cdbd2cSJim Jagielski foreach my $regitem ( keys %{$registryhash} ) 673*b1cdbd2cSJim Jagielski { 674*b1cdbd2cSJim Jagielski my $root = ""; 675*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Root'}) ) { $root = $registryhash->{$regitem}->{'Root'}; } 676*b1cdbd2cSJim Jagielski else { installer::exiter::exit_program("ERROR: Did not find root in registry table for item: \"$regitem\".", "remove_properties_from_registry_table"); } 677*b1cdbd2cSJim Jagielski my $localkey = ""; 678*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Key'}) ) { $localkey = $registryhash->{$regitem}->{'Key'}; } 679*b1cdbd2cSJim Jagielski my $name = ""; 680*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Name'}) ) { $name = $registryhash->{$regitem}->{'Name'}; } 681*b1cdbd2cSJim Jagielski my $value = ""; 682*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Value'}) ) { $value = $registryhash->{$regitem}->{'Value'}; } 683*b1cdbd2cSJim Jagielski my $comp = ""; 684*b1cdbd2cSJim Jagielski if ( exists($registryhash->{$regitem}->{'Component'}) ) { $comp = $registryhash->{$regitem}->{'Component'}; } 685*b1cdbd2cSJim Jagielski 686*b1cdbd2cSJim Jagielski my $oneline = $regitem . "\t" . $root . "\t" . $localkey . "\t" . $name . "\t" . $value . "\t" . $comp . "\n"; 687*b1cdbd2cSJim Jagielski push(@registrytable, $oneline); 688*b1cdbd2cSJim Jagielski 689*b1cdbd2cSJim Jagielski $newitemcounter++; 690*b1cdbd2cSJim Jagielski } 691*b1cdbd2cSJim Jagielski 692*b1cdbd2cSJim Jagielski $infoline = "Number of registry items: $newitemcounter. Old value: $olditemcounter.\n"; 693*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 694*b1cdbd2cSJim Jagielski 695*b1cdbd2cSJim Jagielski $installer::logger::Lang->print("\n"); 696*b1cdbd2cSJim Jagielski $installer::logger::Lang->add_timestamp("Performance Info: End remove_properties_from_registry_table"); 697*b1cdbd2cSJim Jagielski 698*b1cdbd2cSJim Jagielski return (\@registrytable); 699*b1cdbd2cSJim Jagielski} 700*b1cdbd2cSJim Jagielski 701*b1cdbd2cSJim Jagielski############################################################### 702*b1cdbd2cSJim Jagielski# Writing content of administrative installations into 703*b1cdbd2cSJim Jagielski# Summary Information Stream of msi database. 704*b1cdbd2cSJim Jagielski# This is required for example for following 705*b1cdbd2cSJim Jagielski# patch processes using Windows Installer service. 706*b1cdbd2cSJim Jagielski############################################################### 707*b1cdbd2cSJim Jagielski 708*b1cdbd2cSJim Jagielskisub write_sis_info 709*b1cdbd2cSJim Jagielski{ 710*b1cdbd2cSJim Jagielski my ($msidatabase) = @_ ; 711*b1cdbd2cSJim Jagielski 712*b1cdbd2cSJim Jagielski if ( ! -f $msidatabase ) { installer::exiter::exit_program("ERROR: Cannot find file $msidatabase", "write_sis_info"); } 713*b1cdbd2cSJim Jagielski 714*b1cdbd2cSJim Jagielski my $msiinfo = "msiinfo.exe"; # Has to be in the path 715*b1cdbd2cSJim Jagielski my $infoline = ""; 716*b1cdbd2cSJim Jagielski my $systemcall = ""; 717*b1cdbd2cSJim Jagielski my $returnvalue = ""; 718*b1cdbd2cSJim Jagielski 719*b1cdbd2cSJim Jagielski # Required setting for administrative installations: 720*b1cdbd2cSJim Jagielski # -w 4 (source files are unpacked), wordcount 721*b1cdbd2cSJim Jagielski # -s <date of admin installation>, LastPrinted, Syntax: <yyyy/mm/dd hh:mm:ss> 722*b1cdbd2cSJim Jagielski # -l <person_making_admin_installation>, LastSavedBy 723*b1cdbd2cSJim Jagielski 724*b1cdbd2cSJim Jagielski my $wordcount = 4; # Unpacked files 725*b1cdbd2cSJim Jagielski my $lastprinted = get_sis_time_string(); 726*b1cdbd2cSJim Jagielski my $lastsavedby = "Installer"; 727*b1cdbd2cSJim Jagielski 728*b1cdbd2cSJim Jagielski my $localmsidatabase = $msidatabase; 729*b1cdbd2cSJim Jagielski 730*b1cdbd2cSJim Jagielski if( $^O =~ /cygwin/i ) 731*b1cdbd2cSJim Jagielski { 732*b1cdbd2cSJim Jagielski $localmsidatabase = qx{cygpath -w "$localmsidatabase"}; 733*b1cdbd2cSJim Jagielski $localmsidatabase =~ s/\\/\\\\/g; 734*b1cdbd2cSJim Jagielski $localmsidatabase =~ s/\s*$//g; 735*b1cdbd2cSJim Jagielski } 736*b1cdbd2cSJim Jagielski 737*b1cdbd2cSJim Jagielski $systemcall = $msiinfo . " " . "\"" . $localmsidatabase . "\"" . " -w " . $wordcount . " -s " . "\"" . $lastprinted . "\"" . " -l $lastsavedby"; 738*b1cdbd2cSJim Jagielski $installer::logger::Lang->printf($systemcall); 739*b1cdbd2cSJim Jagielski $returnvalue = system($systemcall); 740*b1cdbd2cSJim Jagielski 741*b1cdbd2cSJim Jagielski if ($returnvalue) 742*b1cdbd2cSJim Jagielski { 743*b1cdbd2cSJim Jagielski $infoline = "ERROR: Could not execute $systemcall !\n"; 744*b1cdbd2cSJim Jagielski $installer::logger::Lang->print($infoline); 745*b1cdbd2cSJim Jagielski installer::exiter::exit_program($infoline, "write_sis_info"); 746*b1cdbd2cSJim Jagielski } 747*b1cdbd2cSJim Jagielski} 748*b1cdbd2cSJim Jagielski 749*b1cdbd2cSJim Jagielski#################################################### 750*b1cdbd2cSJim Jagielski# Detecting the directory with extensions 751*b1cdbd2cSJim Jagielski#################################################### 752*b1cdbd2cSJim Jagielski 753*b1cdbd2cSJim Jagielskisub get_extensions_dir 754*b1cdbd2cSJim Jagielski{ 755*b1cdbd2cSJim Jagielski my ( $unopkgfile ) = @_; 756*b1cdbd2cSJim Jagielski 757*b1cdbd2cSJim Jagielski my $localbranddir = $unopkgfile; 758*b1cdbd2cSJim Jagielski installer::pathanalyzer::get_path_from_fullqualifiedname(\$localbranddir); # "program" dir in brand layer 759*b1cdbd2cSJim Jagielski installer::pathanalyzer::get_path_from_fullqualifiedname(\$localbranddir); # root dir in brand layer 760*b1cdbd2cSJim Jagielski $localbranddir =~ s/\Q$installer::globals::separator\E\s*$//; 761*b1cdbd2cSJim Jagielski my $extensiondir = $localbranddir . $installer::globals::separator . "share" . $installer::globals::separator . "extensions"; 762*b1cdbd2cSJim Jagielski 763*b1cdbd2cSJim Jagielski return $extensiondir; 764*b1cdbd2cSJim Jagielski} 765*b1cdbd2cSJim Jagielski 766*b1cdbd2cSJim Jagielski############################################################## 767*b1cdbd2cSJim Jagielski# Removing all empty directories below a specified directory 768*b1cdbd2cSJim Jagielski############################################################## 769*b1cdbd2cSJim Jagielski 770*b1cdbd2cSJim Jagielskisub remove_empty_dirs_in_folder 771*b1cdbd2cSJim Jagielski{ 772*b1cdbd2cSJim Jagielski my ( $dir, $firstrun ) = @_; 773*b1cdbd2cSJim Jagielski 774*b1cdbd2cSJim Jagielski if ( $firstrun ) 775*b1cdbd2cSJim Jagielski { 776*b1cdbd2cSJim Jagielski print "Removing superfluous directories\n"; 777*b1cdbd2cSJim Jagielski } 778*b1cdbd2cSJim Jagielski 779*b1cdbd2cSJim Jagielski my @content = (); 780*b1cdbd2cSJim Jagielski 781*b1cdbd2cSJim Jagielski $dir =~ s/\Q$installer::globals::separator\E\s*$//; 782*b1cdbd2cSJim Jagielski 783*b1cdbd2cSJim Jagielski if ( -d $dir ) 784*b1cdbd2cSJim Jagielski { 785*b1cdbd2cSJim Jagielski opendir(DIR, $dir); 786*b1cdbd2cSJim Jagielski @content = readdir(DIR); 787*b1cdbd2cSJim Jagielski closedir(DIR); 788*b1cdbd2cSJim Jagielski 789*b1cdbd2cSJim Jagielski my $oneitem; 790*b1cdbd2cSJim Jagielski 791*b1cdbd2cSJim Jagielski foreach $oneitem (@content) 792*b1cdbd2cSJim Jagielski { 793*b1cdbd2cSJim Jagielski if ((!($oneitem eq ".")) && (!($oneitem eq ".."))) 794*b1cdbd2cSJim Jagielski { 795*b1cdbd2cSJim Jagielski my $item = $dir . $installer::globals::separator . $oneitem; 796*b1cdbd2cSJim Jagielski 797*b1cdbd2cSJim Jagielski if ( -d $item ) # recursive 798*b1cdbd2cSJim Jagielski { 799*b1cdbd2cSJim Jagielski remove_empty_dirs_in_folder($item, 0); 800*b1cdbd2cSJim Jagielski } 801*b1cdbd2cSJim Jagielski } 802*b1cdbd2cSJim Jagielski } 803*b1cdbd2cSJim Jagielski 804*b1cdbd2cSJim Jagielski # try to remove empty directory 805*b1cdbd2cSJim Jagielski my $returnvalue = rmdir $dir; 806*b1cdbd2cSJim Jagielski 807*b1cdbd2cSJim Jagielski # if ( $returnvalue ) { print "Successfully removed empty dir $dir\n"; } 808*b1cdbd2cSJim Jagielski } 809*b1cdbd2cSJim Jagielski} 810*b1cdbd2cSJim Jagielski 811*b1cdbd2cSJim Jagielski#################################################################################### 812*b1cdbd2cSJim Jagielski# Simulating an administrative installation 813*b1cdbd2cSJim Jagielski#################################################################################### 814*b1cdbd2cSJim Jagielski 815*b1cdbd2cSJim Jagielskisub make_admin_install 816*b1cdbd2cSJim Jagielski{ 817*b1cdbd2cSJim Jagielski my ($databasepath, $targetdir) = @_; 818*b1cdbd2cSJim Jagielski 819*b1cdbd2cSJim Jagielski # Create helper directory 820*b1cdbd2cSJim Jagielski 821*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("... installing %s in directory %s ...\n", 822*b1cdbd2cSJim Jagielski $databasepath, 823*b1cdbd2cSJim Jagielski $targetdir); 824*b1cdbd2cSJim Jagielski 825*b1cdbd2cSJim Jagielski my $helperdir = $targetdir . $installer::globals::separator . "installhelper"; 826*b1cdbd2cSJim Jagielski installer::systemactions::create_directory($helperdir); 827*b1cdbd2cSJim Jagielski 828*b1cdbd2cSJim Jagielski # Get File.idt, Component.idt and Directory.idt from database 829*b1cdbd2cSJim Jagielski 830*b1cdbd2cSJim Jagielski my $tablelist = "File Directory Component Registry"; 831*b1cdbd2cSJim Jagielski extract_tables_from_pcpfile($databasepath, $helperdir, $tablelist); 832*b1cdbd2cSJim Jagielski 833*b1cdbd2cSJim Jagielski # Unpack all cab files into $helperdir, cab files must be located next to msi database 834*b1cdbd2cSJim Jagielski my $installdir = $databasepath; 835*b1cdbd2cSJim Jagielski 836*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) { $installdir =~ s/\\/\//g; } # backslash to slash 837*b1cdbd2cSJim Jagielski 838*b1cdbd2cSJim Jagielski installer::pathanalyzer::get_path_from_fullqualifiedname(\$installdir); 839*b1cdbd2cSJim Jagielski 840*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) { $installdir =~ s/\//\\/g; } # slash to backslash 841*b1cdbd2cSJim Jagielski 842*b1cdbd2cSJim Jagielski my $databasefilename = $databasepath; 843*b1cdbd2cSJim Jagielski installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$databasefilename); 844*b1cdbd2cSJim Jagielski 845*b1cdbd2cSJim Jagielski my $cabfiles = installer::systemactions::find_file_with_file_extension("cab", $installdir); 846*b1cdbd2cSJim Jagielski 847*b1cdbd2cSJim Jagielski if ( $#{$cabfiles} < 0 ) { installer::exiter::exit_program("ERROR: Did not find any cab file in directory $installdir", "make_admin_install"); } 848*b1cdbd2cSJim Jagielski 849*b1cdbd2cSJim Jagielski # Set unpackdir 850*b1cdbd2cSJim Jagielski my $unpackdir = $helperdir . $installer::globals::separator . "unpack"; 851*b1cdbd2cSJim Jagielski installer::systemactions::create_directory($unpackdir); 852*b1cdbd2cSJim Jagielski 853*b1cdbd2cSJim Jagielski for ( my $i = 0; $i <= $#{$cabfiles}; $i++ ) 854*b1cdbd2cSJim Jagielski { 855*b1cdbd2cSJim Jagielski my $cabfile = ""; 856*b1cdbd2cSJim Jagielski if ( $^O =~ /cygwin/i ) 857*b1cdbd2cSJim Jagielski { 858*b1cdbd2cSJim Jagielski $cabfile = $installdir . ${$cabfiles}[$i]; 859*b1cdbd2cSJim Jagielski } 860*b1cdbd2cSJim Jagielski else 861*b1cdbd2cSJim Jagielski { 862*b1cdbd2cSJim Jagielski $cabfile = $installdir . $installer::globals::separator . ${$cabfiles}[$i]; 863*b1cdbd2cSJim Jagielski } 864*b1cdbd2cSJim Jagielski unpack_cabinet_file($cabfile, $unpackdir); 865*b1cdbd2cSJim Jagielski } 866*b1cdbd2cSJim Jagielski 867*b1cdbd2cSJim Jagielski # Reading tables 868*b1cdbd2cSJim Jagielski my $filename = $helperdir . $installer::globals::separator . "Directory.idt"; 869*b1cdbd2cSJim Jagielski my $filecontent = installer::files::read_file($filename); 870*b1cdbd2cSJim Jagielski my $dirhash = analyze_directory_file($filecontent); 871*b1cdbd2cSJim Jagielski 872*b1cdbd2cSJim Jagielski $filename = $helperdir . $installer::globals::separator . "Component.idt"; 873*b1cdbd2cSJim Jagielski my $componentfilecontent = installer::files::read_file($filename); 874*b1cdbd2cSJim Jagielski my $componenthash = analyze_component_file($componentfilecontent); 875*b1cdbd2cSJim Jagielski 876*b1cdbd2cSJim Jagielski $filename = $helperdir . $installer::globals::separator . "File.idt"; 877*b1cdbd2cSJim Jagielski $filecontent = installer::files::read_file($filename); 878*b1cdbd2cSJim Jagielski my ( $filehash, $fileorder, $maxsequence ) = analyze_file_file($filecontent); 879*b1cdbd2cSJim Jagielski 880*b1cdbd2cSJim Jagielski # Creating the directory structure 881*b1cdbd2cSJim Jagielski my $fullpathhash = create_directory_structure($dirhash, $targetdir); 882*b1cdbd2cSJim Jagielski 883*b1cdbd2cSJim Jagielski # Copying files 884*b1cdbd2cSJim Jagielski my $unopkgfile = copy_files_into_directory_structure($fileorder, $filehash, $componenthash, $fullpathhash, $maxsequence, $unpackdir, $installdir, $dirhash); 885*b1cdbd2cSJim Jagielski 886*b1cdbd2cSJim Jagielski my $msidatabase = $targetdir . $installer::globals::separator . $databasefilename; 887*b1cdbd2cSJim Jagielski installer::systemactions::copy_one_file($databasepath, $msidatabase); 888*b1cdbd2cSJim Jagielski 889*b1cdbd2cSJim Jagielski if ( $unopkgfile ne "" ) 890*b1cdbd2cSJim Jagielski { 891*b1cdbd2cSJim Jagielski # Removing empty dirs in extension folder 892*b1cdbd2cSJim Jagielski my $extensionfolder = get_extensions_dir($unopkgfile); 893*b1cdbd2cSJim Jagielski if ( -d $extensionfolder ) { remove_empty_dirs_in_folder($extensionfolder, 1); } 894*b1cdbd2cSJim Jagielski } 895*b1cdbd2cSJim Jagielski 896*b1cdbd2cSJim Jagielski # Editing registry table because of wrong Property value 897*b1cdbd2cSJim Jagielski # my $registryfilename = $helperdir . $installer::globals::separator . "Registry.idt"; 898*b1cdbd2cSJim Jagielski # my $componentfilename = $helperdir . $installer::globals::separator . "Component.idt"; 899*b1cdbd2cSJim Jagielski # my $componentkeypathhash = analyze_keypath_component_file($componentfilecontent); 900*b1cdbd2cSJim Jagielski 901*b1cdbd2cSJim Jagielski # my $registryfilecontent = installer::files::read_file($registryfilename); 902*b1cdbd2cSJim Jagielski # my $registryhash = analyze_registry_file($registryfilecontent); 903*b1cdbd2cSJim Jagielski 904*b1cdbd2cSJim Jagielski # $registryfilecontent = remove_properties_from_registry_table($registryhash, $componentkeypathhash, $registryfilecontent); 905*b1cdbd2cSJim Jagielski 906*b1cdbd2cSJim Jagielski # installer::files::save_file($registryfilename, $registryfilecontent); 907*b1cdbd2cSJim Jagielski # $tablelist = "Registry"; 908*b1cdbd2cSJim Jagielski # include_tables_into_pcpfile($msidatabase, $helperdir, $tablelist); 909*b1cdbd2cSJim Jagielski 910*b1cdbd2cSJim Jagielski # Saving info in Summary Information Stream of msi database (required for following patches) 911*b1cdbd2cSJim Jagielski write_sis_info($msidatabase); 912*b1cdbd2cSJim Jagielski 913*b1cdbd2cSJim Jagielski return $msidatabase; 914*b1cdbd2cSJim Jagielski} 915*b1cdbd2cSJim Jagielski 916*b1cdbd2cSJim Jagielski1; 917