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