xref: /AOO41X/main/solenv/bin/modules/installer/archivefiles.pm (revision fe22d2cfc602815794415026f1317bd625db6f83)
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                $installer::logging::Lang->printf("Selected file list defined at file: %s :\n", $onefile->{'Name'});
201                foreach my $line (@$selectlistfiles)
202                {
203                    $installer::logging::Lang->printf("\"%s\"\n", $line);
204                }
205            }
206
207            if ( $onefile->{'Selectfiles'} ) { $onefile->{'Selectfiles'} = ""; } # Selected files list no longer required
208
209            # mechanism to define patch files inside an archive files
210            my $select_patch_files = 0;
211            my $patchlistfiles = "";
212            my @keptpatchflags = ();
213            if (( $styles =~ /\bPATCH\b/ ) && ( $onefile->{'Patchfiles'} ) && ( $installer::globals::patch ))
214            {
215                $select_patch_files = 1; # special handling if a Patchlist is defined
216                $patchlistfiles = get_patch_file_list( $onefile->{'Patchfiles'} );
217                $installer::logger::Lang->printf("Patch file list defined at file: %s :\n", $onefile->{'Name'});
218                foreach my $line (@$patchlistfiles)
219                {
220                    $installer::logger::Lang->printf("\"%s\"\n", $line);
221                }
222            }
223
224            if ( $onefile->{'Patchfiles'} ) { $onefile->{'Patchfiles'} = ""; } # Patch file list no longer required
225
226            # creating directories
227
228            my $onelanguage = $onefile->{'specificlanguage'};
229
230            # files without language into directory "00"
231
232            if ($onelanguage eq "") { $onelanguage = "00"; }
233
234            my $unzipdir;
235
236            # if ($iscommonfile) { $unzipdir = $commonunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }
237            # else { $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }
238
239            $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator;
240
241            installer::systemactions::create_directory($unzipdir);  # creating language specific subdirectories
242
243            my $onefilename = $onefile->{'Name'};
244            $onefilename =~ s/\./\_/g;      # creating new directory name
245            $onefilename =~ s/\//\_/g;      # only because of /letter/fontunxpsprint.zip, the only zip file with path
246            $unzipdir = $unzipdir . $onefilename . $installer::globals::separator;
247
248            if ( $installer::globals::dounzip ) { installer::systemactions::create_directory($unzipdir); }  # creating subdirectories with the names of the zipfiles
249
250            my $zip = Archive::Zip->new();
251            if ( $zip->read($sourcepath) != AZ_OK )
252            {
253                $installer::logger::Lang->printf("ERROR: Could not unzip %s\n", $sourcepath);
254            }
255
256            my $counter = 0;
257            my $contains_dll = 0;
258            foreach my $member ( $zip->memberNames() )
259            {
260                $counter++;
261                if ( $member =~ /.dll\s*$/ ) { $contains_dll = 1; }
262            }
263
264            if (! ( $counter > 0 )) # the zipfile is empty
265            {
266                $installer::logger::Lang->printf("ERROR: Could not unzip %s\n", $sourcepath);
267            }
268            else
269            {
270                if ( $installer::globals::dounzip )         # really unpacking the files
271                {
272                    if ( $zip->extractTree("", $unzipdir) != AZ_OK )
273                    {
274                        installer::exiter::exit_program("ERROR: can not unzip ".$sourcepath, "resolving_archive_flag");
275                    }
276
277                    if (( $^O =~ /cygwin/i ) && ( $contains_dll ))
278                    {
279                        # Make dll's executable
280                        $systemcall = "cd $unzipdir; find . -name \\*.dll -exec chmod 775 \{\} \\\;";
281                        $returnvalue = system($systemcall);
282                        $installer::logger::Lang->printf("Systemcall: %s\n", $systemcall);
283
284                        if ($returnvalue)
285                        {
286                            $installer::logger::Lang->printf("ERROR: Could not execute \"\"!\n", $systemcall);
287                        }
288                    }
289
290                    if ( ! $installer::globals::iswindowsbuild )
291                    {
292                        # Setting unix rights to "775" for all created directories inside the package
293
294                        $systemcall = "cd $unzipdir; find . -type d -exec chmod 775 \{\} \\\;";
295                        $returnvalue = system($systemcall);
296                        $installer::logger::Lang->printf("Systemcall: %s\n", $systemcall);
297                        if ($returnvalue)
298                        {
299                            $installer::logger::Lang->printf("ERROR: Could not execute \"\"!\n", $systemcall);
300                        }
301                    }
302
303                    # Selecting names of executable files in extensions
304                    if ( $set_executable_privileges )
305                    {
306                        collect_all_executable_files_in_extensions($unzipdir, \%executable_files_in_extensions);
307                    }
308                }
309
310                my $zipfileref = \@zipfile;
311                my $unziperror = 0;
312
313                foreach my $zipname ( $zip->memberNames() )
314                {
315                    # Format from Archive:::Zip :
316                    # dir1/
317                    # dir1/so7drawing.desktop
318
319                    # some directories and files (from the help) start with "./simpress.idx"
320
321                    $zipname =~ s/^\s*\.\///;
322
323                    if ($installer::globals::iswin and $^O =~ /MSWin/i) { $zipname =~ s/\//\\/g; }
324
325                    if ( $zipname =~ /\Q$installer::globals::separator\E\s*$/ ) # slash or backslash at the end characterizes a directory
326                    {
327                        $zipname = $zipname . "\n";
328                        push(@{$additionalpathsref}, $zipname);
329
330                        # Also needed here:
331                        # Name
332                        # Language
333                        # ismultilingual
334                        # Basedirectory
335
336                        # This is not needed, because the list of all directories for the
337                        # epm list file is generated from the destination directories of the
338                        # files included in the product!
339                    }
340                    else
341                    {
342                        my %newfile = ();
343                        %newfile = %{$onefile};
344                        $newfile{'Name'} = $zipname;
345                        my $destination = $onefile->{'destination'};
346                        installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
347                        $newfile{'destination'} = $destination . $zipname;
348                        $newfile{'sourcepath'} = $unzipdir . $zipname;
349                        $newfile{'zipfilename'} = $onefile->{'Name'};
350                        $newfile{'zipfilesource'} = $onefile->{'sourcepath'};
351                        $newfile{'zipfiledestination'} = $onefile->{'destination'};
352
353                        if (( $use_internal_rights ) && ( ! $installer::globals::iswin ))
354                        {
355                            my $value = sprintf("%o", (stat($newfile{'sourcepath'}))[2]);
356                            $newfile{'UnixRights'} = substr($value, 3);
357                            $installer::logger::Lang->printf(
358                                "Setting unix rights for \"%s\" to \"%s\"\n",
359                                $newfile{'sourcepath'},
360                                $newfile{'UnixRights'});
361                        }
362
363                        if ( $set_executable_privileges )
364                        {
365                            # All pathes to executables are saved in the hash %executable_files_in_extensions
366                            my $compare_path = $newfile{'sourcepath'};
367                            $compare_path =~ s/\\/\//g;  # contains only slashes for comparison reasons
368                            if ( exists($executable_files_in_extensions{$compare_path}) )
369                            {
370                                $newfile{'UnixRights'} = "775";
371                                $installer::logger::Lang->printf(
372                                    "Executable in Extension: Setting unix rights for \"%s\" to \"%s\"\n",
373                                    $newfile{'sourcepath'},
374                                    $newfile{'UnixRights'});
375                            }
376                        }
377
378                        if ( $select_files )
379                        {
380                            if ( ! installer::existence::exists_in_array($zipname,$selectlistfiles) )
381                            {
382                                $installer::logger::Lang->printf("Removing from ARCHIVE file %s: %s\n",
383                                    $onefilename,
384                                    $zipname);
385                                next; # ignoring files, that are not included in $selectlistfiles
386                            }
387                            else
388                            {
389                                $installer::logger::Lang->printf("Keeping from ARCHIVE file %s: \n",
390                                    $onefilename,
391                                    $zipname);
392                                push( @keptfiles, $zipname); # collecting all kept files
393                            }
394                        }
395
396                        if ( $select_patch_files )
397                        {
398                            # Is this file listed in the Patchfile list?
399                            # $zipname (filename including path in zip file has to be listed in patchfile list
400
401                            if ( ! installer::existence::exists_in_array($zipname,$patchlistfiles) )
402                            {
403                                $newfile{'Styles'} =~ s/\bPATCH\b//;    # removing the flag PATCH
404                                $newfile{'Styles'} =~ s/\,\s*\,/\,/;
405                                $newfile{'Styles'} =~ s/\(\s*\,/\(/;
406                                $newfile{'Styles'} =~ s/\,\s*\)/\)/;
407                            }
408                            else
409                            {
410                                push( @keptpatchflags, $zipname); # collecting all PATCH flags
411                            }
412                        }
413
414                        if ( $rename_to_language )
415                        {
416                            my $newzipname = put_language_into_name($zipname, $onelanguage);
417                            my $oldfilename = $unzipdir . $zipname;
418                            my $newfilename = $unzipdir . $newzipname;
419
420                            installer::systemactions::copy_one_file($oldfilename, $newfilename);
421
422                            $newfile{'Name'} = $newzipname;
423                            $newfile{'destination'} = $destination . $newzipname;
424                            $newfile{'sourcepath'} = $unzipdir . $newzipname;
425
426                            $installer::logger::Lang->printf("RENAME_TO_LANGUAGE: Using %s instead of %s!\n",
427                                $newzipname,
428                                $zipname);
429                        }
430
431                        my $sourcefiletest = $unzipdir . $zipname;
432                        if ( ! -f $sourcefiletest )
433                        {
434                            $installer::logger::Lang->printf("ATTENTION: Unzip failed for %s!\n", $sourcefiletest);
435                            $unziperror = 1;
436                        }
437
438                        # only adding the new line into the files array, if not in repeat modus
439
440                        if ( ! $repeat_unzip ) { push(@newallfilesarray, \%newfile); }
441                    }
442                }
443
444                # Comparing the content of @keptfiles and $selectlistfiles
445                # Do all files from the list of selected files are stored in @keptfiles ?
446                # @keptfiles contains only files included in $selectlistfiles. But are all
447                # files from $selectlistfiles included in @keptfiles?
448
449                if ( $select_files )
450                {
451                    $installer::logger::Lang->printf("SELECTLIST: Number of files in file selection list: %d\n",
452                        scalar @$selectlistfiles);
453                    $installer::logger::Lang->printf("SELECTLIST: Number of kept files: %d\n",
454                        scalar @keptfiles);
455
456                    foreach my $name (@keptfiles)
457                    {
458                        $installer::logger::Lang->printf("KEPT FILES: %s\n", $name);
459                    }
460
461                    foreach my $name (@$selectlistfiles)
462                    {
463                        if ( ! installer::existence::exists_in_array($name,\@keptfiles) )
464                        {
465                            $installer::logger::Lang->printf(
466                                "WARNING: %s not included in install set (does not exist in zip file)!\n",
467                                $name);;
468                        }
469                    }
470                }
471
472                # Comparing the content of @keptpatchflags and $patchlistfiles
473                # Do all files from the patch list have a PATCH flag ?
474                # @keptpatchflags contains only files included in $patchlistfiles. But are all
475                # files from $patchlistfiles included in @keptpatchflags?
476
477                if ( $select_patch_files )
478                {
479                    $installer::logger::Lang->printf("PATCHLIST: Number of files in patch list: %d\n",
480                        scalar @$patchlistfiles);
481                    $installer::logger::Lang->printf("PATCHLIST: Number of kept PATCH flags: %d\n",
482                        scalar @keptpatchflags);
483
484                    foreach my $flag (@keptpatchflags)
485                    {
486                        $installer::logger::Lang->printf("KEPT PATCH FLAGS: %s\n",
487                            $flag);
488                    }
489
490                    foreach my $name (@$patchlistfiles)
491                    {
492                        if ( ! installer::existence::exists_in_array($name,\@keptpatchflags) )
493                        {
494                            $installer::logger::Lang->printf(
495                                "WARNING: %s did not keep PATCH flag (does not exist in zip file)!\n",
496                                $name);
497                        }
498                    }
499                }
500
501                if ( $unziperror )
502                {
503                    installer::logger::print_warning( "Repeating to unpack $sourcepath! \n" );
504                    $installer::logger::Lang->printf("ATTENTION: Repeating to unpack %s!\n", $sourcepath);
505                    $repeat_unzip = 1;
506                    $maxcounter++;
507
508                    if ( $maxcounter == 5 ) # exiting the program
509                    {
510                        installer::exiter::exit_program("ERROR: Failed to unzip $sourcepath !", "resolving_archive_flag");
511                    }
512                }
513                else
514                {
515                    $installer::logger::Lang->printf("Info: %s unpacked without problems !\n", $sourcepath);
516                    $repeat_unzip = 0;
517                    $maxcounter = 0;
518                }
519            }
520        }
521        else        # nothing to do here, no zipped file (no ARCHIVE flag)
522        {
523            push(@newallfilesarray, $onefile);
524        }
525    }
526
527    $installer::logger::Lang->print("\n");
528
529    return \@newallfilesarray;
530}
531
532
5331;
534