| Filename | /cygdrive/c/lo/libo-master/instsetoo_native/util/C:/lo/libo-master/solenv/bin/modules/installer/windows/msp.pm |
| Statements | Executed 25 statements in 16.9ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 5.98ms | 6.56ms | installer::windows::msp::BEGIN@39 |
| 1 | 1 | 1 | 5.75ms | 6.24ms | installer::windows::msp::BEGIN@41 |
| 1 | 1 | 1 | 446µs | 543µs | installer::windows::msp::BEGIN@30 |
| 1 | 1 | 1 | 21µs | 24µs | installer::windows::msp::BEGIN@40 |
| 1 | 1 | 1 | 18µs | 20µs | installer::windows::msp::BEGIN@31 |
| 1 | 1 | 1 | 17µs | 18µs | installer::windows::msp::BEGIN@38 |
| 1 | 1 | 1 | 17µs | 19µs | installer::windows::msp::BEGIN@32 |
| 1 | 1 | 1 | 17µs | 19µs | installer::windows::msp::BEGIN@34 |
| 1 | 1 | 1 | 16µs | 18µs | installer::windows::msp::BEGIN@33 |
| 1 | 1 | 1 | 16µs | 18µs | installer::windows::msp::BEGIN@37 |
| 1 | 1 | 1 | 15µs | 42µs | installer::windows::msp::BEGIN@36 |
| 1 | 1 | 1 | 15µs | 17µs | installer::windows::msp::BEGIN@35 |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::analyze_msimsp_logfile |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_imagefamilies_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_patchmetadata_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_patchsequence_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_properties_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_targetimages_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::change_upgradedimages_table |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::check_and_save_tables |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::collect_patch_file_destinations |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::convert_unicode_to_ascii |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::correct_langs |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::correct_patch |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::create_langstring |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::create_msp_patch |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::edit_tables |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::execute_msimsp |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::extract_all_tables_from_pcpfile |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_filesequencestart |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_first_path_segment |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_patchid_from_list |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_patchsequence |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_patchtime_value |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_requiredpatchfile_from_list |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::get_supersede |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::include_tables_into_pcpfile |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::install_installation_sets |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::prepare_path_in_nopatchfilehash |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::set_mspfilename |
| 0 | 0 | 0 | 0s | 0s | installer::windows::msp::synchronize_installation_sets |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | #************************************************************************* | ||||
| 2 | # | ||||
| 3 | # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||||
| 4 | # | ||||
| 5 | # Copyright 2000, 2010 Oracle and/or its affiliates. | ||||
| 6 | # | ||||
| 7 | # OpenOffice.org - a multi-platform office productivity suite | ||||
| 8 | # | ||||
| 9 | # This file is part of OpenOffice.org. | ||||
| 10 | # | ||||
| 11 | # OpenOffice.org is free software: you can redistribute it and/or modify | ||||
| 12 | # it under the terms of the GNU Lesser General Public License version 3 | ||||
| 13 | # only, as published by the Free Software Foundation. | ||||
| 14 | # | ||||
| 15 | # OpenOffice.org is distributed in the hope that it will be useful, | ||||
| 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| 18 | # GNU Lesser General Public License version 3 for more details | ||||
| 19 | # (a copy is included in the LICENSE file that accompanied this code). | ||||
| 20 | # | ||||
| 21 | # You should have received a copy of the GNU Lesser General Public License | ||||
| 22 | # version 3 along with OpenOffice.org. If not, see | ||||
| 23 | # <http://www.openoffice.org/license.html> | ||||
| 24 | # for a copy of the LGPLv3 License. | ||||
| 25 | # | ||||
| 26 | #************************************************************************* | ||||
| 27 | |||||
| 28 | package installer::windows::msp; | ||||
| 29 | |||||
| 30 | 2 | 67µs | 2 | 640µs | # spent 543µs (446+97) within installer::windows::msp::BEGIN@30 which was called:
# once (446µs+97µs) by installer::BEGIN@76 at line 30 # spent 543µs making 1 call to installer::windows::msp::BEGIN@30
# spent 98µs making 1 call to Exporter::import |
| 31 | 2 | 56µs | 2 | 23µs | # spent 20µs (18+3) within installer::windows::msp::BEGIN@31 which was called:
# once (18µs+3µs) by installer::BEGIN@76 at line 31 # spent 20µs making 1 call to installer::windows::msp::BEGIN@31
# spent 3µs making 1 call to UNIVERSAL::import |
| 32 | 2 | 54µs | 2 | 21µs | # spent 19µs (17+2) within installer::windows::msp::BEGIN@32 which was called:
# once (17µs+2µs) by installer::BEGIN@76 at line 32 # spent 19µs making 1 call to installer::windows::msp::BEGIN@32
# spent 2µs making 1 call to UNIVERSAL::import |
| 33 | 2 | 55µs | 2 | 20µs | # spent 18µs (16+2) within installer::windows::msp::BEGIN@33 which was called:
# once (16µs+2µs) by installer::BEGIN@76 at line 33 # spent 18µs making 1 call to installer::windows::msp::BEGIN@33
# spent 2µs making 1 call to UNIVERSAL::import |
| 34 | 2 | 54µs | 2 | 22µs | # spent 19µs (17+3) within installer::windows::msp::BEGIN@34 which was called:
# once (17µs+3µs) by installer::BEGIN@76 at line 34 # spent 19µs making 1 call to installer::windows::msp::BEGIN@34
# spent 3µs making 1 call to UNIVERSAL::import |
| 35 | 2 | 52µs | 2 | 19µs | # spent 17µs (15+2) within installer::windows::msp::BEGIN@35 which was called:
# once (15µs+2µs) by installer::BEGIN@76 at line 35 # spent 17µs making 1 call to installer::windows::msp::BEGIN@35
# spent 2µs making 1 call to UNIVERSAL::import |
| 36 | 2 | 56µs | 2 | 69µs | # spent 42µs (15+27) within installer::windows::msp::BEGIN@36 which was called:
# once (15µs+27µs) by installer::BEGIN@76 at line 36 # spent 42µs making 1 call to installer::windows::msp::BEGIN@36
# spent 27µs making 1 call to Exporter::import |
| 37 | 2 | 54µs | 2 | 20µs | # spent 18µs (16+2) within installer::windows::msp::BEGIN@37 which was called:
# once (16µs+2µs) by installer::BEGIN@76 at line 37 # spent 18µs making 1 call to installer::windows::msp::BEGIN@37
# spent 2µs making 1 call to UNIVERSAL::import |
| 38 | 2 | 52µs | 2 | 20µs | # spent 18µs (17+1) within installer::windows::msp::BEGIN@38 which was called:
# once (17µs+1µs) by installer::BEGIN@76 at line 38 # spent 18µs making 1 call to installer::windows::msp::BEGIN@38
# spent 2µs making 1 call to UNIVERSAL::import |
| 39 | 2 | 1.21ms | 2 | 6.57ms | # spent 6.56ms (5.98+583µs) within installer::windows::msp::BEGIN@39 which was called:
# once (5.98ms+583µs) by installer::BEGIN@76 at line 39 # spent 6.56ms making 1 call to installer::windows::msp::BEGIN@39
# spent 10µs making 1 call to UNIVERSAL::import |
| 40 | 2 | 86µs | 2 | 27µs | # spent 24µs (21+3) within installer::windows::msp::BEGIN@40 which was called:
# once (21µs+3µs) by installer::BEGIN@76 at line 40 # spent 24µs making 1 call to installer::windows::msp::BEGIN@40
# spent 3µs making 1 call to UNIVERSAL::import |
| 41 | 2 | 15.1ms | 2 | 6.24ms | # spent 6.24ms (5.75+487µs) within installer::windows::msp::BEGIN@41 which was called:
# once (5.75ms+487µs) by installer::BEGIN@76 at line 41 # spent 6.24ms making 1 call to installer::windows::msp::BEGIN@41
# spent 7µs making 1 call to UNIVERSAL::import |
| 42 | |||||
| 43 | ################################################################################# | ||||
| 44 | # Making all required administrative installations | ||||
| 45 | ################################################################################# | ||||
| 46 | |||||
| 47 | sub install_installation_sets | ||||
| 48 | { | ||||
| 49 | my ($installationdir) = @_; | ||||
| 50 | |||||
| 51 | # Finding the msi database in the new installation set, that is located in $installationdir | ||||
| 52 | |||||
| 53 | my $msifiles = installer::systemactions::find_file_with_file_extension("msi", $installationdir); | ||||
| 54 | |||||
| 55 | if ( $#{$msifiles} < 0 ) { installer::exiter::exit_program("ERROR: Did not find msi database in directory $installationdir", "create_msp_patch"); } | ||||
| 56 | if ( $#{$msifiles} > 0 ) { installer::exiter::exit_program("ERROR: Did find more than one msi database in directory $installationdir", "create_msp_patch"); } | ||||
| 57 | |||||
| 58 | my $newinstallsetdatabasepath = $installationdir . $installer::globals::separator . ${$msifiles}[0]; | ||||
| 59 | my $oldinstallsetdatabasepath = $installer::globals::updatedatabasepath; | ||||
| 60 | |||||
| 61 | # Creating temp directory again | ||||
| 62 | installer::systemactions::create_directory_structure($installer::globals::temppath); | ||||
| 63 | |||||
| 64 | # Creating old installation directory | ||||
| 65 | my $dirname = "admin"; | ||||
| 66 | my $installpath = $installer::globals::temppath . $installer::globals::separator . $dirname; | ||||
| 67 | if ( ! -d $installpath) { installer::systemactions::create_directory($installpath); } | ||||
| 68 | |||||
| 69 | my $oldinstallpath = $installpath . $installer::globals::separator . "old"; | ||||
| 70 | my $newinstallpath = $installpath . $installer::globals::separator . "new"; | ||||
| 71 | |||||
| 72 | if ( ! -d $oldinstallpath) { installer::systemactions::create_directory($oldinstallpath); } | ||||
| 73 | if ( ! -d $newinstallpath) { installer::systemactions::create_directory($newinstallpath); } | ||||
| 74 | |||||
| 75 | my $olddatabase = installer::windows::admin::make_admin_install($oldinstallsetdatabasepath, $oldinstallpath); | ||||
| 76 | my $newdatabase = installer::windows::admin::make_admin_install($newinstallsetdatabasepath, $newinstallpath); | ||||
| 77 | |||||
| 78 | if ( $^O =~ /cygwin/i ) { | ||||
| 79 | $olddatabase = qx{cygpath -w "$olddatabase"}; | ||||
| 80 | $olddatabase =~ s/\s*$//g; | ||||
| 81 | $newdatabase = qx{cygpath -w "$newdatabase"}; | ||||
| 82 | $newdatabase =~ s/\s*$//g; | ||||
| 83 | } | ||||
| 84 | |||||
| 85 | return ($olddatabase, $newdatabase); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | ################################################################################# | ||||
| 89 | # Collecting the destinations of all files with flag PATCH in a hash. | ||||
| 90 | ################################################################################# | ||||
| 91 | |||||
| 92 | sub collect_patch_file_destinations | ||||
| 93 | { | ||||
| 94 | my ( $filesarray ) = @_; | ||||
| 95 | |||||
| 96 | my %patchfiledestinations = (); | ||||
| 97 | my %nopatchfiledestinations = (); | ||||
| 98 | my $patchcounter = 0; | ||||
| 99 | my $nopatchcounter = 0; | ||||
| 100 | |||||
| 101 | for ( my $i = 0; $i <= $#{$filesarray}; $i++ ) | ||||
| 102 | { | ||||
| 103 | my $onefile = ${$filesarray}[$i]; | ||||
| 104 | my $styles = ""; | ||||
| 105 | |||||
| 106 | if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'} }; | ||||
| 107 | |||||
| 108 | if ( $styles =~ /\bPATCH\b/ ) | ||||
| 109 | { | ||||
| 110 | $patchfiledestinations{$onefile->{'destination'}} = 1; | ||||
| 111 | $patchcounter++; | ||||
| 112 | } | ||||
| 113 | else | ||||
| 114 | { | ||||
| 115 | $nopatchfiledestinations{$onefile->{'destination'}} = 1; | ||||
| 116 | $nopatchcounter++; | ||||
| 117 | } | ||||
| 118 | } | ||||
| 119 | |||||
| 120 | return (\%patchfiledestinations, \%nopatchfiledestinations, $patchcounter, $nopatchcounter); | ||||
| 121 | } | ||||
| 122 | |||||
| 123 | ################################################################################# | ||||
| 124 | # Returning the first path segment of a path | ||||
| 125 | ################################################################################# | ||||
| 126 | |||||
| 127 | sub get_first_path_segment | ||||
| 128 | { | ||||
| 129 | my ( $path ) = @_; | ||||
| 130 | |||||
| 131 | my $firstsegment = ""; | ||||
| 132 | my $remainder = $path; | ||||
| 133 | |||||
| 134 | if ( $path =~ /^\s*(.*?)[\/\\](.*)\s*$/ ) | ||||
| 135 | { | ||||
| 136 | $firstsegment = $1; | ||||
| 137 | $remainder = $2; | ||||
| 138 | } | ||||
| 139 | |||||
| 140 | return ($firstsegment, $remainder); | ||||
| 141 | } | ||||
| 142 | |||||
| 143 | ################################################################################# | ||||
| 144 | # Finding the flexible path in the destinations, that are saved in | ||||
| 145 | # the hash $nopatchfiledestinations. | ||||
| 146 | ################################################################################# | ||||
| 147 | |||||
| 148 | sub prepare_path_in_nopatchfilehash | ||||
| 149 | { | ||||
| 150 | my ($nopatchfiledestinations, $newpath) = @_; | ||||
| 151 | |||||
| 152 | my $infoline = ""; | ||||
| 153 | my $flexiblepath = ""; | ||||
| 154 | my $found = 0; | ||||
| 155 | my %checked_destinations = (); | ||||
| 156 | |||||
| 157 | foreach my $onedestination ( keys %{$nopatchfiledestinations} ) | ||||
| 158 | { | ||||
| 159 | $flexiblepath = ""; | ||||
| 160 | $found = 0; | ||||
| 161 | |||||
| 162 | my $found_first_segement = 1; | ||||
| 163 | my $firstsegement = ""; | ||||
| 164 | my $fixedpath = $onedestination; | ||||
| 165 | my $testfile = $newpath . $installer::globals::separator . $fixedpath; | ||||
| 166 | |||||
| 167 | while (( ! -f $testfile ) && ( $found_first_segement )) | ||||
| 168 | { | ||||
| 169 | $firstsegement = ""; | ||||
| 170 | ( $firstsegement, $fixedpath ) = get_first_path_segment($fixedpath); | ||||
| 171 | |||||
| 172 | if ( $firstsegement ne "" ) | ||||
| 173 | { | ||||
| 174 | $found_first_segement = 1; | ||||
| 175 | $flexiblepath = $flexiblepath . $firstsegement . $installer::globals::separator; | ||||
| 176 | } | ||||
| 177 | else | ||||
| 178 | { | ||||
| 179 | $found_first_segement = 0; | ||||
| 180 | } | ||||
| 181 | |||||
| 182 | $testfile = $newpath . $installer::globals::separator . $fixedpath; | ||||
| 183 | } | ||||
| 184 | |||||
| 185 | if ( -f $testfile ) { $found = 1; } | ||||
| 186 | |||||
| 187 | if ( $found ) { last; } | ||||
| 188 | } | ||||
| 189 | |||||
| 190 | if ( ! $found ) { installer::exiter::exit_program("ERROR: Could not determine flexible destination path for msp patch creation!", "prepare_path_in_nopatchfilehash"); } | ||||
| 191 | |||||
| 192 | $infoline = "Setting flexible path for msp creation: $flexiblepath\n"; | ||||
| 193 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 194 | |||||
| 195 | foreach my $onedestination ( keys %{$nopatchfiledestinations} ) | ||||
| 196 | { | ||||
| 197 | $onedestination =~ s/^\s*\Q$flexiblepath\E//; | ||||
| 198 | $checked_destinations{$onedestination} = 1; | ||||
| 199 | } | ||||
| 200 | |||||
| 201 | return \%checked_destinations; | ||||
| 202 | } | ||||
| 203 | |||||
| 204 | ################################################################################# | ||||
| 205 | # Synchronizing the two installed products in that way, that only | ||||
| 206 | # files with flag PATCH are different. | ||||
| 207 | ################################################################################# | ||||
| 208 | |||||
| 209 | sub synchronize_installation_sets | ||||
| 210 | { | ||||
| 211 | my ($olddatabase, $newdatabase, $filesarray) = @_; | ||||
| 212 | |||||
| 213 | my $infoline = "\nSynchronizing installed products because of PATCH flag\n"; | ||||
| 214 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 215 | $infoline = "Old product: $olddatabase\n"; | ||||
| 216 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 217 | $infoline = "New product: $newdatabase\n"; | ||||
| 218 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 219 | |||||
| 220 | my ( $patchfiledestinations, $nopatchfiledestinations, $patchfilecounter, $nopatchfilecounter ) = collect_patch_file_destinations($filesarray); | ||||
| 221 | |||||
| 222 | $infoline = "Number of files with PATCH flag: $patchfilecounter\n"; | ||||
| 223 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 224 | |||||
| 225 | $infoline = "Number of files without PATCH flag: $nopatchfilecounter\n"; | ||||
| 226 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 227 | |||||
| 228 | foreach my $localfile ( sort keys %{$patchfiledestinations} ) | ||||
| 229 | { | ||||
| 230 | $infoline = "\tPATCH file: $localfile\n"; | ||||
| 231 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 232 | } | ||||
| 233 | |||||
| 234 | my $oldpath = $olddatabase; | ||||
| 235 | if ( $^O =~ /cygwin/i ) { $oldpath =~ s/\\/\//g; } | ||||
| 236 | installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldpath); | ||||
| 237 | $oldpath =~ s/\\\s*$//; | ||||
| 238 | $oldpath =~ s/\/\s*$//; | ||||
| 239 | |||||
| 240 | my $newpath = $newdatabase; | ||||
| 241 | if ( $^O =~ /cygwin/i ) { $newpath =~ s/\\/\//g; } | ||||
| 242 | installer::pathanalyzer::get_path_from_fullqualifiedname(\$newpath); | ||||
| 243 | $newpath =~ s/\\\s*$//; | ||||
| 244 | $newpath =~ s/\/\s*$//; | ||||
| 245 | |||||
| 246 | # The destination path is not correct. destinations in the hash contain | ||||
| 247 | # the flexible installation path, that is not part in the administrative installation | ||||
| 248 | $nopatchfiledestinations = prepare_path_in_nopatchfilehash($nopatchfiledestinations, $newpath); | ||||
| 249 | |||||
| 250 | foreach my $onedestination ( keys %{$nopatchfiledestinations} ) | ||||
| 251 | { | ||||
| 252 | my $source = $oldpath . $installer::globals::separator . $onedestination; | ||||
| 253 | my $dest = $newpath . $installer::globals::separator . $onedestination; | ||||
| 254 | |||||
| 255 | if ( -f $source ) | ||||
| 256 | { | ||||
| 257 | if ( -f $dest ) | ||||
| 258 | { | ||||
| 259 | my $copyreturn = copy($source, $dest); | ||||
| 260 | # installer::systemactions::copy_one_file($source, $dest); | ||||
| 261 | # $infoline = "Synchronizing file: $source to $dest\n"; | ||||
| 262 | # push( @installer::globals::logfileinfo, $infoline); | ||||
| 263 | } | ||||
| 264 | else | ||||
| 265 | { | ||||
| 266 | $infoline = "Not synchronizing. Destination file \"$dest\" does not exist.\n"; | ||||
| 267 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 268 | } | ||||
| 269 | } | ||||
| 270 | else | ||||
| 271 | { | ||||
| 272 | $infoline = "Not synchronizing. Source file \"$source\" does not exist.\n"; | ||||
| 273 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 274 | } | ||||
| 275 | } | ||||
| 276 | } | ||||
| 277 | |||||
| 278 | ################################################################################# | ||||
| 279 | # Extracting all tables from a pcp file | ||||
| 280 | ################################################################################# | ||||
| 281 | |||||
| 282 | sub extract_all_tables_from_pcpfile | ||||
| 283 | { | ||||
| 284 | my ($fullpcpfilepath, $workdir) = @_; | ||||
| 285 | |||||
| 286 | my $msidb = "msidb.exe"; # Has to be in the path | ||||
| 287 | my $infoline = ""; | ||||
| 288 | my $systemcall = ""; | ||||
| 289 | my $returnvalue = ""; | ||||
| 290 | my $extraslash = ""; # Has to be set for non-ActiveState perl | ||||
| 291 | |||||
| 292 | my $localfullpcpfile = $fullpcpfilepath; | ||||
| 293 | my $localworkdir = $workdir; | ||||
| 294 | |||||
| 295 | if ( $^O =~ /cygwin/i ) { | ||||
| 296 | # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) | ||||
| 297 | $localfullpcpfile =~ s/\//\\\\/g; | ||||
| 298 | $localworkdir =~ s/\//\\\\/g; | ||||
| 299 | $extraslash = "\\"; | ||||
| 300 | } | ||||
| 301 | if ( $^O =~ /linux/i ) { | ||||
| 302 | $extraslash = "\\"; | ||||
| 303 | } | ||||
| 304 | |||||
| 305 | # Export of all tables by using "*" | ||||
| 306 | |||||
| 307 | $systemcall = $msidb . " -d " . $localfullpcpfile . " -f " . $localworkdir . " -e " . $extraslash . "*"; | ||||
| 308 | $returnvalue = system($systemcall); | ||||
| 309 | |||||
| 310 | $infoline = "Systemcall: $systemcall\n"; | ||||
| 311 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 312 | |||||
| 313 | if ($returnvalue) | ||||
| 314 | { | ||||
| 315 | $infoline = "ERROR: Could not execute $systemcall !\n"; | ||||
| 316 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 317 | installer::exiter::exit_program("ERROR: Could not exclude tables from pcp file: $fullpcpfilepath !", "extract_all_tables_from_msidatabase"); | ||||
| 318 | } | ||||
| 319 | else | ||||
| 320 | { | ||||
| 321 | $infoline = "Success: Executed $systemcall successfully!\n"; | ||||
| 322 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 323 | } | ||||
| 324 | } | ||||
| 325 | |||||
| 326 | ################################################################################# | ||||
| 327 | # Include tables into a pcp file | ||||
| 328 | ################################################################################# | ||||
| 329 | |||||
| 330 | sub include_tables_into_pcpfile | ||||
| 331 | { | ||||
| 332 | my ($fullpcpfilepath, $workdir, $tables) = @_; | ||||
| 333 | |||||
| 334 | my $msidb = "msidb.exe"; # Has to be in the path | ||||
| 335 | my $infoline = ""; | ||||
| 336 | my $systemcall = ""; | ||||
| 337 | my $returnvalue = ""; | ||||
| 338 | |||||
| 339 | # Make all table 8+3 conform | ||||
| 340 | my $alltables = installer::converter::convert_stringlist_into_array(\$tables, " "); | ||||
| 341 | |||||
| 342 | for ( my $i = 0; $i <= $#{$alltables}; $i++ ) | ||||
| 343 | { | ||||
| 344 | my $tablename = ${$alltables}[$i]; | ||||
| 345 | $tablename =~ s/\s*$//; | ||||
| 346 | my $namelength = length($tablename); | ||||
| 347 | if ( $namelength > 8 ) | ||||
| 348 | { | ||||
| 349 | my $newtablename = substr($tablename, 0, 8); # name, offset, length | ||||
| 350 | my $oldfile = $workdir . $installer::globals::separator . $tablename . ".idt"; | ||||
| 351 | my $newfile = $workdir . $installer::globals::separator . $newtablename . ".idt"; | ||||
| 352 | if ( -f $newfile ) { unlink $newfile; } | ||||
| 353 | installer::systemactions::copy_one_file($oldfile, $newfile); | ||||
| 354 | } | ||||
| 355 | } | ||||
| 356 | |||||
| 357 | # Import of tables | ||||
| 358 | |||||
| 359 | my $localworkdir = $workdir; | ||||
| 360 | my $localfullpcpfilepath = $fullpcpfilepath; | ||||
| 361 | |||||
| 362 | if ( $^O =~ /cygwin/i ) { | ||||
| 363 | # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) | ||||
| 364 | $localfullpcpfilepath =~ s/\//\\\\/g; | ||||
| 365 | $localworkdir =~ s/\//\\\\/g; | ||||
| 366 | } | ||||
| 367 | |||||
| 368 | $systemcall = $msidb . " -d " . $localfullpcpfilepath . " -f " . $localworkdir . " -i " . $tables; | ||||
| 369 | |||||
| 370 | $returnvalue = system($systemcall); | ||||
| 371 | |||||
| 372 | $infoline = "Systemcall: $systemcall\n"; | ||||
| 373 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 374 | |||||
| 375 | if ($returnvalue) | ||||
| 376 | { | ||||
| 377 | $infoline = "ERROR: Could not execute $systemcall !\n"; | ||||
| 378 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 379 | installer::exiter::exit_program("ERROR: Could not include tables into pcp file: $fullpcpfilepath !", "include_tables_into_pcpfile"); | ||||
| 380 | } | ||||
| 381 | else | ||||
| 382 | { | ||||
| 383 | $infoline = "Success: Executed $systemcall successfully!\n"; | ||||
| 384 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 385 | } | ||||
| 386 | } | ||||
| 387 | |||||
| 388 | ################################################################################# | ||||
| 389 | # Calling msimsp.exe | ||||
| 390 | ################################################################################# | ||||
| 391 | |||||
| 392 | sub execute_msimsp | ||||
| 393 | { | ||||
| 394 | my ($fullpcpfilename, $mspfilename, $localmspdir) = @_; | ||||
| 395 | |||||
| 396 | my $msimsp = "msimsp.exe"; # Has to be in the path | ||||
| 397 | my $infoline = ""; | ||||
| 398 | my $systemcall = ""; | ||||
| 399 | my $returnvalue = ""; | ||||
| 400 | my $logfilename = $localmspdir . $installer::globals::separator . "msimsp.log"; | ||||
| 401 | |||||
| 402 | # Using a specific temp for each msimsp.exe process | ||||
| 403 | # Creating temp directory again (should already have happened) | ||||
| 404 | installer::systemactions::create_directory_structure($installer::globals::temppath); | ||||
| 405 | |||||
| 406 | # Creating old installation directory | ||||
| 407 | my $dirname = "msimsptemp"; | ||||
| 408 | my $msimsptemppath = $installer::globals::temppath . $installer::globals::separator . $dirname; | ||||
| 409 | if ( ! -d $msimsptemppath) { installer::systemactions::create_directory($msimsptemppath); } | ||||
| 410 | |||||
| 411 | # r:\msvc9p\PlatformSDK\v6.1\bin\msimsp.exe -s c:\patch\hotfix_qfe1.pcp -p c:\patch\patch_ooo3_m2_m3.msp -l c:\patch\patch_ooo3_m2_m3.log | ||||
| 412 | |||||
| 413 | if ( -f $logfilename ) { unlink $logfilename; } | ||||
| 414 | |||||
| 415 | my $localfullpcpfilename = $fullpcpfilename; | ||||
| 416 | my $localmspfilename = $mspfilename; | ||||
| 417 | my $locallogfilename = $logfilename; | ||||
| 418 | my $localmsimsptemppath = $msimsptemppath; | ||||
| 419 | |||||
| 420 | if ( $^O =~ /cygwin/i ) { | ||||
| 421 | # msimsp.exe really wants backslashes. (And double escaping because system() expands the string.) | ||||
| 422 | $localfullpcpfilename =~ s/\//\\\\/g; | ||||
| 423 | $locallogfilename =~ s/\//\\\\/g; | ||||
| 424 | |||||
| 425 | $localmspfilename =~ s/\\/\\\\/g; # path already contains backslash | ||||
| 426 | |||||
| 427 | $localmsimsptemppath = qx{cygpath -w "$localmsimsptemppath"}; | ||||
| 428 | $localmsimsptemppath =~ s/\\/\\\\/g; | ||||
| 429 | $localmsimsptemppath =~ s/\s*$//g; | ||||
| 430 | } | ||||
| 431 | |||||
| 432 | $systemcall = $msimsp . " -s " . $localfullpcpfilename . " -p " . $localmspfilename . " -l " . $locallogfilename . " -f " . $localmsimsptemppath; | ||||
| 433 | installer::logger::print_message( "... $systemcall ...\n" ); | ||||
| 434 | |||||
| 435 | $returnvalue = system($systemcall); | ||||
| 436 | |||||
| 437 | $infoline = "Systemcall: $systemcall\n"; | ||||
| 438 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 439 | |||||
| 440 | if ($returnvalue) | ||||
| 441 | { | ||||
| 442 | $infoline = "ERROR: Could not execute $systemcall !\n"; | ||||
| 443 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 444 | installer::exiter::exit_program("ERROR: Could not execute $systemcall !", "execute_msimsp"); | ||||
| 445 | } | ||||
| 446 | else | ||||
| 447 | { | ||||
| 448 | $infoline = "Success: Executed $systemcall successfully!\n"; | ||||
| 449 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 450 | } | ||||
| 451 | |||||
| 452 | return $logfilename; | ||||
| 453 | } | ||||
| 454 | |||||
| 455 | #################################################################### | ||||
| 456 | # Checking existence and saving all tables, that need to be edited | ||||
| 457 | #################################################################### | ||||
| 458 | |||||
| 459 | sub check_and_save_tables | ||||
| 460 | { | ||||
| 461 | my ($tablelist, $workdir) = @_; | ||||
| 462 | |||||
| 463 | my $tables = installer::converter::convert_stringlist_into_array(\$tablelist, " "); | ||||
| 464 | |||||
| 465 | for ( my $i = 0; $i <= $#{$tables}; $i++ ) | ||||
| 466 | { | ||||
| 467 | my $filename = ${$tables}[$i]; | ||||
| 468 | $filename =~ s/\s*$//; | ||||
| 469 | my $fullfilename = $workdir . $installer::globals::separator . $filename . ".idt"; | ||||
| 470 | |||||
| 471 | if ( ! -f $fullfilename ) { installer::exiter::exit_program("ERROR: Required idt file could not be found: \"$fullfilename\"!", "check_and_save_tables"); } | ||||
| 472 | |||||
| 473 | my $savfilename = $fullfilename . ".sav"; | ||||
| 474 | installer::systemactions::copy_one_file($fullfilename, $savfilename); | ||||
| 475 | } | ||||
| 476 | } | ||||
| 477 | |||||
| 478 | #################################################################### | ||||
| 479 | # Setting the languages for the service packs | ||||
| 480 | #################################################################### | ||||
| 481 | |||||
| 482 | sub create_langstring | ||||
| 483 | { | ||||
| 484 | my ( $languagesarrayref ) = @_; | ||||
| 485 | |||||
| 486 | my $langstring = ""; | ||||
| 487 | for ( my $i = 0; $i <= $#{$languagesarrayref}; $i++ ) { $langstring = $langstring . "_" . ${$languagesarrayref}[$i]; } | ||||
| 488 | |||||
| 489 | return $langstring; | ||||
| 490 | } | ||||
| 491 | |||||
| 492 | #################################################################### | ||||
| 493 | # Setting the name of the msp database | ||||
| 494 | #################################################################### | ||||
| 495 | |||||
| 496 | sub set_mspfilename | ||||
| 497 | { | ||||
| 498 | my ($allvariables, $mspdir, $languagesarrayref) = @_; | ||||
| 499 | |||||
| 500 | my $databasename = $allvariables->{'PRODUCTNAME'}; | ||||
| 501 | $databasename = lc($databasename); | ||||
| 502 | $databasename =~ s/\.//g; | ||||
| 503 | $databasename =~ s/\-//g; | ||||
| 504 | $databasename =~ s/\s//g; | ||||
| 505 | |||||
| 506 | if ( $allvariables->{'MSPPRODUCTVERSION'} ) { $databasename = $databasename . $allvariables->{'MSPPRODUCTVERSION'}; } | ||||
| 507 | |||||
| 508 | # possibility to overwrite the name with variable DATABASENAME | ||||
| 509 | # if ( $allvariables->{'DATABASENAME'} ) { $databasename = $allvariables->{'DATABASENAME'}; } | ||||
| 510 | |||||
| 511 | # Adding patch info to database name | ||||
| 512 | # if ( $installer::globals::buildid ) { $databasename = $databasename . "_" . $installer::globals::buildid; } | ||||
| 513 | |||||
| 514 | # if ( $allvariables->{'VENDORPATCHVERSION'} ) { $databasename = $databasename . "_" . $allvariables->{'VENDORPATCHVERSION'}; } | ||||
| 515 | |||||
| 516 | |||||
| 517 | if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) | ||||
| 518 | { | ||||
| 519 | my $windowspatchlevel = 0; | ||||
| 520 | if ( $allvariables->{'MSPPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'MSPPATCHLEVEL'}; } | ||||
| 521 | $databasename = $databasename . "_servicepack_" . $windowspatchlevel; | ||||
| 522 | my $languagestring = create_langstring($languagesarrayref); | ||||
| 523 | $databasename = $databasename . $languagestring; | ||||
| 524 | } | ||||
| 525 | else | ||||
| 526 | { | ||||
| 527 | my $hotfixaddon = "hotfix_"; | ||||
| 528 | $hotfixaddon = $hotfixaddon . $installer::globals::buildid; | ||||
| 529 | my $cwsname = ""; | ||||
| 530 | if ( $allvariables->{'OVERWRITE_CWSNAME'} ) { $hotfixaddon = $allvariables->{'OVERWRITE_CWSNAME'}; } | ||||
| 531 | $databasename = $databasename . "_" . $hotfixaddon; | ||||
| 532 | } | ||||
| 533 | |||||
| 534 | $databasename = $databasename . ".msp"; | ||||
| 535 | |||||
| 536 | my $fullmspname = $mspdir . $installer::globals::separator . $databasename; | ||||
| 537 | |||||
| 538 | if ( $^O =~ /cygwin/i ) { $fullmspname =~ s/\//\\/g; } | ||||
| 539 | |||||
| 540 | return $fullmspname; | ||||
| 541 | } | ||||
| 542 | |||||
| 543 | #################################################################### | ||||
| 544 | # Editing table Properties | ||||
| 545 | #################################################################### | ||||
| 546 | |||||
| 547 | sub change_properties_table | ||||
| 548 | { | ||||
| 549 | my ($localmspdir, $mspfilename) = @_; | ||||
| 550 | |||||
| 551 | my $infoline = "Changing content of table \"Properties\"\n"; | ||||
| 552 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 553 | |||||
| 554 | my $filename = $localmspdir . $installer::globals::separator . "Properties.idt"; | ||||
| 555 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_properties_table"); } | ||||
| 556 | |||||
| 557 | my $filecontent = installer::files::read_file($filename); | ||||
| 558 | |||||
| 559 | |||||
| 560 | my $guidref = installer::windows::msiglobal::get_guid_list(1, 1); | ||||
| 561 | ${$guidref}[0] =~ s/\s*$//; # removing ending spaces | ||||
| 562 | my $patchcode = "\{" . ${$guidref}[0] . "\}"; | ||||
| 563 | |||||
| 564 | # Setting "PatchOutputPath" | ||||
| 565 | my $found_patchoutputpath = 0; | ||||
| 566 | my $found_patchguid = 0; | ||||
| 567 | |||||
| 568 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) | ||||
| 569 | { | ||||
| 570 | if ( ${$filecontent}[$i] =~ /^\s*PatchOutputPath\t(.*?)\s*$/ ) | ||||
| 571 | { | ||||
| 572 | my $oldvalue = $1; | ||||
| 573 | ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$mspfilename/; | ||||
| 574 | $found_patchoutputpath = 1; | ||||
| 575 | } | ||||
| 576 | |||||
| 577 | if ( ${$filecontent}[$i] =~ /^\s*PatchGUID\t(.*?)\s*$/ ) | ||||
| 578 | { | ||||
| 579 | my $oldvalue = $1; | ||||
| 580 | ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$patchcode/; | ||||
| 581 | $found_patchguid = 1; | ||||
| 582 | } | ||||
| 583 | } | ||||
| 584 | |||||
| 585 | if ( ! $found_patchoutputpath ) | ||||
| 586 | { | ||||
| 587 | my $newline = "PatchOutputPath\t$mspfilename\n"; | ||||
| 588 | push(@{$filecontent}, $newline); | ||||
| 589 | } | ||||
| 590 | |||||
| 591 | if ( ! $found_patchguid ) | ||||
| 592 | { | ||||
| 593 | my $newline = "PatchGUID\t$patchcode\n"; | ||||
| 594 | push(@{$filecontent}, $newline); | ||||
| 595 | } | ||||
| 596 | |||||
| 597 | # saving file | ||||
| 598 | installer::files::save_file($filename, $filecontent); | ||||
| 599 | } | ||||
| 600 | |||||
| 601 | #################################################################### | ||||
| 602 | # Editing table TargetImages | ||||
| 603 | #################################################################### | ||||
| 604 | |||||
| 605 | sub change_targetimages_table | ||||
| 606 | { | ||||
| 607 | my ($localmspdir, $olddatabase) = @_; | ||||
| 608 | |||||
| 609 | my $infoline = "Changing content of table \"TargetImages\"\n"; | ||||
| 610 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 611 | |||||
| 612 | my $filename = $localmspdir . $installer::globals::separator . "TargetImages.idt"; | ||||
| 613 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_targetimages_table"); } | ||||
| 614 | |||||
| 615 | my $filecontent = installer::files::read_file($filename); | ||||
| 616 | my @newcontent = (); | ||||
| 617 | |||||
| 618 | # Copying the header | ||||
| 619 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } } | ||||
| 620 | |||||
| 621 | #Adding all targets | ||||
| 622 | my $newline = "T1\t$olddatabase\t\tU1\t1\t0x00000922\t1\n"; | ||||
| 623 | push(@newcontent, $newline); | ||||
| 624 | |||||
| 625 | # saving file | ||||
| 626 | installer::files::save_file($filename, \@newcontent); | ||||
| 627 | } | ||||
| 628 | |||||
| 629 | #################################################################### | ||||
| 630 | # Editing table UpgradedImages | ||||
| 631 | #################################################################### | ||||
| 632 | |||||
| 633 | sub change_upgradedimages_table | ||||
| 634 | { | ||||
| 635 | my ($localmspdir, $newdatabase) = @_; | ||||
| 636 | |||||
| 637 | my $infoline = "Changing content of table \"UpgradedImages\"\n"; | ||||
| 638 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 639 | |||||
| 640 | my $filename = $localmspdir . $installer::globals::separator . "UpgradedImages.idt"; | ||||
| 641 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_upgradedimages_table"); } | ||||
| 642 | |||||
| 643 | my $filecontent = installer::files::read_file($filename); | ||||
| 644 | my @newcontent = (); | ||||
| 645 | |||||
| 646 | # Copying the header | ||||
| 647 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } } | ||||
| 648 | |||||
| 649 | # Syntax: Upgraded MsiPath PatchMsiPath SymbolPaths Family | ||||
| 650 | |||||
| 651 | # default values | ||||
| 652 | my $upgraded = "U1"; | ||||
| 653 | my $msipath = $newdatabase; | ||||
| 654 | my $patchmsipath = ""; | ||||
| 655 | my $symbolpaths = ""; | ||||
| 656 | my $family = "22334455"; | ||||
| 657 | |||||
| 658 | if ( $#{$filecontent} >= 3 ) | ||||
| 659 | { | ||||
| 660 | my $line = ${$filecontent}[3]; | ||||
| 661 | if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) | ||||
| 662 | { | ||||
| 663 | $upgraded = $1; | ||||
| 664 | $patchmsipath = $3; | ||||
| 665 | $symbolpaths = $4; | ||||
| 666 | $family = $5; | ||||
| 667 | } | ||||
| 668 | } | ||||
| 669 | |||||
| 670 | #Adding sequence line, saving PatchFamily | ||||
| 671 | my $newline = "$upgraded\t$msipath\t$patchmsipath\t$symbolpaths\t$family\n"; | ||||
| 672 | push(@newcontent, $newline); | ||||
| 673 | |||||
| 674 | # saving file | ||||
| 675 | installer::files::save_file($filename, \@newcontent); | ||||
| 676 | } | ||||
| 677 | |||||
| 678 | #################################################################### | ||||
| 679 | # Editing table ImageFamilies | ||||
| 680 | #################################################################### | ||||
| 681 | |||||
| 682 | sub change_imagefamilies_table | ||||
| 683 | { | ||||
| 684 | my ($localmspdir) = @_; | ||||
| 685 | |||||
| 686 | my $infoline = "Changing content of table \"ImageFamilies\"\n"; | ||||
| 687 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 688 | |||||
| 689 | my $filename = $localmspdir . $installer::globals::separator . "ImageFamilies.idt"; | ||||
| 690 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_imagefamilies_table"); } | ||||
| 691 | |||||
| 692 | my $filecontent = installer::files::read_file($filename); | ||||
| 693 | my @newcontent = (); | ||||
| 694 | |||||
| 695 | # Copying the header | ||||
| 696 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } } | ||||
| 697 | |||||
| 698 | # Syntax: Family MediaSrcPropName MediaDiskId FileSequenceStart DiskPrompt VolumeLabel | ||||
| 699 | # "FileSequenceStart has to be set | ||||
| 700 | |||||
| 701 | # Default values: | ||||
| 702 | |||||
| 703 | my $family = "22334455"; | ||||
| 704 | my $mediasrcpropname = "MediaSrcPropName"; | ||||
| 705 | my $mediadiskid = "2"; | ||||
| 706 | my $filesequencestart = get_filesequencestart(); | ||||
| 707 | my $diskprompt = ""; | ||||
| 708 | my $volumelabel = ""; | ||||
| 709 | |||||
| 710 | if ( $#{$filecontent} >= 3 ) | ||||
| 711 | { | ||||
| 712 | my $line = ${$filecontent}[3]; | ||||
| 713 | if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ ) | ||||
| 714 | { | ||||
| 715 | $family = $1; | ||||
| 716 | $mediasrcpropname = $2; | ||||
| 717 | $mediadiskid = $3; | ||||
| 718 | $diskprompt = $5; | ||||
| 719 | $volumelabel = $6; | ||||
| 720 | } | ||||
| 721 | } | ||||
| 722 | |||||
| 723 | #Adding sequence line | ||||
| 724 | my $newline = "$family\t$mediasrcpropname\t$mediadiskid\t$filesequencestart\t$diskprompt\t$volumelabel\n"; | ||||
| 725 | push(@newcontent, $newline); | ||||
| 726 | |||||
| 727 | # saving file | ||||
| 728 | installer::files::save_file($filename, \@newcontent); | ||||
| 729 | } | ||||
| 730 | |||||
| 731 | #################################################################### | ||||
| 732 | # Setting start sequence for patch | ||||
| 733 | #################################################################### | ||||
| 734 | |||||
| 735 | sub get_filesequencestart | ||||
| 736 | { | ||||
| 737 | my $sequence = 1000; # default | ||||
| 738 | |||||
| 739 | if ( $installer::globals::updatelastsequence ) { $sequence = $installer::globals::updatelastsequence + 500; } | ||||
| 740 | |||||
| 741 | return $sequence; | ||||
| 742 | } | ||||
| 743 | |||||
| 744 | #################################################################### | ||||
| 745 | # Setting time value into pcp file | ||||
| 746 | # Format mm/dd/yyyy hh:mm | ||||
| 747 | #################################################################### | ||||
| 748 | |||||
| 749 | sub get_patchtime_value | ||||
| 750 | { | ||||
| 751 | # Syntax: 8/8/2008 11:55 | ||||
| 752 | my $minute = (localtime())[1]; | ||||
| 753 | my $hour = (localtime())[2]; | ||||
| 754 | my $day = (localtime())[3]; | ||||
| 755 | my $month = (localtime())[4]; | ||||
| 756 | my $year = 1900 + (localtime())[5]; | ||||
| 757 | |||||
| 758 | $month++; # zero based month | ||||
| 759 | if ( $minute < 10 ) { $minute = "0" . $minute; } | ||||
| 760 | if ( $hour < 10 ) { $hour = "0" . $hour; } | ||||
| 761 | |||||
| 762 | my $timestring = $month . "/" . $day . "/" . $year . " " . $hour . ":" . $minute; | ||||
| 763 | |||||
| 764 | return $timestring; | ||||
| 765 | } | ||||
| 766 | |||||
| 767 | ################################################################################# | ||||
| 768 | # Checking, if this is the correct database. | ||||
| 769 | ################################################################################# | ||||
| 770 | |||||
| 771 | sub correct_langs | ||||
| 772 | { | ||||
| 773 | my ($langs, $languagestringref) = @_; | ||||
| 774 | |||||
| 775 | my $correct_langs = 0; | ||||
| 776 | |||||
| 777 | # Comparing $langs with $languagestringref | ||||
| 778 | |||||
| 779 | my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ","); | ||||
| 780 | my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_"); | ||||
| 781 | |||||
| 782 | my $not_included = 0; | ||||
| 783 | foreach my $onelang ( keys %{$langlisthash} ) | ||||
| 784 | { | ||||
| 785 | if ( ! exists($langstringhash->{$onelang}) ) | ||||
| 786 | { | ||||
| 787 | $not_included = 1; | ||||
| 788 | last; | ||||
| 789 | } | ||||
| 790 | } | ||||
| 791 | |||||
| 792 | if ( ! $not_included ) | ||||
| 793 | { | ||||
| 794 | foreach my $onelanguage ( keys %{$langstringhash} ) | ||||
| 795 | { | ||||
| 796 | if ( ! exists($langlisthash->{$onelanguage}) ) | ||||
| 797 | { | ||||
| 798 | $not_included = 1; | ||||
| 799 | last; | ||||
| 800 | } | ||||
| 801 | } | ||||
| 802 | |||||
| 803 | if ( ! $not_included ) { $correct_langs = 1; } | ||||
| 804 | } | ||||
| 805 | |||||
| 806 | return $correct_langs; | ||||
| 807 | } | ||||
| 808 | |||||
| 809 | ################################################################################# | ||||
| 810 | # Searching for the path to the reference database for this special product. | ||||
| 811 | ################################################################################# | ||||
| 812 | |||||
| 813 | sub get_patchid_from_list | ||||
| 814 | { | ||||
| 815 | my ($filecontent, $languagestringref, $filename) = @_; | ||||
| 816 | |||||
| 817 | my $patchid = ""; | ||||
| 818 | |||||
| 819 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) | ||||
| 820 | { | ||||
| 821 | my $line = ${$filecontent}[$i]; | ||||
| 822 | if ( $line =~ /^\s*$/ ) { next; } # empty line | ||||
| 823 | if ( $line =~ /^\s*\#/ ) { next; } # comment line | ||||
| 824 | |||||
| 825 | if ( $line =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/ ) | ||||
| 826 | { | ||||
| 827 | my $langs = $1; | ||||
| 828 | my $localpatchid = $2; | ||||
| 829 | |||||
| 830 | if ( correct_langs($langs, $languagestringref) ) | ||||
| 831 | { | ||||
| 832 | $patchid = $localpatchid; | ||||
| 833 | last; | ||||
| 834 | } | ||||
| 835 | } | ||||
| 836 | else | ||||
| 837 | { | ||||
| 838 | installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_patchid_from_list"); | ||||
| 839 | } | ||||
| 840 | } | ||||
| 841 | |||||
| 842 | return $patchid; | ||||
| 843 | } | ||||
| 844 | |||||
| 845 | #################################################################### | ||||
| 846 | # Editing table PatchMetadata | ||||
| 847 | #################################################################### | ||||
| 848 | |||||
| 849 | sub change_patchmetadata_table | ||||
| 850 | { | ||||
| 851 | my ($localmspdir, $allvariables, $languagestringref) = @_; | ||||
| 852 | |||||
| 853 | my $infoline = "Changing content of table \"PatchMetadata\"\n"; | ||||
| 854 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 855 | |||||
| 856 | my $filename = $localmspdir . $installer::globals::separator . "PatchMetadata.idt"; | ||||
| 857 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchmetadata_table"); } | ||||
| 858 | |||||
| 859 | my $filecontent = installer::files::read_file($filename); | ||||
| 860 | my @newcontent = (); | ||||
| 861 | |||||
| 862 | # Syntax: Company Property Value | ||||
| 863 | # Interesting properties: "Classification" and "CreationTimeUTC" | ||||
| 864 | |||||
| 865 | my $classification_set = 0; | ||||
| 866 | my $creationtime_set = 0; | ||||
| 867 | my $targetproductname_set = 0; | ||||
| 868 | my $manufacturer_set = 0; | ||||
| 869 | my $displayname_set = 0; | ||||
| 870 | my $description_set = 0; | ||||
| 871 | my $allowremoval_set = 0; | ||||
| 872 | |||||
| 873 | my $defaultcompany = ""; | ||||
| 874 | |||||
| 875 | my $classificationstring = "Classification"; | ||||
| 876 | my $classificationvalue = "Hotfix"; | ||||
| 877 | if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $classificationvalue = "ServicePack"; } | ||||
| 878 | |||||
| 879 | my $allowremovalstring = "AllowRemoval"; | ||||
| 880 | my $allowremovalvalue = "1"; | ||||
| 881 | if (( exists($allvariables->{'MSPALLOWREMOVAL'}) ) && ( $allvariables->{'MSPALLOWREMOVAL'} == 0 )) { $allowremovalvalue = 0; } | ||||
| 882 | |||||
| 883 | my $timestring = "CreationTimeUTC"; | ||||
| 884 | # Syntax: 8/8/2008 11:55 | ||||
| 885 | my $timevalue = get_patchtime_value(); | ||||
| 886 | |||||
| 887 | my $targetproductnamestring = "TargetProductName"; | ||||
| 888 | my $targetproductnamevalue = $allvariables->{'PRODUCTNAME'}; | ||||
| 889 | if ( $allvariables->{'PROPERTYTABLEPRODUCTNAME'} ) { $targetproductnamevalue = $allvariables->{'PROPERTYTABLEPRODUCTNAME'}; } | ||||
| 890 | |||||
| 891 | my $manufacturerstring = "ManufacturerName"; | ||||
| 892 | my $manufacturervalue = $ENV{'OOO_VENDOR'}; | ||||
| 893 | if ( $installer::globals::longmanufacturer ) { $manufacturervalue = $installer::globals::longmanufacturer; } | ||||
| 894 | |||||
| 895 | my $displaynamestring = "DisplayName"; | ||||
| 896 | my $descriptionstring = "Description"; | ||||
| 897 | my $displaynamevalue = ""; | ||||
| 898 | my $descriptionvalue = ""; | ||||
| 899 | |||||
| 900 | my $base = $allvariables->{'PRODUCTNAME'} . " " . $allvariables->{'PRODUCTVERSION'}; | ||||
| 901 | if ( $installer::globals::languagepack || $installer::globals::helppack ) { $base = $targetproductnamevalue; } | ||||
| 902 | |||||
| 903 | my $windowspatchlevel = 0; | ||||
| 904 | if ( $allvariables->{'WINDOWSPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'WINDOWSPATCHLEVEL'}; } | ||||
| 905 | |||||
| 906 | my $displayaddon = ""; | ||||
| 907 | if ( $allvariables->{'PATCHDISPLAYADDON'} ) { $displayaddon = $allvariables->{'PATCHDISPLAYADDON'}; } | ||||
| 908 | |||||
| 909 | my $patchsequence = get_patchsequence($allvariables); | ||||
| 910 | |||||
| 911 | if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) | ||||
| 912 | { | ||||
| 913 | $displaynamevalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid; | ||||
| 914 | $descriptionvalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid; | ||||
| 915 | } | ||||
| 916 | else | ||||
| 917 | { | ||||
| 918 | $displaynamevalue = $base . " Hotfix " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid; | ||||
| 919 | $descriptionvalue = $base . " Hotfix " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid; | ||||
| 920 | $displaynamevalue =~ s/ / /g; | ||||
| 921 | $descriptionvalue =~ s/ / /g; | ||||
| 922 | $displaynamevalue =~ s/ / /g; | ||||
| 923 | $descriptionvalue =~ s/ / /g; | ||||
| 924 | $displaynamevalue =~ s/ / /g; | ||||
| 925 | $descriptionvalue =~ s/ / /g; | ||||
| 926 | } | ||||
| 927 | |||||
| 928 | if ( $allvariables->{'MSPPATCHNAMELIST'} ) | ||||
| 929 | { | ||||
| 930 | my $patchnamelistfile = $allvariables->{'MSPPATCHNAMELIST'}; | ||||
| 931 | $patchnamelistfile = $installer::globals::idttemplatepath . $installer::globals::separator . $patchnamelistfile; | ||||
| 932 | if ( ! -f $patchnamelistfile ) { installer::exiter::exit_program("ERROR: Could not find file \"$patchnamelistfile\".", "change_patchmetadata_table"); } | ||||
| 933 | my $filecontent = installer::files::read_file($patchnamelistfile); | ||||
| 934 | |||||
| 935 | # Get name and path of reference database | ||||
| 936 | my $patchid = get_patchid_from_list($filecontent, $languagestringref, $patchnamelistfile); | ||||
| 937 | |||||
| 938 | if ( $patchid eq "" ) { installer::exiter::exit_program("ERROR: Could not find file patchid in file \"$patchnamelistfile\" for language(s) \"$$languagestringref\".", "change_patchmetadata_table"); } | ||||
| 939 | |||||
| 940 | # Setting language specific patch id | ||||
| 941 | } | ||||
| 942 | |||||
| 943 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) | ||||
| 944 | { | ||||
| 945 | if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\s*$/ ) | ||||
| 946 | { | ||||
| 947 | my $company = $1; | ||||
| 948 | my $property = $2; | ||||
| 949 | my $value = $3; | ||||
| 950 | |||||
| 951 | if ( $property eq $classificationstring ) | ||||
| 952 | { | ||||
| 953 | ${$filecontent}[$i] = "$company\t$property\t$classificationvalue\n"; | ||||
| 954 | $classification_set = 1; | ||||
| 955 | } | ||||
| 956 | |||||
| 957 | if ( $property eq $allowremovalstring ) | ||||
| 958 | { | ||||
| 959 | ${$filecontent}[$i] = "$company\t$property\t$allowremovalvalue\n"; | ||||
| 960 | $allowremoval_set = 1; | ||||
| 961 | } | ||||
| 962 | |||||
| 963 | if ( $property eq $timestring ) | ||||
| 964 | { | ||||
| 965 | ${$filecontent}[$i] = "$company\t$property\t$timevalue\n"; | ||||
| 966 | $creationtime_set = 1; | ||||
| 967 | } | ||||
| 968 | |||||
| 969 | if ( $property eq $targetproductnamestring ) | ||||
| 970 | { | ||||
| 971 | ${$filecontent}[$i] = "$company\t$property\t$targetproductnamevalue\n"; | ||||
| 972 | $targetproductname_set = 1; | ||||
| 973 | } | ||||
| 974 | |||||
| 975 | if ( $property eq $manufacturerstring ) | ||||
| 976 | { | ||||
| 977 | ${$filecontent}[$i] = "$company\t$property\t$manufacturervalue\n"; | ||||
| 978 | $manufacturer_set = 1; | ||||
| 979 | } | ||||
| 980 | |||||
| 981 | if ( $property eq $displaynamestring ) | ||||
| 982 | { | ||||
| 983 | ${$filecontent}[$i] = "$company\t$property\t$displaynamevalue\n"; | ||||
| 984 | $displayname_set = 1; | ||||
| 985 | } | ||||
| 986 | |||||
| 987 | if ( $property eq $descriptionstring ) | ||||
| 988 | { | ||||
| 989 | ${$filecontent}[$i] = "$company\t$property\t$descriptionvalue\n"; | ||||
| 990 | $description_set = 1; | ||||
| 991 | } | ||||
| 992 | } | ||||
| 993 | |||||
| 994 | push(@newcontent, ${$filecontent}[$i]); | ||||
| 995 | } | ||||
| 996 | |||||
| 997 | if ( ! $classification_set ) | ||||
| 998 | { | ||||
| 999 | my $line = "$defaultcompany\t$classificationstring\t$classificationvalue\n"; | ||||
| 1000 | push(@newcontent, $line); | ||||
| 1001 | } | ||||
| 1002 | |||||
| 1003 | if ( ! $allowremoval_set ) | ||||
| 1004 | { | ||||
| 1005 | my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n"; | ||||
| 1006 | push(@newcontent, $line); | ||||
| 1007 | } | ||||
| 1008 | |||||
| 1009 | if ( ! $allowremoval_set ) | ||||
| 1010 | { | ||||
| 1011 | my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n"; | ||||
| 1012 | push(@newcontent, $line); | ||||
| 1013 | } | ||||
| 1014 | |||||
| 1015 | if ( ! $creationtime_set ) | ||||
| 1016 | { | ||||
| 1017 | my $line = "$defaultcompany\t$timestring\t$timevalue\n"; | ||||
| 1018 | push(@newcontent, $line); | ||||
| 1019 | } | ||||
| 1020 | |||||
| 1021 | if ( ! $targetproductname_set ) | ||||
| 1022 | { | ||||
| 1023 | my $line = "$defaultcompany\t$targetproductnamestring\t$targetproductnamevalue\n"; | ||||
| 1024 | push(@newcontent, $line); | ||||
| 1025 | } | ||||
| 1026 | |||||
| 1027 | if ( ! $manufacturer_set ) | ||||
| 1028 | { | ||||
| 1029 | my $line = "$defaultcompany\t$manufacturerstring\t$manufacturervalue\n"; | ||||
| 1030 | push(@newcontent, $line); | ||||
| 1031 | } | ||||
| 1032 | |||||
| 1033 | if ( ! $displayname_set ) | ||||
| 1034 | { | ||||
| 1035 | my $line = "$defaultcompany\t$displaynamestring\t$displaynamevalue\n"; | ||||
| 1036 | push(@newcontent, $line); | ||||
| 1037 | } | ||||
| 1038 | |||||
| 1039 | if ( ! $description_set ) | ||||
| 1040 | { | ||||
| 1041 | my $line = "$defaultcompany\t$descriptionstring\t$descriptionvalue\n"; | ||||
| 1042 | push(@newcontent, $line); | ||||
| 1043 | } | ||||
| 1044 | |||||
| 1045 | # saving file | ||||
| 1046 | installer::files::save_file($filename, \@newcontent); | ||||
| 1047 | } | ||||
| 1048 | |||||
| 1049 | #################################################################### | ||||
| 1050 | # Editing table PatchSequence | ||||
| 1051 | #################################################################### | ||||
| 1052 | |||||
| 1053 | sub change_patchsequence_table | ||||
| 1054 | { | ||||
| 1055 | my ($localmspdir, $allvariables) = @_; | ||||
| 1056 | |||||
| 1057 | my $infoline = "Changing content of table \"PatchSequence\"\n"; | ||||
| 1058 | push( @installer::globals::logfileinfo, $infoline); | ||||
| 1059 | |||||
| 1060 | my $filename = $localmspdir . $installer::globals::separator . "PatchSequence.idt"; | ||||
| 1061 | if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchsequence_table"); } | ||||
| 1062 | |||||
| 1063 | my $filecontent = installer::files::read_file($filename); | ||||
| 1064 | my @newcontent = (); | ||||
| 1065 | |||||
| 1066 | # Copying the header | ||||
| 1067 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } } | ||||
| 1068 | |||||
| 1069 | # Syntax: PatchFamily Target Sequence Supersede | ||||
| 1070 | |||||
| 1071 | my $patchfamily = "SO"; | ||||
| 1072 | my $target = ""; | ||||
| 1073 | my $patchsequence = get_patchsequence($allvariables); | ||||
| 1074 | my $supersede = get_supersede($allvariables); | ||||
| 1075 | |||||
| 1076 | if ( $#{$filecontent} >= 3 ) | ||||
| 1077 | { | ||||
| 1078 | my $line = ${$filecontent}[3]; | ||||
| 1079 | if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\s$/ ) | ||||
| 1080 | { | ||||
| 1081 | $patchfamily = $1; | ||||
| 1082 | $target = $2; | ||||
| 1083 | } | ||||
| 1084 | } | ||||
| 1085 | |||||
| 1086 | #Adding sequence line, saving PatchFamily | ||||
| 1087 | my $newline = "$patchfamily\t$target\t$patchsequence\t$supersede\n"; | ||||
| 1088 | push(@newcontent, $newline); | ||||
| 1089 | |||||
| 1090 | # saving file | ||||
| 1091 | installer::files::save_file($filename, \@newcontent); | ||||
| 1092 | } | ||||
| 1093 | |||||
| 1094 | #################################################################### | ||||
| 1095 | # Setting supersede, "0" for Hotfixes, "1" for ServicePack | ||||
| 1096 | #################################################################### | ||||
| 1097 | |||||
| 1098 | sub get_supersede | ||||
| 1099 | { | ||||
| 1100 | my ( $allvariables ) = @_; | ||||
| 1101 | |||||
| 1102 | my $supersede = 0; # if not defined, this is a Hotfix | ||||
| 1103 | |||||
| 1104 | if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $supersede = 1; } | ||||
| 1105 | |||||
| 1106 | return $supersede; | ||||
| 1107 | } | ||||
| 1108 | |||||
| 1109 | #################################################################### | ||||
| 1110 | # Setting the sequence of the patch | ||||
| 1111 | #################################################################### | ||||
| 1112 | |||||
| 1113 | sub get_patchsequence | ||||
| 1114 | { | ||||
| 1115 | my ( $allvariables ) = @_; | ||||
| 1116 | |||||
| 1117 | my $patchsequence = "1.0"; | ||||
| 1118 | |||||
| 1119 | if ( ! $allvariables->{'PACKAGEVERSION'} ) { installer::exiter::exit_program("ERROR: PACKAGEVERSION must be set for msp patch creation!", "get_patchsequence"); } | ||||
| 1120 | |||||
| 1121 | my $packageversion = $allvariables->{'PACKAGEVERSION'}; | ||||
| 1122 | |||||
| 1123 | if ( $packageversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) | ||||
| 1124 | { | ||||
| 1125 | my $major = $1; | ||||
| 1126 | my $minor = $2; | ||||
| 1127 | my $micro = $3; | ||||
| 1128 | my $concat = 100 * $minor + $micro; | ||||
| 1129 | $packageversion = $major . "\." . $concat; | ||||
| 1130 | } | ||||
| 1131 | my $vendornumber = 0; | ||||
| 1132 | if ( $allvariables->{'VENDORPATCHVERSION'} ) { $vendornumber = $allvariables->{'VENDORPATCHVERSION'}; } | ||||
| 1133 | $patchsequence = $packageversion . "\." . $installer::globals::buildid . "\." . $vendornumber; | ||||
| 1134 | |||||
| 1135 | if ( $allvariables->{'PATCHSEQUENCE'} ) { $patchsequence = $allvariables->{'PATCHSEQUENCE'}; } | ||||
| 1136 | |||||
| 1137 | return $patchsequence; | ||||
| 1138 | } | ||||
| 1139 | |||||
| 1140 | #################################################################### | ||||
| 1141 | # Editing all tables from pcp file, that need to be edited | ||||
| 1142 | #################################################################### | ||||
| 1143 | |||||
| 1144 | sub edit_tables | ||||
| 1145 | { | ||||
| 1146 | my ($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref) = @_; | ||||
| 1147 | |||||
| 1148 | # table list contains: my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence"; | ||||
| 1149 | |||||
| 1150 | change_properties_table($localmspdir, $mspfilename); | ||||
| 1151 | change_targetimages_table($localmspdir, $olddatabase); | ||||
| 1152 | change_upgradedimages_table($localmspdir, $newdatabase); | ||||
| 1153 | change_imagefamilies_table($localmspdir); | ||||
| 1154 | change_patchmetadata_table($localmspdir, $allvariables, $languagestringref); | ||||
| 1155 | change_patchsequence_table($localmspdir, $allvariables); | ||||
| 1156 | } | ||||
| 1157 | |||||
| 1158 | ################################################################################# | ||||
| 1159 | # Checking, if this is the correct database. | ||||
| 1160 | ################################################################################# | ||||
| 1161 | |||||
| 1162 | sub correct_patch | ||||
| 1163 | { | ||||
| 1164 | my ($product, $pro, $langs, $languagestringref) = @_; | ||||
| 1165 | |||||
| 1166 | my $correct_patch = 0; | ||||
| 1167 | |||||
| 1168 | # Comparing $product with $installer::globals::product and | ||||
| 1169 | # $pro with $installer::globals::pro and | ||||
| 1170 | # $langs with $languagestringref | ||||
| 1171 | |||||
| 1172 | my $product_is_good = 0; | ||||
| 1173 | |||||
| 1174 | my $localproduct = $installer::globals::product; | ||||
| 1175 | if ( $installer::globals::languagepack ) { $localproduct = $localproduct . "LanguagePack"; } | ||||
| 1176 | elsif ( $installer::globals::helppack ) { $localproduct = $localproduct . "HelpPack"; } | ||||
| 1177 | |||||
| 1178 | if ( $product eq $localproduct ) { $product_is_good = 1; } | ||||
| 1179 | |||||
| 1180 | if ( $product_is_good ) | ||||
| 1181 | { | ||||
| 1182 | my $pro_is_good = 0; | ||||
| 1183 | |||||
| 1184 | if ((( $pro eq "pro" ) && ( $installer::globals::pro )) || (( $pro eq "nonpro" ) && ( ! $installer::globals::pro ))) { $pro_is_good = 1; } | ||||
| 1185 | |||||
| 1186 | if ( $pro_is_good ) | ||||
| 1187 | { | ||||
| 1188 | my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ","); | ||||
| 1189 | my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_"); | ||||
| 1190 | |||||
| 1191 | my $not_included = 0; | ||||
| 1192 | foreach my $onelang ( keys %{$langlisthash} ) | ||||
| 1193 | { | ||||
| 1194 | if ( ! exists($langstringhash->{$onelang}) ) | ||||
| 1195 | { | ||||
| 1196 | $not_included = 1; | ||||
| 1197 | last; | ||||
| 1198 | } | ||||
| 1199 | } | ||||
| 1200 | |||||
| 1201 | if ( ! $not_included ) | ||||
| 1202 | { | ||||
| 1203 | foreach my $onelanguage ( keys %{$langstringhash} ) | ||||
| 1204 | { | ||||
| 1205 | if ( ! exists($langlisthash->{$onelanguage}) ) | ||||
| 1206 | { | ||||
| 1207 | $not_included = 1; | ||||
| 1208 | last; | ||||
| 1209 | } | ||||
| 1210 | } | ||||
| 1211 | |||||
| 1212 | if ( ! $not_included ) { $correct_patch = 1; } | ||||
| 1213 | } | ||||
| 1214 | } | ||||
| 1215 | } | ||||
| 1216 | |||||
| 1217 | return $correct_patch; | ||||
| 1218 | } | ||||
| 1219 | |||||
| 1220 | ################################################################################# | ||||
| 1221 | # Searching for the path to the required patch for this special product. | ||||
| 1222 | ################################################################################# | ||||
| 1223 | |||||
| 1224 | sub get_requiredpatchfile_from_list | ||||
| 1225 | { | ||||
| 1226 | my ($filecontent, $languagestringref, $filename) = @_; | ||||
| 1227 | |||||
| 1228 | my $patchpath = ""; | ||||
| 1229 | |||||
| 1230 | for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) | ||||
| 1231 | { | ||||
| 1232 | my $line = ${$filecontent}[$i]; | ||||
| 1233 | if ( $line =~ /^\s*$/ ) { next; } # empty line | ||||
| 1234 | if ( $line =~ /^\s*\#/ ) { next; } # comment line | ||||
| 1235 | |||||
| 1236 | if ( $line =~ /^\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*$/ ) | ||||
| 1237 | { | ||||
| 1238 | my $product = $1; | ||||
| 1239 | my $pro = $2; | ||||
| 1240 | my $langs = $3; | ||||
| 1241 | my $path = $4; | ||||
| 1242 | |||||
| 1243 | if (( $pro ne "pro" ) && ( $pro ne "nonpro" )) { installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename. Only \"pro\" or \"nonpro\" allowed in column 1! Line: \"$line\"", "get_databasename_from_list"); } | ||||
| 1244 | |||||
| 1245 | if ( correct_patch($product, $pro, $langs, $languagestringref) ) | ||||
| 1246 | { | ||||
| 1247 | $patchpath = $path; | ||||
| 1248 | last; | ||||
| 1249 | } | ||||
| 1250 | } | ||||
| 1251 | else | ||||
| 1252 | { | ||||
| 1253 | installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_requiredpatchfile_from_list"); | ||||
| 1254 | } | ||||
| 1255 | } | ||||
| 1256 | |||||
| 1257 | return $patchpath; | ||||
| 1258 | } | ||||
| 1259 | |||||
| 1260 | ################################################################## | ||||
| 1261 | # Converting unicode file to ascii | ||||
| 1262 | # to be more precise: uft-16 little endian to ascii | ||||
| 1263 | ################################################################## | ||||
| 1264 | |||||
| 1265 | sub convert_unicode_to_ascii | ||||
| 1266 | { | ||||
| 1267 | my ( $filename ) = @_; | ||||
| 1268 | |||||
| 1269 | my @localfile = (); | ||||
| 1270 | |||||
| 1271 | my $savfilename = $filename . "_before.unicode"; | ||||
| 1272 | installer::systemactions::copy_one_file($filename, $savfilename); | ||||
| 1273 | |||||
| 1274 | open( IN, "<:encoding(UTF16-LE)", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii"); | ||||
| 1275 | while ( $line = <IN> ) { | ||||
| 1276 | push @localfile, $line; | ||||
| 1277 | } | ||||
| 1278 | close( IN ); | ||||
| 1279 | |||||
| 1280 | if ( open( OUT, ">", $filename ) ) | ||||
| 1281 | { | ||||
| 1282 | print OUT @localfile; | ||||
| 1283 | close(OUT); | ||||
| 1284 | } | ||||
| 1285 | } | ||||
| 1286 | |||||
| 1287 | #################################################################### | ||||
| 1288 | # Analyzing the log file created by msimsp.exe to find all | ||||
| 1289 | # files included into the patch. | ||||
| 1290 | #################################################################### | ||||
| 1291 | |||||
| 1292 | sub analyze_msimsp_logfile | ||||
| 1293 | { | ||||
| 1294 | my ($logfile, $filesarray) = @_; | ||||
| 1295 | |||||
| 1296 | # Reading log file after converting from utf-16 (LE) to ascii | ||||
| 1297 | convert_unicode_to_ascii($logfile); | ||||
| 1298 | my $logfilecontent = installer::files::read_file($logfile); | ||||
| 1299 | |||||
| 1300 | # Creating hash from $filesarray: unique file name -> destination of file | ||||
| 1301 | my %filehash = (); | ||||
| 1302 | my %destinationcollector = (); | ||||
| 1303 | |||||
| 1304 | for ( my $i = 0; $i <= $#{$filesarray}; $i++ ) | ||||
| 1305 | { | ||||
| 1306 | my $onefile = ${$filesarray}[$i]; | ||||
| 1307 | |||||
| 1308 | # Only collecting files with "uniquename" and "destination" | ||||
| 1309 | if (( exists($onefile->{'uniquename'}) ) && ( exists($onefile->{'uniquename'}) )) | ||||
| 1310 | { | ||||
| 1311 | my $uniquefilename = $onefile->{'uniquename'}; | ||||
| 1312 | my $destpath = $onefile->{'destination'}; | ||||
| 1313 | $filehash{$uniquefilename} = $destpath; | ||||
| 1314 | } | ||||
| 1315 | } | ||||
| 1316 | |||||
| 1317 | # Analyzing log file of msimsp.exe, finding all changed files | ||||
| 1318 | # and searching all destinations of unique file names. | ||||
| 1319 | # Content in log file: "INFO File Key: <file key> is modified" | ||||
| 1320 | # Collecting content in @installer::globals::patchfilecollector | ||||
| 1321 | |||||
| 1322 | for ( my $i = 0; $i <= $#{$logfilecontent}; $i++ ) | ||||
| 1323 | { | ||||
| 1324 | if ( ${$logfilecontent}[$i] =~ /Key\:\s*(.*?) is modified\s*$/ ) | ||||
| 1325 | { | ||||
| 1326 | my $filekey = $1; | ||||
| 1327 | if ( exists($filehash{$filekey}) ) { $destinationcollector{$filehash{$filekey}} = 1; } | ||||
| 1328 | else { installer::exiter::exit_program("ERROR: Could not find file key \"$filekey\" in file collector.", "analyze_msimsp_logfile"); } | ||||
| 1329 | } | ||||
| 1330 | } | ||||
| 1331 | |||||
| 1332 | foreach my $onedest ( sort keys %destinationcollector ) { push(@installer::globals::patchfilecollector, "$onedest\n"); } | ||||
| 1333 | |||||
| 1334 | } | ||||
| 1335 | |||||
| 1336 | #################################################################### | ||||
| 1337 | # Creating msp patch files for Windows | ||||
| 1338 | #################################################################### | ||||
| 1339 | |||||
| 1340 | sub create_msp_patch | ||||
| 1341 | { | ||||
| 1342 | my ($installationdir, $includepatharrayref, $allvariables, $languagestringref, $languagesarrayref, $filesarray) = @_; | ||||
| 1343 | |||||
| 1344 | my $force = 1; # print this message even in 'quiet' mode | ||||
| 1345 | installer::logger::print_message( "\n******************************************\n" ); | ||||
| 1346 | installer::logger::print_message( "... creating msp installation set ...\n", $force ); | ||||
| 1347 | installer::logger::print_message( "******************************************\n" ); | ||||
| 1348 | |||||
| 1349 | $installer::globals::creating_windows_installer_patch = 1; | ||||
| 1350 | |||||
| 1351 | my @needed_files = ("msimsp.exe"); # only required for patch creation process | ||||
| 1352 | installer::control::check_needed_files_in_path(\@needed_files); | ||||
| 1353 | |||||
| 1354 | installer::logger::include_header_into_logfile("Creating msp installation sets:"); | ||||
| 1355 | |||||
| 1356 | my $firstdir = $installationdir; | ||||
| 1357 | installer::pathanalyzer::get_path_from_fullqualifiedname(\$firstdir); | ||||
| 1358 | |||||
| 1359 | my $lastdir = $installationdir; | ||||
| 1360 | installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$lastdir); | ||||
| 1361 | |||||
| 1362 | if ( $lastdir =~ /\./ ) { $lastdir =~ s/\./_msp_inprogress\./ } | ||||
| 1363 | else { $lastdir = $lastdir . "_msp_inprogress"; } | ||||
| 1364 | |||||
| 1365 | # Removing existing directory "_native_packed_inprogress" and "_native_packed_witherror" and "_native_packed" | ||||
| 1366 | |||||
| 1367 | my $mspdir = $firstdir . $lastdir; | ||||
| 1368 | if ( -d $mspdir ) { installer::systemactions::remove_complete_directory($mspdir); } | ||||
| 1369 | |||||
| 1370 | my $olddir = $mspdir; | ||||
| 1371 | $olddir =~ s/_inprogress/_witherror/; | ||||
| 1372 | if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); } | ||||
| 1373 | |||||
| 1374 | $olddir = $mspdir; | ||||
| 1375 | $olddir =~ s/_inprogress//; | ||||
| 1376 | if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); } | ||||
| 1377 | |||||
| 1378 | # Creating the new directory for new installation set | ||||
| 1379 | installer::systemactions::create_directory($mspdir); | ||||
| 1380 | |||||
| 1381 | $installer::globals::saveinstalldir = $mspdir; | ||||
| 1382 | |||||
| 1383 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting product installation"); | ||||
| 1384 | |||||
| 1385 | # Installing both installation sets | ||||
| 1386 | installer::logger::print_message( "... installing products ...\n" ); | ||||
| 1387 | my ($olddatabase, $newdatabase) = install_installation_sets($installationdir); | ||||
| 1388 | |||||
| 1389 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting synchronization of installation sets"); | ||||
| 1390 | |||||
| 1391 | # Synchronizing installed products, allowing only different files with PATCH flag | ||||
| 1392 | installer::logger::print_message( "... synchronizing installation sets ...\n" ); | ||||
| 1393 | synchronize_installation_sets($olddatabase, $newdatabase, $filesarray); | ||||
| 1394 | |||||
| 1395 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting pcp file creation"); | ||||
| 1396 | |||||
| 1397 | # Create pcp file | ||||
| 1398 | installer::logger::print_message( "... creating pcp file ...\n" ); | ||||
| 1399 | |||||
| 1400 | my $localmspdir = installer::systemactions::create_directories("msp", $languagestringref); | ||||
| 1401 | |||||
| 1402 | if ( ! $allvariables->{'PCPFILENAME'} ) { installer::exiter::exit_program("ERROR: Property \"PCPFILENAME\" has to be defined.", "create_msp_patch"); } | ||||
| 1403 | my $pcpfilename = $allvariables->{'PCPFILENAME'}; | ||||
| 1404 | |||||
| 1405 | if ( $installer::globals::languagepack ) { $pcpfilename =~ s/.pcp\s*$/languagepack.pcp/; } | ||||
| 1406 | elsif ( $installer::globals::helppack ) { $pcpfilename =~ s/.pcp\s*$/helppack.pcp/; } | ||||
| 1407 | |||||
| 1408 | # Searching the pcp file in the include paths | ||||
| 1409 | my $fullpcpfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$pcpfilename, $includepatharrayref, 1); | ||||
| 1410 | if ( $$fullpcpfilenameref eq "" ) { installer::exiter::exit_program("ERROR: pcp file not found: $pcpfilename !", "create_msp_patch"); } | ||||
| 1411 | my $fullpcpfilenamesource = $$fullpcpfilenameref; | ||||
| 1412 | |||||
| 1413 | # Copying pcp file | ||||
| 1414 | my $fullpcpfilename = $localmspdir . $installer::globals::separator . $pcpfilename; | ||||
| 1415 | installer::systemactions::copy_one_file($fullpcpfilenamesource, $fullpcpfilename); | ||||
| 1416 | |||||
| 1417 | # a. Extracting tables from msi database: msidb.exe -d <msifile> -f <directory> -e File Media, ... | ||||
| 1418 | # b. Changing content of msi database in tables: File, Media, Directory, FeatureComponent | ||||
| 1419 | # c. Including tables into msi database: msidb.exe -d <msifile> -f <directory> -i File Media, ... | ||||
| 1420 | |||||
| 1421 | # Unpacking tables from pcp file | ||||
| 1422 | extract_all_tables_from_pcpfile($fullpcpfilename, $localmspdir); | ||||
| 1423 | |||||
| 1424 | # Tables, that need to be edited | ||||
| 1425 | my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence"; # required tables | ||||
| 1426 | |||||
| 1427 | # Saving all tables | ||||
| 1428 | check_and_save_tables($tablelist, $localmspdir); | ||||
| 1429 | |||||
| 1430 | # Setting the name of the new msp file | ||||
| 1431 | my $mspfilename = set_mspfilename($allvariables, $mspdir, $languagesarrayref); | ||||
| 1432 | |||||
| 1433 | # Editing tables | ||||
| 1434 | edit_tables($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref); | ||||
| 1435 | |||||
| 1436 | # Adding edited tables into pcp file | ||||
| 1437 | include_tables_into_pcpfile($fullpcpfilename, $localmspdir, $tablelist); | ||||
| 1438 | |||||
| 1439 | # Start msimsp.exe | ||||
| 1440 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting msimsp.exe"); | ||||
| 1441 | my $msimsplogfile = execute_msimsp($fullpcpfilename, $mspfilename, $localmspdir); | ||||
| 1442 | |||||
| 1443 | # Copy final installation set next to msp file | ||||
| 1444 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: Copying installation set"); | ||||
| 1445 | installer::logger::print_message( "... copying installation set ...\n" ); | ||||
| 1446 | |||||
| 1447 | my $oldinstallationsetpath = $installer::globals::updatedatabasepath; | ||||
| 1448 | |||||
| 1449 | if ( $^O =~ /cygwin/i ) { $oldinstallationsetpath =~ s/\\/\//g; } | ||||
| 1450 | |||||
| 1451 | installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldinstallationsetpath); | ||||
| 1452 | installer::systemactions::copy_complete_directory($oldinstallationsetpath, $mspdir); | ||||
| 1453 | |||||
| 1454 | # Copying additional patches into the installation set, if required | ||||
| 1455 | if (( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ) && ( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ne "" ) && ( ! $installer::globals::languagepack ) && ( ! $installer::globals::helppack )) | ||||
| 1456 | { | ||||
| 1457 | my $filename = $allvariables->{'ADDITIONALREQUIREDPATCHES'}; | ||||
| 1458 | |||||
| 1459 | my $fullfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1); | ||||
| 1460 | if ( $$fullfilenameref eq "" ) { installer::exiter::exit_program("ERROR: Could not find file with required patches, although it is defined: $filename !", "create_msp_patch"); } | ||||
| 1461 | my $fullfilename = $$fullfilenameref; | ||||
| 1462 | |||||
| 1463 | # Reading list file | ||||
| 1464 | my $listfile = installer::files::read_file($fullfilename); | ||||
| 1465 | |||||
| 1466 | # Get name and path of reference database | ||||
| 1467 | my $requiredpatchfile = get_requiredpatchfile_from_list($listfile, $languagestringref, $fullfilename); | ||||
| 1468 | if ( $requiredpatchfile eq "" ) { installer::exiter::exit_program("ERROR: Could not find path to required patch in file $fullfilename for language(s) $$languagestringref!", "create_msp_patch"); } | ||||
| 1469 | |||||
| 1470 | # Copying patch file | ||||
| 1471 | installer::systemactions::copy_one_file($requiredpatchfile, $mspdir); | ||||
| 1472 | # my $infoline = "Copy $requiredpatchfile to $mspdir\n"; | ||||
| 1473 | # push( @installer::globals::logfileinfo, $infoline); | ||||
| 1474 | } | ||||
| 1475 | |||||
| 1476 | # Find all files included into the patch | ||||
| 1477 | # Analyzing the msimsp log file $msimsplogfile | ||||
| 1478 | analyze_msimsp_logfile($msimsplogfile, $filesarray); | ||||
| 1479 | |||||
| 1480 | # Done | ||||
| 1481 | installer::logger::include_timestamp_into_logfile("\nPerformance Info: msp creation done"); | ||||
| 1482 | |||||
| 1483 | return $mspdir; | ||||
| 1484 | } | ||||
| 1485 | |||||
| 1486 | 1 | 11µs | 1; |