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::windows::directory; 25 26use installer::exiter; 27use installer::files; 28use installer::globals; 29use installer::pathanalyzer; 30use installer::windows::idtglobal; 31use installer::windows::msiglobal; 32use installer::scriptitems; 33 34use strict; 35 36############################################################## 37# Collecting all directory trees in global hash 38############################################################## 39 40sub collectdirectorytrees 41{ 42 my ( $directoryref ) = @_; 43 44 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 45 { 46 my $onedir = ${$directoryref}[$i]; 47 my $styles = ""; 48 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; } 49 50 if ( $styles ne "" ) 51 { 52 foreach my $treestyle ( keys %installer::globals::treestyles ) 53 { 54 if ( $styles =~ /\b$treestyle\b/ ) 55 { 56 my $hostname = $onedir->{'HostName'}; 57 # -> hostname is the key, the style the value! 58 $installer::globals::hostnametreestyles{$hostname} = $treestyle; 59 } 60 } 61 } 62 } 63} 64 65############################################################## 66# Overwriting global programfilesfolder, if required 67############################################################## 68 69sub overwrite_programfilesfolder 70{ 71 my ( $allvariables ) = @_; 72 73 if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} ) 74 { 75 $installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'}; 76 } 77} 78 79 80 81 82=head2 make_short_dir_version($longstring) 83 84 Transform the given string into one that is at most 70 characters long. 85 That is done in two steps: 86 - Cut all parts separated by '_' or '-' down to a length of 5. 87 - Cut down the result to a length of 60 and fill it up to length 70 88 with the MD5 checksum. 89 90 This transform always returns the same result for the same string. 91 There is no counter and reference to a global set of names to make the string unique. 92 93=cut 94sub make_short_dir_version ($) 95{ 96 my ($longstring) = @_; 97 98 my $shortstring = ""; 99 my $cutlength = 60; 100 my $length = 5; # So the directory can still be recognized 101 my $longstring_save = $longstring; 102 103 # Splitting the string at each "underline" and allowing only $length characters per directory name. 104 # Checking also uniqueness and length. 105 106 my @outer_parts = split(/_/, $longstring); 107 foreach my $onestring (@outer_parts) 108 { 109 my $partstring = ""; 110 111 if ( $onestring =~ /\-/ ) 112 { 113 my @inner_parts = split(/-/, $onestring); 114 @inner_parts = map {substr($_,0,$length)} @inner_parts; 115 $partstring = join("-", @inner_parts); 116 $partstring =~ s/^\s*\-//; 117 } 118 else 119 { 120 $partstring = substr($onestring, 0, $length); 121 } 122 123 $shortstring .= "_" . $partstring; 124 } 125 126 $shortstring =~ s/^\s*\_//; 127 128 # Setting unique ID to each directory 129 # No counter allowed, process must be absolute reproducable due to patch creation process. 130 131 my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits 132 $shortstring = substr($shortstring, 0, $cutlength) . "_" . $subid; 133 134 return $shortstring; 135} 136 137 138 139 140=head2 get_unique_name ($hostname, $unique_map, $shortdirhash, $shortdirhashreverse) 141 142 Return a long and a short unique name for the given $hostname. 143 Despite the function name and unlike the generation of unique 144 names for files, the returned names are not really unique. Quite 145 the opposite. The returned names are quaranteed to return the 146 same result for the same input. 147 148 The returned short name has at most length 70. 149 150=cut 151sub get_unique_name ($$) 152{ 153 my ($hostname, $hostnamehash) = @_; 154 155 # Make sure that we where not called for this hostname before. Otherwise the other test would be triggered. 156 if (defined $hostnamehash->{$hostname}) 157 { 158 installer::exiter::exit_program( 159 "ERROR: get_unique_name was already called for hostname ".$hostname, 160 "get_unique_name"); 161 } 162 $hostnamehash->{$hostname} = 1; 163 164 my $uniquename = $hostname; 165 166 $uniquename =~ s/^\s*//g; # removing beginning white spaces 167 $uniquename =~ s/\s*$//g; # removing ending white spaces 168 $uniquename =~ s/\s//g; # removing white spaces 169 $uniquename =~ s/\_//g; # removing existing underlines 170 $uniquename =~ s/\.//g; # removing dots in directoryname 171 $uniquename =~ s/OpenOffice/OO/g; 172 173 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline 174 175 $uniquename =~ s/_registry/_rgy/g; 176 $uniquename =~ s/_registration/_rgn/g; 177 $uniquename =~ s/_extension/_ext/g; 178 $uniquename =~ s/_frame/_frm/g; 179 $uniquename =~ s/_table/_tbl/g; 180 $uniquename =~ s/_chart/_crt/g; 181 182 my $short_uniquename = make_short_dir_version($uniquename); 183 184 return ($uniquename, $short_uniquename); 185} 186 187 188 189 190=head2 check_unique_directorynames($directories) 191 192 The one really important check is made in get_unique_name(). It 193 checks that get_unique_name() is not called twice for the same 194 directory host name. The tests in this function contain the 195 legacy tests that basically only check if there where a collision 196 of the partial MD5 sum that is used to make the short unique names 197 unique. 198 199 The maps $unique_map, $shortdirhash, $shortdirhashreverse are used 200 only to check that _different_ input names are mapped to different 201 results. They are not used to influence the result. That assumes 202 that this function is called only once for every directory 203 hostname. 204=cut 205sub check_unique_directorynames ($) 206{ 207 my ($directories) = @_; 208 209 my %completedirhashstep1 = (); 210 my %shortdirhash = (); 211 my %shortdirhashreverse = (); 212 213 # Check unique name of directories. 214 foreach my $directory (@$directories) 215 { 216 my ($long_uniquename, $short_uniquename) = ($directory->{'long_uniquename'}, $directory->{'uniquename'}); 217 218 # The names after this small changes must still be unique! 219 if (exists($completedirhashstep1{$long_uniquename})) 220 { 221 installer::exiter::exit_program( 222 sprintf("ERROR: Unallowed modification of directory name, not unique (step 1): \"%s\".", 223 $short_uniquename), 224 "check_unique_directorynames"); 225 } 226 $completedirhashstep1{$long_uniquename} = 1; 227 228 229 # Checking if the same directory already exists, but has another short version. 230 if (exists($shortdirhash{$long_uniquename}) 231 && ( $shortdirhash{$long_uniquename} ne $short_uniquename )) 232 { 233 installer::exiter::exit_program( 234 sprintf( 235 "ERROR: Unallowed modification of directory name, not unique (step 2A): \"%s\".", 236 $short_uniquename), 237 "check_unique_directorynames"); 238 } 239 $shortdirhash{$long_uniquename} = $short_uniquename; 240 241 # Also checking vice versa 242 # Checking if the same short directory already exists, but has another long version. 243 if (exists($shortdirhashreverse{$short_uniquename}) 244 && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename )) 245 { 246 installer::exiter::exit_program( 247 sprintf( 248 "ERROR: Unallowed modification of directory name, not unique (step 2B): \"%s\".", 249 $short_uniquename), 250 "check_unique_directorynames"); 251 } 252 $shortdirhashreverse{$short_uniquename} = $long_uniquename; 253 } 254 255 # Check unique name of parents 256 foreach my $directory (@$directories) 257 { 258 my ($long_uniquename, $short_uniquename) 259 = ($directory->{'long_uniqueparentname'}, $directory->{'uniqueparentname'}); 260 261 # Again checking if the same directory already exists, but has another short version. 262 if (exists($shortdirhash{$long_uniquename}) 263 && ( $shortdirhash{$long_uniquename} ne $short_uniquename )) 264 { 265 installer::exiter::exit_program( 266 sprintf( 267 "ERROR: Unallowed modification of directory name, not unique (step 3A): \"%s\".", 268 $short_uniquename), 269 "check_unique_directorynames"); 270 } 271 $shortdirhash{$long_uniquename} = $short_uniquename; 272 273 # Also checking vice versa 274 # Checking if the same short directory already exists, but has another long version. 275 if (exists($shortdirhashreverse{$short_uniquename}) 276 && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename )) 277 { 278 installer::exiter::exit_program( 279 sprintf( 280 "ERROR: Unallowed modification of directory name, not unique (step 3B): \"%s\".", 281 $short_uniquename), 282 "check_unique_directorynames"); 283 } 284 $shortdirhashreverse{$short_uniquename} = $long_uniquename; 285 } 286} 287 288 289 290 291sub get_unique_parent_name ($$) 292{ 293 my ($uniqueparentname, $styles) = @_; 294 295 my $keepparent = 1; 296 297 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator 298 { 299 $uniqueparentname = $1; 300 $keepparent = 0; 301 } 302 else 303 { 304 $uniqueparentname = $installer::globals::programfilesfolder; 305 $keepparent = 1; 306 } 307 308 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ ) 309 { 310 $uniqueparentname = $installer::globals::programfilesfolder; 311 $keepparent = 1; 312 } 313 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ ) 314 { 315 $uniqueparentname = $installer::globals::commonfilesfolder; 316 $keepparent = 1; 317 } 318 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ ) 319 { 320 $uniqueparentname = $installer::globals::commonappdatafolder; 321 $keepparent = 1; 322 } 323 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ ) 324 { 325 $uniqueparentname = $installer::globals::localappdatafolder; 326 $keepparent = 1; 327 } 328 329 if ( $styles =~ /\bSHAREPOINTPATH\b/ ) 330 { 331 $uniqueparentname = "SHAREPOINTPATH"; 332 $installer::globals::usesharepointpath = 1; 333 $keepparent = 1; 334 } 335 336 # also setting short directory name for the parent 337 338 my $originaluniqueparentname = $uniqueparentname; 339 340 if ( ! $keepparent ) 341 { 342 $uniqueparentname = make_short_dir_version($uniqueparentname); 343 } 344 345 return ($originaluniqueparentname, $uniqueparentname); 346} 347 348 349 350 351############################################################## 352# Adding unique directory names to the directory collection 353############################################################## 354 355sub create_unique_directorynames ($) 356{ 357 my ($directories) = @_; 358 359 $installer::globals::officeinstalldirectoryset = 0; 360 361 my %hostnamehash = (); 362 my $infoline = ""; 363 my $errorcount = 0; 364 365 foreach my $directory (@$directories) 366 { 367 next if defined $directory->{'uniquename'}; 368 369 my $styles = $directory->{'Styles'} // ""; 370 371 my ($originaluniquename, $uniquename) = get_unique_name( 372 $directory->{'HostName'}, 373 \%hostnamehash); 374 375 my ($originaluniqueparentname, $uniqueparentname) = get_unique_parent_name( 376 $originaluniquename, 377 $styles); 378 379 380 # Hyphen not allowed in database 381 $uniquename =~ s/\-/\_/g; # making "-" to "_" 382 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_" 383 384 # And finally setting the values for the directories 385 $directory->{'uniquename'} = $uniquename; 386 $directory->{'uniqueparentname'} = $uniqueparentname; 387 $directory->{'long_uniquename'} = $originaluniquename; 388 $directory->{'long_uniqueparentname'} = $originaluniqueparentname; 389 } 390 391 # Find the installation directory. 392 foreach my $directory (@$directories) 393 { 394 next unless defined $directory->{'Styles'}; 395 396 # setting the installlocation directory 397 next unless $directory->{'Styles'} =~ /\bISINSTALLLOCATION\b/; 398 399 if ( $installer::globals::installlocationdirectoryset ) 400 { 401 installer::exiter::exit_program( 402 sprintf( 403 "ERROR: Directory with flag ISINSTALLLOCATION alread set: \"%s\".", 404 $installer::globals::installlocationdirectory), 405 "create_unique_directorynames"); 406 } 407 408 $installer::globals::installlocationdirectory = $directory->{'uniquename'}; 409 $installer::globals::installlocationdirectoryset = 1; 410 } 411} 412 413 414 415 416##################################################### 417# Adding ":." to selected default directory names 418##################################################### 419 420sub update_defaultdir ($$) 421{ 422 my ( $onedir, $allvariableshashref ) = @_; 423 424 if ($installer::globals::addchildprojects 425 || $installer::globals::patch 426 || $installer::globals::languagepack 427 || $allvariableshashref->{'CHANGETARGETDIR'}) 428 { 429 my $sourcediraddon = "\:\."; 430 return $onedir->{'defaultdir'} . $sourcediraddon; 431 } 432 else 433 { 434 return $onedir->{'defaultdir'}; 435 } 436} 437 438##################################################### 439# The directory with the style ISINSTALLLOCATION 440# will be replaced by INSTALLLOCATION 441##################################################### 442 443sub set_installlocation_directory 444{ 445 my ( $directoryref, $allvariableshashref ) = @_; 446 447 if ( ! $installer::globals::installlocationdirectoryset ) 448 { 449 installer::exiter::exit_program( 450 "ERROR: Directory with flag ISINSTALLLOCATION not set!", 451 "set_installlocation_directory"); 452 } 453 454 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 455 { 456 my $onedir = ${$directoryref}[$i]; 457 458 if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory ) 459 { 460 $onedir->{'uniquename'} = "INSTALLLOCATION"; 461 $onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref); 462 } 463 464 if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory ) 465 { 466 $onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref); 467 } 468 469 if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory ) 470 { 471 $onedir->{'uniqueparentname'} = "INSTALLLOCATION"; 472 } 473 } 474} 475 476##################################################### 477# Getting the name of the top level directory. This 478# can have only one letter 479##################################################### 480 481sub get_last_directory_name 482{ 483 my ($completepathref) = @_; 484 485 if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ ) 486 { 487 $$completepathref = $1; 488 } 489} 490 491sub setup_global_font_directory_name ($) 492{ 493 my ($directories) = @_; 494 495 foreach my $directory (@$directories) 496 { 497 next unless defined $directory->{'Dir'}; 498 next unless defined $directory->{'defaultdir'}; 499 500 next if $directory->{'Dir'} ne "PREDEFINED_OSSYSTEMFONTDIR"; 501 next if $directory->{'defaultdir'} ne $installer::globals::fontsdirhostname; 502 503 $installer::globals::fontsdirname = $installer::globals::fontsdirhostname; 504 $installer::globals::fontsdirparent = $directory->{'uniqueparentname'}; 505 506 $installer::logger::Info->printf("%s, fdhn %s, dd %s, ipn %s, HN %s\n", 507 "PREDEFINED_OSSYSTEMFONTDIR", 508 $installer::globals::fontsdirhostname, 509 $directory->{'defaultdir'}, 510 $directory->{'uniqueparentname'}, 511 $directory->{'HostName'}); 512 installer::scriptitems::print_script_item($directory); 513 } 514} 515 516##################################################### 517# Creating the defaultdir for the file Director.idt 518##################################################### 519 520sub create_defaultdir_directorynames ($) 521{ 522 my ($directoryref) = @_; 523 524 my @shortnames = (); 525 if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); } 526 527 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 528 { 529 my $onedir = ${$directoryref}[$i]; 530 my $hostname = $onedir->{'HostName'}; 531 532 $hostname =~ s/\Q$installer::globals::separator\E\s*$//; 533 get_last_directory_name(\$hostname); 534 # installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname); # making program/classes to classes 535 my $uniquename = $onedir->{'uniquename'}; 536 my $shortstring; 537 if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) )) 538 { 539 $shortstring = $installer::globals::saved83dirmapping{$uniquename}; 540 } 541 else 542 { 543 $shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames); 544 } 545 546 my $defaultdir; 547 548 if ( $shortstring eq $hostname ) 549 { 550 $defaultdir = $hostname; 551 } 552 else 553 { 554 $defaultdir = $shortstring . "|" . $hostname; 555 } 556 557 $onedir->{'defaultdir'} = $defaultdir; 558 } 559} 560 561############################################### 562# Fill content into the directory table 563############################################### 564 565sub create_directorytable_from_collection ($$) 566{ 567 my ($directorytableref, $directoryref) = @_; 568 569 foreach my $onedir (@$directoryref) 570 { 571 # Remove entries for special directories. 572 if (defined $onedir->{'HostName'} 573 && $onedir->{'HostName'} eq "" 574 && defined $onedir->{'Dir'} 575 && $onedir->{'Dir'} eq "PREDEFINED_PROGDIR") 576 { 577 next; 578 } 579 580 my $oneline = sprintf( 581 "%s\t%s\t%s\n", 582 $onedir->{'uniquename'}, 583 $onedir->{'uniqueparentname'}, 584 $onedir->{'defaultdir'}); 585 586 push @{$directorytableref}, $oneline; 587 } 588} 589 590############################################### 591# Defining the root installation structure 592############################################### 593 594sub process_root_directories ($$) 595{ 596 my ($allvariableshashref, $functor) = @_; 597 598 my $oneline = ""; 599 600 if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} )) 601 { 602 my $productname = $allvariableshashref->{'PRODUCTNAME'}; 603 my $productversion = $allvariableshashref->{'PRODUCTVERSION'}; 604 my $baseproductversion = $productversion; 605 606 if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} )) 607 { 608 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo 609 } 610 611 my $realproductkey = $productname . " " . $productversion; 612 my $productkey = $productname . " " . $baseproductversion; 613 614 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} )) 615 { 616 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 617 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 618 } 619 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} ) 620 { 621 $productkey =~ s/\ /\_/g; 622 $realproductkey =~ s/\ /\_/g; 623 } 624 625 my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir", undef); 626 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline 627 628 &$functor( 629 $installer::globals::officemenufolder, 630 $installer::globals::programmenufolder, 631 $shortproductkey . "|". $realproductkey); 632 } 633 634 &$functor("TARGETDIR", "", "SourceDir"); 635 &$functor($installer::globals::programfilesfolder, "TARGETDIR", "."); 636 &$functor($installer::globals::programmenufolder, "TARGETDIR", "."); 637 &$functor($installer::globals::startupfolder, "TARGETDIR", "."); 638 &$functor($installer::globals::desktopfolder, "TARGETDIR", "."); 639 &$functor($installer::globals::startmenufolder, "TARGETDIR", "."); 640 &$functor($installer::globals::commonfilesfolder, "TARGETDIR", "."); 641 &$functor($installer::globals::commonappdatafolder, "TARGETDIR", "."); 642 &$functor($installer::globals::localappdatafolder, "TARGETDIR", "."); 643 644 if ( $installer::globals::usesharepointpath ) 645 { 646 &$functor("SHAREPOINTPATH", "TARGETDIR", "."); 647 } 648 649 &$functor($installer::globals::systemfolder, "TARGETDIR", "."); 650 651 my $localtemplatefoldername = $installer::globals::templatefoldername; 652 my $directorytableentry = $localtemplatefoldername; 653 my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir"); 654 if ( $shorttemplatefoldername ne $localtemplatefoldername ) 655 { 656 $directorytableentry = $shorttemplatefoldername . "|" . $localtemplatefoldername; 657 } 658 &$functor($installer::globals::templatefolder, "TARGETDIR", $directorytableentry); 659 660 if ( $installer::globals::fontsdirname ) 661 { 662 &$functor( 663 $installer::globals::fontsfolder, 664 $installer::globals::fontsdirparent, 665 $installer::globals::fontsfoldername . ":" . $installer::globals::fontsdirname); 666 } 667 else 668 { 669 &$functor( 670 $installer::globals::fontsfolder, 671 "TARGETDIR", 672 $installer::globals::fontsfoldername); 673 } 674} 675 676 677 678 679sub find_missing_directories ($$) 680{ 681 my ($directories, $allvariableshashref) = @_; 682 683 # Set up the list of target directories. 684 my %target_directories = map {$_->{'uniquename'} => 1} @$directories; 685 # Add special directories. 686 process_root_directories( 687 $allvariableshashref, 688 sub($$$){ 689 my ($uniquename, $parentname, $defaultdir) = @_; 690 $target_directories{$uniquename} = 1; 691 } 692 ); 693 694 # Set up the list of source directories. 695 my $source_directory_map = $installer::globals::source_msi->GetDirectoryMap(); 696 my $source_file_map = $installer::globals::source_msi->GetFileMap(); 697 my %source_directories = map {$_->{'unique_name'} => $_} values %$source_directory_map; 698 699 # Find the missing source directories. 700 my @missing_directories = (); 701 foreach my $source_uniquename (keys %source_directories) 702 { 703 if ( ! $target_directories{$source_uniquename}) 704 { 705 push @missing_directories, $source_directories{$source_uniquename}; 706 } 707 } 708 709 # Report the missing directories. 710 $installer::logger::Info->printf("found %d missing directories\n", scalar @missing_directories); 711 my $index = 0; 712 foreach my $directory_item (@missing_directories) 713 { 714 # Print information about the directory. 715 $installer::logger::Info->printf("missing directory %d: %s\n", 716 ++$index, 717 $directory_item->{'full_target_long_name'}); 718 while (my($key,$value) = each %$directory_item) 719 { 720 $installer::logger::Info->printf(" %s -> %s\n", $key, $value); 721 } 722 723 # Print the referencing files. 724 my @filenames = (); 725 while (my ($key,$value) = each %$source_file_map) 726 { 727 if ($value->{'directory'}->{'unique_name'} eq $directory_item->{'unique_name'}) 728 { 729 push @filenames, $key; 730 } 731 } 732 $installer::logger::Info->printf(" referencing files are %s\n", join(", ", @filenames)); 733 } 734 735 foreach my $directory (@$directories) 736 { 737 $installer::logger::Lang->printf("target directory %s -> HN %s\n", 738 $directory->{'uniquename'}, 739 $directory->{'HostName'}); 740 installer::scriptitems::print_script_item($directory); 741 } 742 743 # Setup a map of directory uniquenames to verify that the new 744 # entries don't use unique names that are already in use. 745 my %unique_names = map {$_->{'uniquename'} => $_} @$directories; 746 747 # Create script items for the missing directories. 748 my @new_source_directories = (); 749 foreach my $source_directory_item (@missing_directories) 750 { 751 my $new_directory_item = { 752 'uniquename' => $source_directory_item->{'unique_name'}, 753 'uniqueparentname' => $source_directory_item->{'parent_name'}, 754 'defaultdir' => $source_directory_item->{'default_dir'}, 755 'HostName' => $source_directory_item->{'full_target_long_name'}, 756 'componentname' => $source_directory_item->{'component_name'}, 757 }; 758 759 if (defined $unique_names{$new_directory_item->{'uniquename'}}) 760 { 761 installer::logger::PrintError("newly created directory entry collides with existing directory"); 762 last; 763 } 764 765 push @new_source_directories, $new_directory_item; 766 } 767 768 return @new_source_directories; 769} 770 771 772 773 774sub prepare_directory_table_creation ($$) 775{ 776 my ($directories, $allvariableshashref) = @_; 777 778 foreach my $directory (@$directories) 779 { 780 delete $directory->{'uniquename'}; 781 } 782 783 overwrite_programfilesfolder($allvariableshashref); 784 create_unique_directorynames($directories); 785 check_unique_directorynames($directories); 786 create_defaultdir_directorynames($directories); # only destdir! 787 setup_global_font_directory_name($directories); 788 set_installlocation_directory($directories, $allvariableshashref); 789 790 if ($installer::globals::is_release) 791 { 792 my @new_directories = find_missing_directories($directories, $allvariableshashref); 793 push @$directories, @new_directories; 794 } 795} 796 797 798 799 800############################################### 801# Creating the file Director.idt dynamically 802############################################### 803 804sub create_directory_table ($$$) 805{ 806 my ($directoryref, $basedir, $allvariableshashref) = @_; 807 808 # Structure of the directory table: 809 # Directory Directory_Parent DefaultDir 810 # Directory is a unique identifier 811 # Directory_Parent is the unique identifier of the parent 812 # DefaultDir is .:APPLIC~1|Application Data with 813 # Before ":" : [sourcedir]:[destdir] (not programmed yet) 814 # After ":" : 8+3 and not 8+3 the destination directory name 815 816 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table start"); 817 818 my @directorytable = (); 819 installer::windows::idtglobal::write_idt_header(\@directorytable, "directory"); 820 821 # Add entries for the root directories (and a few special directories like that for fonts). 822 process_root_directories( 823 $allvariableshashref, 824 sub($$$){ 825 push(@directorytable, join("\t", @_)."\n"); 826 } 827 ); 828 829 # Add entries for the non-root directories. 830 create_directorytable_from_collection(\@directorytable, $directoryref); 831 832 # Saving the file 833 834 my $directorytablename = $basedir . $installer::globals::separator . "Director.idt"; 835 installer::files::save_file($directorytablename ,\@directorytable); 836 $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename); 837 838 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table end"); 839} 840 841 8421; 843