xref: /AOO41X/main/solenv/bin/modules/installer/archivefiles.pm (revision ff0525f24f03981d56b7579b645949f111420994)
1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22
23
24package installer::archivefiles;
25
26use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
27use installer::converter;
28use installer::existence;
29use installer::exiter;
30use installer::files;
31use installer::globals;
32use installer::logger;
33use installer::pathanalyzer;
34use installer::systemactions;
35
36#################################################################
37# Changing the name for files with flag RENAME_TO_LANGUAGE
38#################################################################
39
40sub put_language_into_name
41{
42    my ( $oldname, $onelanguage ) = @_;
43
44    my $newname = "";
45
46    my $filename = "";
47    my $extension = "";
48
49    if ( $oldname =~ /en-US/ )  # files, that contain the language in the file name
50    {
51        $newname = $oldname;
52        $newname =~ s/en-US/$onelanguage/;
53    }
54    else    # files, that do not contain the language in the file name
55    {
56        if ( $oldname =~ /^\s*(.*)(\..*?)\s*$/ )    # files with extension
57        {
58            $filename = $1;
59            $extension = $2;
60        }
61        else
62        {
63            $filename = $oldname;
64            $extension = "";
65        }
66
67        $newname = $1 . "_" . $onelanguage . $2;
68    }
69
70    return $newname;
71}
72
73#################################################################
74# Converting patchfiles string into array
75#################################################################
76
77sub get_patch_file_list
78{
79    my ( $patchfilestring ) = @_;
80
81    $patchfilestring =~ s/^\s*\(?//;
82    $patchfilestring =~ s/\)?\s*$//;
83    $patchfilestring =~ s/^\s*\///;
84    $patchfilestring =~ s/^\s*\\//;
85
86    my $patchfilesarray = installer::converter::convert_stringlist_into_array_without_linebreak_and_quotes(\$patchfilestring, ",");
87
88    return $patchfilesarray;
89}
90
91#################################################################
92# Reading all executables in the "manifest.xml"
93#################################################################
94
95sub get_all_executables_from_manifest
96{
97    my ($unzipdir, $manifestfile, $executable_files_in_extensions) = @_;
98
99    my $is_executable = 0;
100
101    for ( my $i = 0; $i <= $#{$manifestfile}; $i++ )
102    {
103        my $line = ${$manifestfile}[$i];
104
105        if ( $line =~ /\"application\/vnd\.sun\.star\.executable\"/ ) { $is_executable = 1; }
106
107        if (( $line =~ /manifest\:full\-path=\"(.*?)\"/ ) && ( $is_executable ))
108        {
109            my $filename = $unzipdir . $installer::globals::separator . $1;
110            # making only slashes for comparison reasons
111            $filename =~ s/\\/\//g;
112            $executable_files_in_extensions->{$filename} = 1;
113        }
114
115        if ( $line =~ /\/\>/ ) { $is_executable = 0; }
116    }
117}
118
119#################################################################
120# Reading the "manifest.xml" in extensions and determine, if
121# there are executable files
122#################################################################
123
124sub collect_all_executable_files_in_extensions
125{
126    my ($unzipdir, $executable_files_in_extensions) = @_;
127
128    $unzipdir =~ s/\Q$installer::globals::separator\E\s*$//;
129
130    my $manifestfilename = $unzipdir . $installer::globals::separator . "META-INF" . $installer::globals::separator . "manifest.xml";
131
132    if ( -f $manifestfilename )
133    {
134        my $manifestfile = installer::files::read_file($manifestfilename);
135        get_all_executables_from_manifest($unzipdir, $manifestfile, $executable_files_in_extensions);
136    }
137}
138
139#################################################################
140# Analyzing files with flag ARCHIVE
141#################################################################
142
143sub resolving_archive_flag
144{
145    my ($filesarrayref, $additionalpathsref, $languagestringref, $loggingdir) = @_;
146
147    if ( $installer::globals::debug ) { installer::logger::debuginfo("installer::archivefiles::resolving_archive_flag : $#{$filesarrayref} : $#{$additionalpathsref} : $$languagestringref : $loggingdir"); }
148
149    my @newallfilesarray = ();
150
151    my ($systemcall, $returnvalue, $infoline);
152
153    my $unziplistfile = $loggingdir . "unziplist_" . $installer::globals::build . "_" . $installer::globals::compiler . "_" . $$languagestringref . ".txt";
154
155    my $platformunzipdirbase = installer::systemactions::create_directories("zip", $languagestringref);
156    push(@installer::globals::removedirs, $platformunzipdirbase);
157
158    installer::logger::include_header_into_logfile("Files with flag ARCHIVE:");
159
160    my $repeat_unzip = 0;
161    my $maxcounter = 0;
162
163    for ( my $i = 0; $i <= $#{$filesarrayref}; $i++ )
164    {
165        if ( $repeat_unzip ) { $i--; }  # decreasing the counter
166
167        my $onefile = ${$filesarrayref}[$i];
168        my $styles = "";
169
170        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
171
172        if ( $styles =~ /\bARCHIVE\b/ )     # copying, unzipping and changing the file list
173        {
174            my $iscommonfile = 0;
175            my $sourcepath = $onefile->{'sourcepath'};
176
177            if ( $sourcepath =~ /\Q$installer::globals::separator\E\bcommon$installer::globals::productextension\Q$installer::globals::separator\E/ )   # /common/ or /common.pro/
178            {
179                $iscommonfile = 1;
180            }
181
182            my $use_internal_rights = 0;
183            if ( $styles =~ /\bUSE_INTERNAL_RIGHTS\b/ ) { $use_internal_rights = 1; }   # using the rights used inside the zip file
184
185            my $rename_to_language = 0;
186            if ( $styles =~ /\bRENAME_TO_LANGUAGE\b/ ) { $rename_to_language = 1; } # special handling for renamed files (scriptitems.pm)
187
188            my %executable_files_in_extensions = ();
189            my $set_executable_privileges = 0;  # setting privileges for exectables is required for oxt files
190            if ( $onefile->{'Name'} =~ /\.oxt\s*$/ ) { $set_executable_privileges = 1; }
191
192            # mechanism to select files from an archive files
193            my $select_files = 0;
194            my $selectlistfiles = "";
195            my @keptfiles = ();
196            if ( $onefile->{'Selectfiles'} )
197            {
198                $select_files = 1;
199                $selectlistfiles = get_patch_file_list( $onefile->{'Selectfiles'} );
200                $infoline = "Selected file list defined at file: $onefile->{'Name'} :\n";
201                push( @installer::globals::logfileinfo, $infoline);
202                for ( my $k = 0; $k <= $#{$selectlistfiles}; $k++ )
203                {
204                    $infoline = "\"${$selectlistfiles}[$k]\"\n";
205                    push( @installer::globals::logfileinfo, $infoline);
206                }
207            }
208
209            if ( $onefile->{'Selectfiles'} ) { $onefile->{'Selectfiles'} = ""; } # Selected files list no longer required
210
211            # mechanism to define patch files inside an archive files
212            my $select_patch_files = 0;
213            my $patchlistfiles = "";
214            my @keptpatchflags = ();
215            if (( $styles =~ /\bPATCH\b/ ) && ( $onefile->{'Patchfiles'} ) && ( $installer::globals::patch ))
216            {
217                $select_patch_files = 1; # special handling if a Patchlist is defined
218                $patchlistfiles = get_patch_file_list( $onefile->{'Patchfiles'} );
219                $infoline = "Patch file list defined at file: $onefile->{'Name'} :\n";
220                push( @installer::globals::logfileinfo, $infoline);
221                for ( my $k = 0; $k <= $#{$patchlistfiles}; $k++ )
222                {
223                    $infoline = "\"${$patchlistfiles}[$k]\"\n";
224                    push( @installer::globals::logfileinfo, $infoline);
225                }
226            }
227
228            if ( $onefile->{'Patchfiles'} ) { $onefile->{'Patchfiles'} = ""; } # Patch file list no longer required
229
230            # creating directories
231
232            my $onelanguage = $onefile->{'specificlanguage'};
233
234            # files without language into directory "00"
235
236            if ($onelanguage eq "") { $onelanguage = "00"; }
237
238            my $unzipdir;
239
240            # if ($iscommonfile) { $unzipdir = $commonunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }
241            # else { $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }
242
243            $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator;
244
245            installer::systemactions::create_directory($unzipdir);  # creating language specific subdirectories
246
247            my $onefilename = $onefile->{'Name'};
248            $onefilename =~ s/\./\_/g;      # creating new directory name
249            $onefilename =~ s/\//\_/g;      # only because of /letter/fontunxpsprint.zip, the only zip file with path
250            $unzipdir = $unzipdir . $onefilename . $installer::globals::separator;
251
252            if ( $installer::globals::dounzip ) { installer::systemactions::create_directory($unzipdir); }  # creating subdirectories with the names of the zipfiles
253
254            my $zip = Archive::Zip->new();
255            if ( $zip->read($sourcepath) != AZ_OK )
256            {
257                $infoline = "ERROR: Could not unzip $sourcepath\n";
258                push( @installer::globals::logfileinfo, $infoline);
259            }
260
261            my $counter = 0;
262            my $contains_dll = 0;
263            foreach my $member ( $zip->memberNames() )
264            {
265                $counter++;
266                if ( $member =~ /.dll\s*$/ ) { $contains_dll = 1; }
267            }
268
269            if (! ( $counter > 0 )) # the zipfile is empty
270            {
271                $infoline = "ERROR: Could not unzip $sourcepath\n";
272                push( @installer::globals::logfileinfo, $infoline);
273
274            }
275            else
276            {
277                if ( $installer::globals::dounzip )         # really unpacking the files
278                {
279                    if ( $zip->extractTree("", $unzipdir) != AZ_OK ) { installer::exiter::exit_program("ERROR: $infoline", "resolving_archive_flag"); }
280
281                    if (( $^O =~ /cygwin/i ) && ( $contains_dll ))
282                    {
283                        # Make dll's executable
284                        $systemcall = "cd $unzipdir; find . -name \\*.dll -exec chmod 775 \{\} \\\;";
285                        $returnvalue = system($systemcall);
286                        $infoline = "Systemcall: $systemcall\n";
287                        push( @installer::globals::logfileinfo, $infoline);
288
289                        if ($returnvalue)
290                        {
291                            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
292                            push( @installer::globals::logfileinfo, $infoline);
293                        }
294                    }
295
296                    if ( ! $installer::globals::iswindowsbuild )
297                    {
298                        # Setting unix rights to "775" for all created directories inside the package
299
300                        $systemcall = "cd $unzipdir; find . -type d -exec chmod 775 \{\} \\\;";
301                        $returnvalue = system($systemcall);
302                        $infoline = "Systemcall: $systemcall\n";
303                        push( @installer::globals::logfileinfo, $infoline);
304
305                        if ($returnvalue)
306                        {
307                            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
308                            push( @installer::globals::logfileinfo, $infoline);
309                        }
310                    }
311
312                    # Selecting names of executable files in extensions
313                    if ( $set_executable_privileges )
314                    {
315                        collect_all_executable_files_in_extensions($unzipdir, \%executable_files_in_extensions);
316                    }
317                }
318
319                my $zipfileref = \@zipfile;
320                my $unziperror = 0;
321
322                foreach my $zipname ( $zip->memberNames() )
323                {
324                    # Format from Archive:::Zip :
325                    # dir1/
326                    # dir1/so7drawing.desktop
327
328                    # some directories and files (from the help) start with "./simpress.idx"
329
330                    $zipname =~ s/^\s*\.\///;
331
332                    if ($installer::globals::iswin and $^O =~ /MSWin/i) { $zipname =~ s/\//\\/g; }
333
334                    if ( $zipname =~ /\Q$installer::globals::separator\E\s*$/ ) # slash or backslash at the end characterizes a directory
335                    {
336                        $zipname = $zipname . "\n";
337                        push(@{$additionalpathsref}, $zipname);
338
339                        # Also needed here:
340                        # Name
341                        # Language
342                        # ismultilingual
343                        # Basedirectory
344
345                        # This is not needed, because the list of all directories for the
346                        # epm list file is generated from the destination directories of the
347                        # files included in the product!
348                    }
349                    else
350                    {
351                        my %newfile = ();
352                        %newfile = %{$onefile};
353                        $newfile{'Name'} = $zipname;
354                        my $destination = $onefile->{'destination'};
355                        installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
356                        $newfile{'destination'} = $destination . $zipname;
357                        $newfile{'sourcepath'} = $unzipdir . $zipname;
358                        $newfile{'zipfilename'} = $onefile->{'Name'};
359                        $newfile{'zipfilesource'} = $onefile->{'sourcepath'};
360                        $newfile{'zipfiledestination'} = $onefile->{'destination'};
361
362                        if (( $use_internal_rights ) && ( ! $installer::globals::iswin ))
363                        {
364                            my $value = sprintf("%o", (stat($newfile{'sourcepath'}))[2]);
365                            $newfile{'UnixRights'} = substr($value, 3);
366                            $infoline = "Setting unix rights for \"$newfile{'sourcepath'}\" to \"$newfile{'UnixRights'}\"\n";
367                            push( @installer::globals::logfileinfo, $infoline);
368                        }
369
370                        if ( $set_executable_privileges )
371                        {
372                            # All pathes to executables are saved in the hash %executable_files_in_extensions
373                            my $compare_path = $newfile{'sourcepath'};
374                            $compare_path =~ s/\\/\//g;  # contains only slashes for comparison reasons
375                            if ( exists($executable_files_in_extensions{$compare_path}) )
376                            {
377                                $newfile{'UnixRights'} = "775";
378                                $infoline = "Executable in Extension: Setting unix rights for \"$newfile{'sourcepath'}\" to \"$newfile{'UnixRights'}\"\n";
379                                push( @installer::globals::logfileinfo, $infoline);
380                            }
381                        }
382
383                        if ( $select_files )
384                        {
385                            if ( ! installer::existence::exists_in_array($zipname,$selectlistfiles) )
386                            {
387                                $infoline = "Removing from ARCHIVE file $onefilename: $zipname\n";
388                                push( @installer::globals::logfileinfo, $infoline);
389                                next; # ignoring files, that are not included in $selectlistfiles
390                            }
391                            else
392                            {
393                                $infoline = "Keeping from ARCHIVE file $onefilename: $zipname\n";
394                                push( @installer::globals::logfileinfo, $infoline);
395                                push( @keptfiles, $zipname); # collecting all kept files
396                            }
397                        }
398
399                        if ( $select_patch_files )
400                        {
401                            # Is this file listed in the Patchfile list?
402                            # $zipname (filename including path in zip file has to be listed in patchfile list
403
404                            if ( ! installer::existence::exists_in_array($zipname,$patchlistfiles) )
405                            {
406                                $newfile{'Styles'} =~ s/\bPATCH\b//;    # removing the flag PATCH
407                                $newfile{'Styles'} =~ s/\,\s*\,/\,/;
408                                $newfile{'Styles'} =~ s/\(\s*\,/\(/;
409                                $newfile{'Styles'} =~ s/\,\s*\)/\)/;
410                                # $infoline = "Removing PATCH flag from: $zipname\n";
411                                # push( @installer::globals::logfileinfo, $infoline);
412                            }
413                            else
414                            {
415                                # $infoline = "Keeping PATCH flag at: $zipname\n";
416                                # push( @installer::globals::logfileinfo, $infoline);
417                                push( @keptpatchflags, $zipname); # collecting all PATCH flags
418                            }
419                        }
420
421                        if ( $rename_to_language )
422                        {
423                            my $newzipname = put_language_into_name($zipname, $onelanguage);
424                            my $oldfilename = $unzipdir . $zipname;
425                            my $newfilename = $unzipdir . $newzipname;
426
427                            installer::systemactions::copy_one_file($oldfilename, $newfilename);
428
429                            $newfile{'Name'} = $newzipname;
430                            $newfile{'destination'} = $destination . $newzipname;
431                            $newfile{'sourcepath'} = $unzipdir . $newzipname;
432
433                            $infoline = "RENAME_TO_LANGUAGE: Using $newzipname instead of $zipname!\n";
434                            push( @installer::globals::logfileinfo, $infoline);
435                        }
436
437                        my $sourcefiletest = $unzipdir . $zipname;
438                        if ( ! -f $sourcefiletest )
439                        {
440                            $infoline = "ATTENTION: Unzip failed for $sourcefiletest!\n";
441                            push( @installer::globals::logfileinfo, $infoline);
442                            $unziperror = 1;
443                        }
444
445                        # only adding the new line into the files array, if not in repeat modus
446
447                        if ( ! $repeat_unzip ) { push(@newallfilesarray, \%newfile); }
448                    }
449                }
450
451                # Comparing the content of @keptfiles and $selectlistfiles
452                # Do all files from the list of selected files are stored in @keptfiles ?
453                # @keptfiles contains only files included in $selectlistfiles. But are all
454                # files from $selectlistfiles included in @keptfiles?
455
456                if ( $select_files )
457                {
458                    my $number = $#{$selectlistfiles} + 1;
459                    $infoline = "SELECTLIST: Number of files in file selection list: $number\n";
460                    push( @installer::globals::logfileinfo, $infoline);
461                    $number = $#keptfiles + 1;
462                    $infoline = "SELECTLIST: Number of kept files: $number\n";
463                    push( @installer::globals::logfileinfo, $infoline);
464
465                    for ( my $k = 0; $k <= $#keptfiles; $k++ )
466                    {
467                        $infoline = "KEPT FILES: $keptfiles[$k]\n";
468                        push( @installer::globals::logfileinfo, $infoline);
469                    }
470
471                    my @warningfiles = ();
472
473                    for ( my $k = 0; $k <= $#{$selectlistfiles}; $k++ )
474                    {
475                        if ( ! installer::existence::exists_in_array(${$selectlistfiles}[$k],\@keptfiles) )
476                        {
477                            push(@warningfiles, ${$selectlistfiles}[$k]);
478                        }
479                    }
480
481                    for ( my $k = 0; $k <= $#warningfiles; $k++ )
482                    {
483                        $infoline = "WARNING: $warningfiles[$k] not included in install set (does not exist in zip file)!\n";
484                        push( @installer::globals::logfileinfo, $infoline);
485                    }
486
487                }
488
489                # Comparing the content of @keptpatchflags and $patchlistfiles
490                # Do all files from the patch list have a PATCH flag ?
491                # @keptpatchflags contains only files included in $patchlistfiles. But are all
492                # files from $patchlistfiles included in @keptpatchflags?
493
494                if ( $select_patch_files )
495                {
496                    my $number = $#{$patchlistfiles} + 1;
497                    $infoline = "PATCHLIST: Number of files in patch list: $number\n";
498                    push( @installer::globals::logfileinfo, $infoline);
499                    $number = $#keptpatchflags + 1;
500                    $infoline = "PATCHLIST: Number of kept PATCH flags: $number\n";
501                    push( @installer::globals::logfileinfo, $infoline);
502
503                    for ( my $k = 0; $k <= $#keptpatchflags; $k++ )
504                    {
505                        $infoline = "KEPT PATCH FLAGS: $keptpatchflags[$k]\n";
506                        push( @installer::globals::logfileinfo, $infoline);
507                    }
508
509                    my @warningfiles = ();
510
511                    for ( my $k = 0; $k <= $#{$patchlistfiles}; $k++ )
512                    {
513                        if ( ! installer::existence::exists_in_array(${$patchlistfiles}[$k],\@keptpatchflags) )
514                        {
515                            push(@warningfiles, ${$patchlistfiles}[$k]);
516                        }
517                    }
518
519                    for ( my $k = 0; $k <= $#warningfiles; $k++ )
520                    {
521                        $infoline = "WARNING: $warningfiles[$k] did not keep PATCH flag (does not exist in zip file)!\n";
522                        push( @installer::globals::logfileinfo, $infoline);
523                    }
524                }
525
526                if ( $unziperror )
527                {
528                    installer::logger::print_warning( "Repeating to unpack $sourcepath! \n" );
529                    $infoline = "ATTENTION: Repeating to unpack $sourcepath !\n";
530                    push( @installer::globals::logfileinfo, $infoline);
531                    $repeat_unzip = 1;
532                    $maxcounter++;
533
534                    if ( $maxcounter == 5 ) # exiting the program
535                    {
536                        installer::exiter::exit_program("ERROR: Failed to unzip $sourcepath !", "resolving_archive_flag");
537                    }
538                }
539                else
540                {
541                    $infoline = "Info: $sourcepath unpacked without problems !\n";
542                    push( @installer::globals::logfileinfo, $infoline);
543                    $repeat_unzip = 0;
544                    $maxcounter = 0;
545                }
546            }
547        }
548        else        # nothing to do here, no zipped file (no ARCHIVE flag)
549        {
550            push(@newallfilesarray, $onefile);
551        }
552    }
553
554    $infoline = "\n";
555    push( @installer::globals::logfileinfo, $infoline);
556
557    return \@newallfilesarray;
558}
559
560
5611;
562