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 | BEGIN@39 | installer::windows::msp::
1 | 1 | 1 | 5.75ms | 6.24ms | BEGIN@41 | installer::windows::msp::
1 | 1 | 1 | 446µs | 543µs | BEGIN@30 | installer::windows::msp::
1 | 1 | 1 | 21µs | 24µs | BEGIN@40 | installer::windows::msp::
1 | 1 | 1 | 18µs | 20µs | BEGIN@31 | installer::windows::msp::
1 | 1 | 1 | 17µs | 18µs | BEGIN@38 | installer::windows::msp::
1 | 1 | 1 | 17µs | 19µs | BEGIN@32 | installer::windows::msp::
1 | 1 | 1 | 17µs | 19µs | BEGIN@34 | installer::windows::msp::
1 | 1 | 1 | 16µs | 18µs | BEGIN@33 | installer::windows::msp::
1 | 1 | 1 | 16µs | 18µs | BEGIN@37 | installer::windows::msp::
1 | 1 | 1 | 15µs | 42µs | BEGIN@36 | installer::windows::msp::
1 | 1 | 1 | 15µs | 17µs | BEGIN@35 | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | analyze_msimsp_logfile | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_imagefamilies_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_patchmetadata_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_patchsequence_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_properties_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_targetimages_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | change_upgradedimages_table | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | check_and_save_tables | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | collect_patch_file_destinations | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | convert_unicode_to_ascii | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | correct_langs | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | correct_patch | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | create_langstring | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | create_msp_patch | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | edit_tables | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | execute_msimsp | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | extract_all_tables_from_pcpfile | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_filesequencestart | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_first_path_segment | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_patchid_from_list | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_patchsequence | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_patchtime_value | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_requiredpatchfile_from_list | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | get_supersede | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | include_tables_into_pcpfile | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | install_installation_sets | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | prepare_path_in_nopatchfilehash | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | set_mspfilename | installer::windows::msp::
0 | 0 | 0 | 0s | 0s | synchronize_installation_sets | installer::windows::msp::
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; |