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