Update ooo320-m1
[ooovba.git] / solenv / bin / modules / installer / windows / sign.pm
blob10223f2059c2223d90cee0384746e4b39fa9ea63
1 #*************************************************************************
3 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 #
5 # Copyright 2008 by Sun Microsystems, Inc.
7 # OpenOffice.org - a multi-platform office productivity suite
9 # $RCSfile: binary.pm,v $
11 # This file is part of OpenOffice.org.
13 # OpenOffice.org is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU Lesser General Public License version 3
15 # only, as published by the Free Software Foundation.
17 # OpenOffice.org is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU Lesser General Public License version 3 for more details
21 # (a copy is included in the LICENSE file that accompanied this code).
23 # You should have received a copy of the GNU Lesser General Public License
24 # version 3 along with OpenOffice.org. If not, see
25 # <http://www.openoffice.org/license.html>
26 # for a copy of the LGPLv3 License.
28 #*************************************************************************
30 package installer::windows::sign;
32 use Cwd;
33 use installer::converter;
34 use installer::existence;
35 use installer::files;
36 use installer::globals;
37 use installer::scriptitems;
38 use installer::worker;
39 use installer::windows::admin;
41 ########################################################
42 # Copying an existing Windows installation set.
43 ########################################################
45 sub copy_install_set
47 my ( $installsetpath ) = @_;
49 installer::logger::include_header_into_logfile("Start: Copying installation set $installsetpath");
51 my $infoline = "";
53 my $dirname = $installsetpath;
54 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname);
56 my $path = $installsetpath;
57 installer::pathanalyzer::get_path_from_fullqualifiedname(\$path);
59 $path =~ s/\Q$installer::globals::separator\E\s*$//;
61 if ( $dirname =~ /\./ ) { $dirname =~ s/\./_signed_inprogress./; }
62 else { $dirname = $dirname . "_signed_inprogress"; }
64 my $newpath = $path . $installer::globals::separator . $dirname;
65 my $removepath = $newpath;
66 $removepath =~ s/_inprogress/_witherror/;
68 if ( -d $newpath ) { installer::systemactions::remove_complete_directory($newpath, 1); }
69 if ( -d $removepath ) { installer::systemactions::remove_complete_directory($removepath, 1); }
71 $infoline = "Copy installation set from $installsetpath to $newpath\n";
72 push( @installer::globals::logfileinfo, $infoline);
74 $installsetpath = installer::systemactions::copy_complete_directory($installsetpath, $newpath);
76 installer::logger::include_header_into_logfile("End: Copying installation set $installsetpath");
78 return $newpath;
81 ########################################################
82 # Renaming an existing Windows installation set.
83 ########################################################
85 sub rename_install_set
87 my ( $installsetpath ) = @_;
89 my $infoline = "";
91 my $dirname = $installsetpath;
92 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$dirname);
94 my $path = $installsetpath;
95 installer::pathanalyzer::get_path_from_fullqualifiedname(\$path);
97 $path =~ s/\Q$installer::globals::separator\E\s*$//;
99 if ( $dirname =~ /\./ ) { $dirname =~ s/\./_inprogress./; }
100 else { $dirname = $dirname . "_inprogress"; }
102 my $newpath = $path . $installer::globals::separator . $dirname;
103 my $removepath = $newpath;
104 $removepath =~ s/_inprogress/_witherror/;
106 if ( -d $newpath ) { installer::systemactions::remove_complete_directory($newpath, 1); }
107 if ( -d $removepath ) { installer::systemactions::remove_complete_directory($removepath, 1); }
109 $installsetpath = installer::systemactions::rename_directory($installsetpath, $newpath);
111 return $newpath;
114 #########################################################
115 # Checking the local system
116 # Checking existence of needed files in include path
117 #########################################################
119 sub check_system_path
121 # The following files have to be found in the environment variable PATH
122 # Only, if \"-sign\" is used.
123 # Windows : "msicert.exe", "msidb.exe", "signtool.exe"
125 my @needed_files_in_path = ("msicert.exe", "msidb.exe", "signtool.exe");
126 if ( $installer::globals::internal_cabinet_signing )
128 push(@needed_files_in_path, "cabarc.exe");
129 push(@needed_files_in_path, "makecab.exe");
132 my $onefile;
133 my $error = 0;
134 my $pathvariable = $ENV{'PATH'};
135 my $local_pathseparator = $installer::globals::pathseparator;
137 if( $^O =~ /cygwin/i )
138 { # When using cygwin's perl the PATH variable is POSIX style and ...
139 $pathvariable = qx{cygpath -mp "$pathvariable"} ;
140 # has to be converted to DOS style for further use.
141 $local_pathseparator = ';';
144 my $patharrayref = installer::converter::convert_stringlist_into_array(\$pathvariable, $local_pathseparator);
146 $installer::globals::patharray = $patharrayref;
148 foreach my $onefile ( @needed_files_in_path )
150 installer::logger::print_message( "...... searching $onefile ..." );
152 my $fileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath_classic(\$onefile, $patharrayref , 0);
154 if ( $$fileref eq "" )
156 $error = 1;
157 installer::logger::print_error( "$onefile not found\n" );
159 else
161 installer::logger::print_message( "\tFound: $$fileref\n" );
165 $installer::globals::signfiles_checked = 1;
167 if ( $error ) { installer::exiter::exit_program("ERROR: Could not find all needed files in path!", "check_system_path"); }
170 ######################################################
171 # Making systemcall
172 ######################################################
174 sub make_systemcall
176 my ($systemcall, $displaysystemcall) = @_;
178 installer::logger::print_message( "... $displaysystemcall ...\n" );
180 my $success = 1;
181 my $returnvalue = system($systemcall);
183 my $infoline = "Systemcall: $displaysystemcall\n";
184 push( @installer::globals::logfileinfo, $infoline);
186 if ($returnvalue)
188 $infoline = "ERROR: Could not execute \"$displaysystemcall\"!\n";
189 push( @installer::globals::logfileinfo, $infoline);
190 $success = 0;
192 else
194 $infoline = "Success: Executed \"$displaysystemcall\" successfully!\n";
195 push( @installer::globals::logfileinfo, $infoline);
198 return $success;
201 ######################################################
202 # Making systemcall with warning
203 ######################################################
205 sub make_systemcall_with_warning
207 my ($systemcall, $displaysystemcall) = @_;
209 installer::logger::print_message( "... $displaysystemcall ...\n" );
211 my $success = 1;
212 my $returnvalue = system($systemcall);
214 my $infoline = "Systemcall: $displaysystemcall\n";
215 push( @installer::globals::logfileinfo, $infoline);
217 if ($returnvalue)
219 $infoline = "WARNING: Could not execute \"$displaysystemcall\"!\n";
220 push( @installer::globals::logfileinfo, $infoline);
221 $success = 0;
223 else
225 $infoline = "Success: Executed \"$displaysystemcall\" successfully!\n";
226 push( @installer::globals::logfileinfo, $infoline);
229 return $success;
232 ######################################################
233 # Making systemcall with more return data
234 ######################################################
236 sub execute_open_system_call
238 my ( $systemcall ) = @_;
240 my @openoutput = ();
241 my $success = 1;
243 my $comspec = $ENV{COMSPEC};
244 $comspec = $comspec . " -c ";
246 if( $^O =~ /cygwin/i )
248 # $comspec =~ s/\\/\\\\/g;
249 # $comspec = qx{cygpath -u "$comspec"};
250 # $comspec =~ s/\s*$//g;
251 $comspec = "";
254 my $localsystemcall = "$comspec $systemcall 2>&1 |";
256 open( OPN, "$localsystemcall") or warn "Can't execute $localsystemcall\n";
257 while (<OPN>) { push(@openoutput, $_); }
258 close (OPN);
260 my $returnvalue = $?; # $? contains the return value of the systemcall
262 if ($returnvalue)
264 $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
265 push( @installer::globals::logfileinfo, $infoline);
266 $success = 0;
268 else
270 $infoline = "Success: Executed \"$systemcall\" successfully!\n";
271 push( @installer::globals::logfileinfo, $infoline);
274 return ($success, \@openoutput);
277 ########################################################
278 # Reading first line of pw file.
279 ########################################################
281 sub get_pw
283 my ( $file ) = @_;
285 my $filecontent = installer::files::read_file($file);
287 my $pw = ${$filecontent}[0];
288 $pw =~ s/^\s*//;
289 $pw =~ s/\s*$//;
291 return $pw;
294 ########################################################
295 # Counting the keys of a hash.
296 ########################################################
298 sub get_hash_count
300 my ($hashref) = @_;
302 my $counter = 0;
304 foreach my $key ( keys %{$hashref} ) { $counter++; }
306 return $counter;
309 ############################################################
310 # Collect all DiskIds to the corresponding cabinet files.
311 ############################################################
313 sub analyze_media_file
315 my ($filecontent) = @_;
317 my %diskidhash = ();
319 for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
321 if ( $i < 3 ) { next; }
323 if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
325 my $diskid = $1;
326 my $cabfile = $4;
328 $diskidhash{$cabfile} = $diskid;
332 return \%diskidhash;
335 ########################################################
336 # Collect all DiskIds from database table "Media".
337 ########################################################
339 sub collect_diskid_from_media_table
341 my ($msidatabase, $languagestring) = @_;
343 # creating working directory
344 my $workdir = installer::systemactions::create_directories("media", \$languagestring);
345 installer::windows::admin::extract_tables_from_pcpfile($msidatabase, $workdir, "Media");
347 # Reading tables
348 my $filename = $workdir . $installer::globals::separator . "Media.idt";
349 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find required file: $filename !", "collect_diskid_from_media_table"); }
350 my $filecontent = installer::files::read_file($filename);
351 my $diskidhash = analyze_media_file($filecontent);
353 return $diskidhash;
356 ########################################################
357 # Check, if this installation set contains
358 # internal cabinet files included into the msi
359 # database.
360 ########################################################
362 sub check_for_internal_cabfiles
364 my ($cabfilehash) = @_;
366 my $contains_internal_cabfiles = 0;
367 my %allcabfileshash = ();
369 foreach my $filename ( keys %{$cabfilehash} )
371 if ( $filename =~ /^\s*\#/ ) # starting with a hash
373 $contains_internal_cabfiles = 1;
374 # setting real filename without hash as key and name with hash as value
375 my $realfilename = $filename;
376 $realfilename =~ s/^\s*\#//;
377 $allcabfileshash{$realfilename} = $filename;
381 return ( $contains_internal_cabfiles, \%allcabfileshash );
384 ########################################################
385 # Collecting all files in an installation set.
386 ########################################################
388 sub analyze_installset_content
390 my ( $installsetpath ) = @_;
392 my @sourcefiles = ();
393 my $pathstring = "";
394 installer::systemactions::read_complete_directory($installsetpath, $pathstring, \@sourcefiles);
396 if ( ! ( $#sourcefiles > -1 )) { installer::exiter::exit_program("ERROR: No file in installation set. Path: $installsetpath !", "analyze_installset_content"); }
398 my %allcabfileshash = ();
399 my %allmsidatabaseshash = ();
400 my %allfileshash = ();
401 my $contains_external_cabfiles = 0;
402 my $msidatabase = "";
403 my $contains_msidatabase = 0;
405 for ( my $j = 0; $j <= $#sourcefiles; $j++ )
407 if ( $sourcefiles[$j] =~ /\.cab\s*$/ ) { $allcabfileshash{$sourcefiles[$j]} = 1; }
408 else
410 if ( $sourcefiles[$j] =~ /\.txt\s*$/ ) { next; }
411 if ( $sourcefiles[$j] =~ /\.html\s*$/ ) { next; }
412 if ( $sourcefiles[$j] =~ /\.ini\s*$/ ) { next; }
413 if ( $sourcefiles[$j] =~ /\.bmp\s*$/ ) { next; }
414 if ( $sourcefiles[$j] =~ /\.msi\s*$/ )
416 if ( $msidatabase eq "" ) { $msidatabase = $sourcefiles[$j]; }
417 else { installer::exiter::exit_program("ERROR: There is more than one msi database in installation set. Path: $installsetpath !", "analyze_installset_content"); }
419 $allfileshash{$sourcefiles[$j]} = 1;
423 # Is there at least one cab file in the installation set?
424 my $cabcounter = get_hash_count(\%allcabfileshash);
425 if ( $cabcounter > 0 ) { $contains_external_cabfiles = 1; }
427 # How about a cab file without a msi database?
428 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"); }
430 if ( $msidatabase ne "" ) { $contains_msidatabase = 1; }
432 return (\%allcabfileshash, \%allfileshash, $msidatabase, $contains_external_cabfiles, $contains_msidatabase);
435 ########################################################
436 # Adding content of external cabinet files into the
437 # msi database
438 ########################################################
440 sub msicert_database
442 my ($msidatabase, $allcabfiles, $cabfilehash, $internalcabfile) = @_;
444 my $fullsuccess = 1;
446 foreach my $cabfile ( keys %{$allcabfiles} )
448 my $mediacabfilename = $cabfile;
449 if ( $internalcabfile ) { $mediacabfilename = "\#" . $mediacabfilename; }
450 if ( ! exists($cabfilehash->{$mediacabfilename}) ) { installer::exiter::exit_program("ERROR: Could not determine DiskId from media table for cabinet file \"$cabfile\" !", "msicert_database"); }
451 my $diskid = $cabfilehash->{$mediacabfilename};
453 my $systemcall = "msicert.exe -d $msidatabase -m $diskid -c $cabfile -h";
454 $success = make_systemcall($systemcall, $systemcall);
455 if ( ! $success ) { $fullsuccess = 0; }
458 return $fullsuccess;
461 ########################################################
462 # Signing a list of files
463 ########################################################
465 sub sign_files
467 my ( $followmeinfohash, $allfiles, $pw, $cabinternal ) = @_;
469 my $infoline = "";
470 my $fullsuccess = 1;
471 my $maxcounter = 3;
473 my $productname = "";
474 if ( $followmeinfohash->{'allvariableshash'}->{'PRODUCTNAME'} ) { $productname = "/d " . "\"$followmeinfohash->{'allvariableshash'}->{'PRODUCTNAME'}\""; }
475 my $url = "";
476 if (( ! exists($followmeinfohash->{'allvariableshash'}->{'OPENSOURCE'}) ) || ( $followmeinfohash->{'allvariableshash'}->{'OPENSOURCE'} == 0 )) { $url = "/du " . "\"http://www.sun.com\""; }
477 else { $url = "/du " . "\"http://www.openoffice.org\""; }
478 my $timestampurl = "http://timestamp.verisign.com/scripts/timestamp.dll";
480 my $pfxfilepath = $installer::globals::pfxfile;
482 if( $^O =~ /cygwin/i )
484 $pfxfilepath = qx{cygpath -w "$pfxfilepath"};
485 $pfxfilepath =~ s/\\/\\\\/g;
486 $pfxfilepath =~ s/\s*$//g;
489 foreach my $onefile ( reverse sort keys %{$allfiles} )
491 if ( already_certified($onefile) )
493 $infoline = "Already certified: Skipping file $onefile\n";
494 push( @installer::globals::logfileinfo, $infoline);
495 next;
498 my $counter = 1;
499 my $success = 0;
501 while (( $counter <= $maxcounter ) && ( ! $success ))
503 if ( $counter > 1 ) { installer::logger::print_message( "\n\n... repeating file $onefile ...\n" ); }
504 if ( $cabinternal ) { installer::logger::print_message(" Signing: $onefile\n"); }
505 my $systemcall = "signtool.exe sign /f \"$pfxfilepath\" /p $pw $productname $url /t \"$timestampurl\" \"$onefile\"";
506 my $displaysystemcall = "signtool.exe sign /f \"$pfxfilepath\" /p ***** $productname $url /t \"$timestampurl\" \"$onefile\"";
507 $success = make_systemcall_with_warning($systemcall, $displaysystemcall);
508 $counter++;
511 if ( ! $success )
513 $fullsuccess = 0;
514 installer::exiter::exit_program("ERROR: Could not sign file: $onefile!", "sign_files");
518 return $fullsuccess;
521 ##########################################################################
522 # Lines in ddf files must not contain more than 256 characters
523 ##########################################################################
525 sub check_ddf_file
527 my ( $ddffile, $ddffilename ) = @_;
529 my $maxlength = 0;
530 my $maxline = 0;
531 my $linelength = 0;
532 my $linenumber = 0;
534 for ( my $i = 0; $i <= $#{$ddffile}; $i++ )
536 my $oneline = ${$ddffile}[$i];
538 $linelength = length($oneline);
539 $linenumber = $i + 1;
541 if ( $linelength > 256 )
543 installer::exiter::exit_program("ERROR \"$ddffilename\" line $linenumber: Lines in ddf files must not contain more than 256 characters!", "check_ddf_file");
546 if ( $linelength > $maxlength )
548 $maxlength = $linelength;
549 $maxline = $linenumber;
553 my $infoline = "Check of ddf file \"$ddffilename\": Maximum length \"$maxlength\" in line \"$maxline\" (allowed line length: 256 characters)\n";
554 push( @installer::globals::logfileinfo, $infoline);
557 #################################################################
558 # Setting the path, where the cab files are unpacked.
559 #################################################################
561 sub get_cab_path
563 my ($temppath) = @_;
565 my $cabpath = "cabs_" . $$;
566 $cabpath = $temppath . $installer::globals::separator . $cabpath;
567 if ( ! -d $cabpath ) { installer::systemactions::create_directory($cabpath); }
569 return $cabpath;
572 #################################################################
573 # Exclude all cab files from the msi database.
574 #################################################################
576 sub extract_cabs_from_database
578 my ($msidatabase, $allcabfiles) = @_;
580 installer::logger::include_header_into_logfile("Extracting cabs from msi database");
582 my $infoline = "";
583 my $fullsuccess = 1;
584 my $msidb = "msidb.exe"; # Has to be in the path
586 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
587 $msidatabase =~ s/\//\\\\/g;
589 foreach my $onefile ( keys %{$allcabfiles} )
591 my $systemcall = $msidb . " -d " . $msidatabase . " -x " . $onefile;
592 my $success = make_systemcall($systemcall, $systemcall);
593 if ( ! $success ) { $fullsuccess = 0; }
595 # and removing the stream from the database
596 $systemcall = $msidb . " -d " . $msidatabase . " -k " . $onefile;
597 $success = make_systemcall($systemcall, $systemcall);
598 if ( ! $success ) { $fullsuccess = 0; }
601 return $fullsuccess;
604 #################################################################
605 # Include cab files into the msi database.
606 #################################################################
608 sub include_cabs_into_database
610 my ($msidatabase, $allcabfiles) = @_;
612 installer::logger::include_header_into_logfile("Including cabs into msi database");
614 my $infoline = "";
615 my $fullsuccess = 1;
616 my $msidb = "msidb.exe"; # Has to be in the path
618 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
619 $msidatabase =~ s/\//\\\\/g;
621 foreach my $onefile ( keys %{$allcabfiles} )
623 my $systemcall = $msidb . " -d " . $msidatabase . " -a " . $onefile;
624 my $success = make_systemcall($systemcall, $systemcall);
625 if ( ! $success ) { $fullsuccess = 0; }
628 return $fullsuccess;
631 ########################################################
632 # Reading the order of the files inside the
633 # cabinet files.
634 ########################################################
636 sub read_cab_file
638 my ($cabfilename) = @_;
640 installer::logger::print_message( "\n... reading cabinet file $cabfilename ...\n" );
641 my $infoline = "Reading cabinet file $cabfilename\n";
642 push( @installer::globals::logfileinfo, $infoline);
644 my $systemcall = "cabarc.exe" . " L " . $cabfilename;
645 push(@logfile, "$systemcall\n");
647 my ($success, $fileorder) = execute_open_system_call($systemcall);
649 my @allfiles = ();
651 for ( my $i = 0; $i <= $#{$fileorder}; $i++ )
653 my $line = ${$fileorder}[$i];
654 if ( $line =~ /^\s*(.*?)\s+\d+\s+\d+\/\d+\/\d+\s+\d+\:\d+\:\d+\s+[\w-]+\s*$/ )
656 my $filename = $1;
657 push(@allfiles, $filename);
661 return \@allfiles;
664 ########################################################
665 # Unpacking a cabinet file.
666 ########################################################
668 sub unpack_cab_file
670 my ($cabfilename, $temppath) = @_;
672 installer::logger::print_message( "\n... unpacking cabinet file $cabfilename ...\n" );
673 my $infoline = "Unpacking cabinet file $cabfilename\n";
674 push( @installer::globals::logfileinfo, $infoline);
676 my $dirname = $cabfilename;
677 $dirname =~ s/\.cab\s*$//;
678 my $workingpath = $temppath . $installer::globals::separator . "unpack_". $dirname . "_" . $$;
679 if ( ! -d $workingpath ) { installer::systemactions::create_directory($workingpath); }
681 # changing into unpack directory
682 my $from = cwd();
683 chdir($workingpath);
685 my $fullcabfilename = $from . $installer::globals::separator . $cabfilename;
687 if( $^O =~ /cygwin/i )
689 $fullcabfilename = qx{cygpath -w "$fullcabfilename"};
690 $fullcabfilename =~ s/\\/\\\\/g;
691 $fullcabfilename =~ s/\s*$//g;
694 my $systemcall = "cabarc.exe" . " -p X " . $fullcabfilename;
695 $success = make_systemcall($systemcall, $systemcall);
696 if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not unpack cabinet file: $fullcabfilename!", "unpack_cab_file"); }
698 # returning to directory
699 chdir($from);
701 return $workingpath;
704 ########################################################
705 # Returning the header of a ddf file.
706 ########################################################
708 sub get_ddf_file_header
710 my ($ddffileref, $cabinetfile, $installdir) = @_;
712 my $oneline;
713 my $compressionlevel = 2;
715 if( $^O =~ /cygwin/i )
717 $installdir = qx{cygpath -w "$installdir"};
718 $installdir =~ s/\s*$//g;
721 $oneline = ".Set CabinetName1=" . $cabinetfile . "\n";
722 push(@{$ddffileref} ,$oneline);
723 $oneline = ".Set ReservePerCabinetSize=128\n"; # This reserves space for a digital signature.
724 push(@{$ddffileref} ,$oneline);
725 $oneline = ".Set MaxDiskSize=CDROM\n"; # This allows the .cab file to be as large as needed.
726 push(@{$ddffileref} ,$oneline);
727 $oneline = ".Set CompressionType=LZX\n";
728 push(@{$ddffileref} ,$oneline);
729 $oneline = ".Set Compress=ON\n";
730 push(@{$ddffileref} ,$oneline);
731 $oneline = ".Set CompressionLevel=$compressionlevel\n";
732 push(@{$ddffileref} ,$oneline);
733 $oneline = ".Set Cabinet=ON\n";
734 push(@{$ddffileref} ,$oneline);
735 $oneline = ".Set DiskDirectoryTemplate=" . $installdir . "\n";
736 push(@{$ddffileref} ,$oneline);
739 ########################################################
740 # Writing content into ddf file.
741 ########################################################
743 sub put_all_files_into_ddffile
745 my ($ddffile, $allfiles, $workingpath) = @_;
747 $workingpath =~ s/\//\\/g;
749 for ( my $i = 0; $i <= $#{$allfiles}; $i++ )
751 my $filename = ${$allfiles}[$i];
752 if( $^O =~ /cygwin/i ) { $filename =~ s/\//\\/g; } # Backslash for Cygwin!
753 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file: $filename!", "put_all_files_into_ddffile"); }
754 my $infoline = "\"" . $filename . "\"" . " " . ${$allfiles}[$i] . "\n";
755 push( @{$ddffile}, $infoline);
759 ########################################################
760 # Packing a cabinet file.
761 ########################################################
763 sub do_pack_cab_file
765 my ($cabfilename, $allfiles, $workingpath, $temppath) = @_;
767 installer::logger::print_message( "\n... packing cabinet file $cabfilename ...\n" );
768 my $infoline = "Packing cabinet file $cabfilename\n";
769 push( @installer::globals::logfileinfo, $infoline);
771 if ( -f $cabfilename ) { unlink($cabfilename); } # removing cab file
772 if ( -f $cabfilename ) { installer::exiter::exit_program("ERROR: Failed to remove file: $cabfilename!", "do_pack_cab_file"); }
774 # generate ddf file for makecab.exe
775 my @ddffile = ();
777 my $dirname = $cabfilename;
778 $dirname =~ s/\.cab\s*$//;
779 my $ddfpath = $temppath . $installer::globals::separator . "ddf_". $dirname . "_" . $$;
781 my $ddffilename = $cabfilename;
782 $ddffilename =~ s/.cab/.ddf/;
783 $ddffilename = $ddfpath . $installer::globals::separator . $ddffilename;
785 if ( ! -d $ddfpath ) { installer::systemactions::create_directory($ddfpath); }
787 my $from = cwd();
789 chdir($workingpath); # changing into the directory with the unpacked files
791 get_ddf_file_header(\@ddffile, $cabfilename, $from);
792 put_all_files_into_ddffile(\@ddffile, $allfiles, $workingpath);
793 # lines in ddf files must not be longer than 256 characters
794 check_ddf_file(\@ddffile, $ddffilename);
796 installer::files::save_file($ddffilename, \@ddffile);
798 if( $^O =~ /cygwin/i )
800 $ddffilename = qx{cygpath -w "$ddffilename"};
801 $ddffilename =~ s/\\/\\\\/g;
802 $ddffilename =~ s/\s*$//g;
805 my $systemcall = "makecab.exe /V1 /F " . $ddffilename;
806 my $success = make_systemcall($systemcall, $systemcall);
807 if ( ! $success ) { installer::exiter::exit_program("ERROR: Could not pack cabinet file!", "do_pack_cab_file"); }
809 chdir($from);
811 return ($success);
814 ########################################################
815 # Extraction the file extension from a file
816 ########################################################
818 sub get_extension
820 my ( $file ) = @_;
822 my $extension = "";
824 if ( $file =~ /^\s*(.*)\.(\w+?)\s*$/ ) { $extension = $2; }
826 return $extension;
829 ########################################################
830 # Checking, if a file already contains a certificate.
831 # This must not be overwritten.
832 ########################################################
834 sub already_certified
836 my ( $filename ) = @_;
838 my $success = 1;
839 my $is_certified = 0;
841 my $systemcall = "signtool.exe verify /q /pa \"$filename\"";
842 my $returnvalue = system($systemcall);
844 if ( $returnvalue ) { $success = 0; }
846 # my $success = make_systemcall($systemcall, $systemcall);
848 if ( $success )
850 $is_certified = 1;
851 installer::logger::print_message( "... already certified -> skipping $filename ...\n" );
854 return $is_certified;
857 ########################################################
858 # Signing the files, that are included into
859 # cabinet files.
860 ########################################################
862 sub sign_files_in_cabinet_files
864 my ( $followmeinfohash, $allcabfiles, $pw, $temppath ) = @_;
866 my $complete_success = 1;
867 my $from = cwd();
869 foreach my $cabfilename ( keys %{$allcabfiles} )
871 my $success = 1;
873 # saving order of files in cab file
874 my $fileorder = read_cab_file($cabfilename);
876 # unpack into $working path
877 my $workingpath = unpack_cab_file($cabfilename, $temppath);
879 chdir($workingpath);
881 # sign files
882 my %allfileshash = ();
883 foreach my $onefile ( @{$fileorder} )
885 my $extension = get_extension($onefile);
886 if ( exists( $installer::globals::sign_extensions{$extension} ) )
888 $allfileshash{$onefile} = 1;
891 $success = sign_files($followmeinfohash, \%allfileshash, $pw, 1);
892 if ( ! $success ) { $complete_success = 0; }
894 chdir($from);
896 # pack into new directory
897 do_pack_cab_file($cabfilename, $fileorder, $workingpath, $temppath);
900 return $complete_success;
903 ########################################################
904 # Signing an existing Windows installation set.
905 ########################################################
907 sub sign_install_set
909 my ($followmeinfohash, $make_copy, $temppath) = @_;
911 my $installsetpath = $followmeinfohash->{'finalinstalldir'};
913 installer::logger::include_header_into_logfile("Start: Signing installation set $installsetpath");
915 my $complete_success = 1;
916 my $success = 1;
918 my $infoline = "Signing installation set in $installsetpath\n";
919 push( @installer::globals::logfileinfo, $infoline);
921 # check required files.
922 if ( ! $installer::globals::signfiles_checked ) { check_system_path(); }
924 # get cerficate information
925 my $pw = get_pw($installer::globals::pwfile);
927 # making a copy of the installation set, if required
928 if ( $make_copy ) { $installsetpath = copy_install_set($installsetpath); }
929 else { $installsetpath = rename_install_set($installsetpath); }
931 # collecting all files in the installation set
932 my ($allcabfiles, $allfiles, $msidatabase, $contains_external_cabfiles, $contains_msidatabase) = analyze_installset_content($installsetpath);
934 # changing into installation set
935 my $from = cwd();
936 my $fullmsidatabase = $installsetpath . $installer::globals::separator . $msidatabase;
938 if( $^O =~ /cygwin/i )
940 $fullmsidatabase = qx{cygpath -w "$fullmsidatabase"};
941 $fullmsidatabase =~ s/\\/\\\\/g;
942 $fullmsidatabase =~ s/\s*$//g;
945 chdir($installsetpath);
947 if ( $contains_msidatabase )
949 # exclude media table from msi database and get all diskids.
950 my $cabfilehash = collect_diskid_from_media_table($msidatabase, $followmeinfohash->{'languagestring'});
952 # Check, if there are internal cab files
953 my ( $contains_internal_cabfiles, $all_internal_cab_files) = check_for_internal_cabfiles($cabfilehash);
955 if ( $contains_internal_cabfiles )
957 my $cabpath = get_cab_path($temppath);
958 chdir($cabpath);
960 # Exclude all cabinet files from database
961 $success = extract_cabs_from_database($fullmsidatabase, $all_internal_cab_files);
962 if ( ! $success ) { $complete_success = 0; }
964 if ( $installer::globals::internal_cabinet_signing ) { sign_files_in_cabinet_files($followmeinfohash, $all_internal_cab_files, $pw, $temppath); }
966 $success = sign_files($followmeinfohash, $all_internal_cab_files, $pw, 0);
967 if ( ! $success ) { $complete_success = 0; }
968 $success = msicert_database($fullmsidatabase, $all_internal_cab_files, $cabfilehash, 1);
969 if ( ! $success ) { $complete_success = 0; }
971 # Include all cabinet files into database
972 $success = include_cabs_into_database($fullmsidatabase, $all_internal_cab_files);
973 if ( ! $success ) { $complete_success = 0; }
974 chdir($installsetpath);
977 # Warning: There might be a problem with very big cabinet files
978 # signing all external cab files first
979 if ( $contains_external_cabfiles )
981 if ( $installer::globals::internal_cabinet_signing ) { sign_files_in_cabinet_files($followmeinfohash, $allcabfiles, $pw, $temppath); }
983 $success = sign_files($followmeinfohash, $allcabfiles, $pw, 0);
984 if ( ! $success ) { $complete_success = 0; }
985 $success = msicert_database($msidatabase, $allcabfiles, $cabfilehash, 0);
986 if ( ! $success ) { $complete_success = 0; }
990 # finally all other files can be signed
991 $success = sign_files($followmeinfohash, $allfiles, $pw, 0);
992 if ( ! $success ) { $complete_success = 0; }
994 # and changing back
995 chdir($from);
997 installer::logger::include_header_into_logfile("End: Signing installation set $installsetpath");
999 return ($installsetpath);