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