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