1 /* 2 * Copyright (c) 2007, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org> 7 */ 8 9 10 #include "PackageInfo.h" 11 12 #include <Alert.h> 13 #include <ByteOrder.h> 14 #include <FindDirectory.h> 15 #include <Path.h> 16 #include <kernel/OS.h> 17 18 19 // Macro reserved for later localization 20 #define T(x) x 21 22 const uint32 kSkipOffset = 33; 23 24 // Section constants 25 enum { 26 P_GROUPS_SECTION = 0, 27 P_PATH_SECTION, 28 P_USER_PATH_SECTION, 29 P_LICENSE_SECTION 30 }; 31 32 33 // Element constants 34 enum { 35 P_NONE = 0, 36 P_FILE, 37 P_DIRECTORY, 38 P_LINK 39 }; 40 41 42 PackageInfo::PackageInfo() 43 : 44 fStatus(B_NO_INIT), 45 fPackageFile(0), 46 fDescription(T("No package available.")), 47 fProfiles(2), 48 fHasImage(false) 49 { 50 } 51 52 53 PackageInfo::PackageInfo(const entry_ref *ref) 54 : 55 fStatus(B_NO_INIT), 56 fPackageFile(new BFile(ref, B_READ_ONLY)), 57 fDescription(T("No package selected.")), 58 fProfiles(2), 59 fHasImage(false) 60 { 61 fStatus = Parse(); 62 } 63 64 65 PackageInfo::~PackageInfo() 66 { 67 pkg_profile *iter = 0; 68 while (1) { 69 iter = static_cast<pkg_profile *>(fProfiles.RemoveItem((long int)0)); 70 if (iter) 71 delete iter; 72 else 73 break; 74 } 75 76 PkgItem *file = 0; 77 while (1) { 78 file = static_cast<PkgItem *>(fFiles.RemoveItem((long int)0)); 79 if (file) 80 delete file; 81 else 82 break; 83 } 84 85 if (fPackageFile) 86 delete fPackageFile; 87 } 88 89 90 status_t 91 PackageInfo::Parse() 92 { 93 // TODO: Clean up 94 if (!fPackageFile || fPackageFile->InitCheck() != B_OK) { 95 fStatus = B_ERROR; 96 return fStatus; 97 } 98 99 // Check for the presence of the first AlB tag - as the 'magic number'. 100 // This also ensures that the file header section is present - which 101 // is a crucial pkg section 102 char buffer[16]; 103 fPackageFile->Read(buffer, 8); 104 if (buffer[0] != 'A' || buffer[1] != 'l' || buffer[2] != 'B' 105 || buffer[3] != 0x1a) { 106 fStatus = B_ERROR; 107 return fStatus; 108 } 109 110 fHasImage = false; 111 112 // Parse all known parts of the given .pkg file 113 114 uint32 i; 115 int8 bytesRead; 116 off_t actualSize = 0; 117 fPackageFile->GetSize(&actualSize); 118 uint64 fileSize = 0; 119 120 const char padding[7] = { 0, 0, 0, 0, 0, 0, 0 }; 121 122 system_info sysinfo; 123 get_system_info(&sysinfo); 124 125 uint64 infoOffset = 0, groupsOffset = 0; 126 uint64 length = 0; 127 128 // Parse the file header 129 while (1) { 130 bytesRead = fPackageFile->Read(buffer, 7); 131 if (bytesRead != 7) { 132 fStatus = B_ERROR; 133 return fStatus; 134 } 135 136 if (!memcmp(buffer, "PhIn", 5)) { 137 } 138 else if (!memcmp(buffer, "FVer", 5)) { 139 // Not used right now 140 fPackageFile->Seek(4, SEEK_CUR); 141 parser_debug("FVer\n"); 142 } 143 else if (!memcmp(buffer, "AFla", 5)) { 144 // Not used right now TODO: Check what this tag is for 145 fPackageFile->Seek(8, SEEK_CUR); 146 parser_debug("AFla\n"); 147 } 148 else if (!memcmp(buffer, "FSiz", 5)) { 149 fPackageFile->Read(&fileSize, 8); 150 swap_data(B_UINT64_TYPE, &fileSize, sizeof(uint64), 151 B_SWAP_BENDIAN_TO_HOST); 152 parser_debug("FSiz %llu\n", fileSize); 153 } 154 else if (!memcmp(buffer, "COff", 5)) { 155 fPackageFile->Read(&infoOffset, 8); 156 swap_data(B_UINT64_TYPE, &infoOffset, sizeof(uint64), 157 B_SWAP_BENDIAN_TO_HOST); 158 parser_debug("COff %llu\n", infoOffset); 159 } 160 else if (!memcmp(buffer, "AOff", 5)) { 161 fPackageFile->Read(&groupsOffset, 8); 162 swap_data(B_UINT64_TYPE, &groupsOffset, sizeof(uint64), 163 B_SWAP_BENDIAN_TO_HOST); 164 parser_debug("AOff %llu\n", groupsOffset); 165 } 166 else if (!memcmp(buffer, padding, 7)) { 167 // This means the end of this section - we should move to the 168 // groups section. 169 if (groupsOffset) { 170 fPackageFile->Seek(groupsOffset, SEEK_SET); 171 } 172 parser_debug("End!\n"); 173 break; 174 } 175 else { 176 fStatus = B_ERROR; 177 return fStatus; 178 } 179 } 180 181 fPackageFile->Read(buffer, 7); 182 if (memcmp(buffer, "PkgA", 5) || !groupsOffset || !infoOffset) { 183 fStatus = B_ERROR; 184 return fStatus; 185 } 186 187 // Section header identifying constant byte sequences: 188 const char groupsMarker[7] = { 0, 0, 0, 1, 0, 0, 4 }; 189 const char idMarker[7] = { 0, 0, 0, 2, 0, 0, 4 }; 190 const char pathMarker[7] = { 0, 0, 0, 3, 0, 0, 4 }; 191 const char upathMarker[7] = { 0, 0, 0, 4, 0, 0, 4 }; 192 const char licenseMarker[7] = { 0, 0, 0, 18, 0, 0, 4 }; 193 const char descMarker[7] = { 0, 0, 0, 5, 0, 0, 2 }; 194 const char helpMarker[7] = { 0, 0, 0, 10, 0, 0, 3 }; 195 196 const char splashScreenMarker[7] = { 0, 0, 0, 8, 0, 0, 3 }; 197 const char disclaimerMarker[7] = { 0, 0, 0, 7, 0, 0, 3 }; 198 199 const char nameMarker[7] = { 0, 0, 0, 13, 0, 0, 2 }; 200 const char versionMarker[7] = { 0, 0, 0, 14, 0, 0, 2 }; 201 const char devMarker[7] = { 0, 0, 0, 15, 0, 0, 2 }; 202 const char shortDescMarker[7] = { 0, 0, 0, 17, 0, 0, 2 }; 203 204 int8 section = P_GROUPS_SECTION, installDirectoryFlag = 0; 205 206 pkg_profile group; 207 BList groups(3), userPaths(3), systemPaths(10); 208 bool groupStarted = false; 209 parser_debug("Package Info reached!\n"); 210 // TODO: Maybe checking whether the needed number of bytes are read 211 // everytime would be a good idea 212 213 // Parse the package info section 214 while (1) { 215 bytesRead = fPackageFile->Read(buffer, 7); 216 if (bytesRead != 7) { 217 parser_debug("EOF!\n"); 218 break; 219 } 220 221 if (!memcmp(buffer, groupsMarker, 7)) { 222 section = P_GROUPS_SECTION; 223 parser_debug("Got to Groups section\n"); 224 continue; 225 } 226 else if (!memcmp(buffer, pathMarker, 7)) { 227 section = P_PATH_SECTION; 228 parser_debug("Got to System Paths\n"); 229 continue; 230 } 231 else if (!memcmp(buffer, upathMarker, 7)) { 232 section = P_USER_PATH_SECTION; 233 parser_debug("Got to User Paths\n"); 234 continue; 235 } 236 else if (!memcmp(buffer, licenseMarker, 7)) { 237 section = P_LICENSE_SECTION; 238 parser_debug("Got to License\n"); 239 continue; 240 } // After this, non sectioned tags follow 241 else if (!memcmp(buffer, disclaimerMarker, 7)) { 242 uint64 length; 243 fPackageFile->Read(&length, 8); 244 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 245 246 uint64 original; 247 if (fPackageFile->Read(&original, 8) != 8) { 248 fStatus = B_ERROR; 249 return fStatus; 250 } 251 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 252 253 fPackageFile->Seek(4, SEEK_CUR); 254 255 uint8 *compressed = new uint8[length]; 256 if (fPackageFile->Read(compressed, length) != static_cast<int64>(length)) { 257 fStatus = B_ERROR; 258 delete compressed; 259 return fStatus; 260 } 261 262 uint8 *disclaimer = new uint8[original + 1]; 263 status_t ret = inflate_data(compressed, length, disclaimer, original); 264 disclaimer[original] = 0; 265 delete compressed; 266 if (ret != B_OK) { 267 fStatus = B_ERROR; 268 delete disclaimer; 269 return ret; 270 } 271 272 fDisclaimer = (char *)disclaimer; 273 delete disclaimer; 274 275 continue; 276 } 277 else if (!memcmp(buffer, splashScreenMarker, 7)) { 278 uint64 length; 279 fPackageFile->Read(&length, 8); 280 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 281 282 uint64 original; 283 if (fPackageFile->Read(&original, 8) != 8) { 284 fStatus = B_ERROR; 285 return fStatus; 286 } 287 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 288 289 fPackageFile->Seek(4, SEEK_CUR); 290 291 uint8 *compressed = new uint8[length]; 292 if (fPackageFile->Read(compressed, length) != static_cast<int64>(length)) { 293 fStatus = B_ERROR; 294 delete compressed; 295 return fStatus; 296 } 297 298 fImage.SetSize(original); 299 status_t ret = inflate_data(compressed, length, 300 static_cast<uint8 *>(const_cast<void *>(fImage.Buffer())), original); 301 delete compressed; 302 if (ret != B_OK) { 303 fStatus = B_ERROR; 304 return ret; 305 } 306 fHasImage = true; 307 continue; 308 } 309 310 switch (section) { 311 case P_PATH_SECTION: 312 { 313 if (!memcmp(buffer, "DPat", 5)) { 314 parser_debug("DPat\n"); 315 continue; 316 } 317 else if (!memcmp(buffer, "FDst", 5)) { 318 parser_debug("FDst - "); 319 directory_which dir; 320 if (fPackageFile->Read(&dir, 4) != 4) { 321 fStatus = B_ERROR; 322 return fStatus; 323 } 324 swap_data(B_UINT32_TYPE, &dir, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 325 BPath *path = new BPath(); 326 status_t ret = find_directory(dir, path); 327 if (ret != B_OK) { 328 fStatus = B_ERROR; 329 return fStatus; 330 } 331 332 parser_debug("%s\n", path->Path()); 333 334 systemPaths.AddItem(path); 335 } 336 else if (!memcmp(buffer, "PaNa", 5)) { 337 parser_debug("PaNa\n"); 338 if (fPackageFile->Read(&length, 4) != 4) { 339 fStatus = B_ERROR; 340 return fStatus; 341 } 342 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 343 // Since its a default, system path, we can ignore the path name 344 // - all information needed is beside the FDst tag. 345 fPackageFile->Seek(length, SEEK_CUR); 346 } 347 else if (!memcmp(buffer, padding, 7)) { 348 parser_debug("Padding!\n"); 349 continue; 350 } 351 else { 352 fStatus = B_ERROR; 353 return fStatus; 354 } 355 break; 356 } 357 358 case P_GROUPS_SECTION: 359 { 360 if (!memcmp(buffer, "IGrp", 5)) { 361 // Creata a new group 362 groupStarted = true; 363 group = pkg_profile(); 364 parser_debug("IGrp\n"); 365 } 366 else if (!memcmp(buffer, "GrpN", 5)) { 367 if (!groupStarted) { 368 fStatus = B_ERROR; 369 return fStatus; 370 } 371 372 parser_debug("GrpN\n"); 373 fPackageFile->Read(&length, 4); 374 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 375 376 char *name = new char[length + 1]; 377 fPackageFile->Read(name, length); 378 name[length] = 0; 379 group.name = name; 380 delete name; 381 } 382 else if (!memcmp(buffer, "GrpD", 5)) { 383 if (!groupStarted) { 384 fStatus = B_ERROR; 385 return fStatus; 386 } 387 388 parser_debug("GrpD\n"); 389 fPackageFile->Read(&length, 4); 390 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 391 392 char *desc = new char[length + 1]; 393 fPackageFile->Read(desc, length); 394 desc[length] = 0; 395 group.description = desc; 396 delete desc; 397 } 398 else if (!memcmp(buffer, "GrHt", 5)) { 399 if (!groupStarted) { 400 fStatus = B_ERROR; 401 return fStatus; 402 } 403 404 parser_debug("GrHt\n"); 405 // For now, we don't need group help 406 fPackageFile->Read(&length, 4); 407 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 408 fPackageFile->Seek(length, SEEK_CUR); 409 } 410 else if (!memcmp(buffer, padding, 5)) { 411 if (!groupStarted) { 412 parser_debug("No group - padding!\n"); 413 continue; 414 } 415 416 fProfiles.AddItem(new pkg_profile(group)); 417 parser_debug("Group added: %s %s\n", group.name.String(), 418 group.description.String()); 419 420 groupStarted = false; 421 } 422 else if (!memcmp(buffer, "GrId", 5)) { 423 uint32 id; 424 fPackageFile->Read(&id, 4); 425 swap_data(B_UINT32_TYPE, &id, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 426 427 parser_debug("GrId\n"); 428 429 if (id == 0xffffffff) 430 groups.AddItem(NULL); 431 else 432 groups.AddItem(fProfiles.ItemAt(id)); 433 } 434 else if (!memcmp(buffer, idMarker, 7) || 435 !memcmp(buffer, groupsMarker, 7)) { 436 parser_debug("Marker, jumping!\n"); 437 continue; 438 } 439 else { 440 fStatus = B_ERROR; 441 return fStatus; 442 } 443 break; 444 } 445 446 case P_LICENSE_SECTION: 447 { 448 if (!memcmp(buffer, "Lic?", 5)) { 449 parser_debug("Lic?\n"); 450 // This tag informs whether a license is present in the package 451 // or not. Since we don't care about licenses right now, just 452 // skip this section 453 fPackageFile->Seek(4, SEEK_CUR); 454 } 455 else if (!memcmp(buffer, "LicP", 5)) { 456 parser_debug("LicP\n"); 457 fPackageFile->Read(&length, 4); 458 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 459 460 fPackageFile->Seek(length, SEEK_CUR); 461 } 462 else if (!memcmp(buffer, padding, 7)) { 463 continue; 464 } 465 else if (!memcmp(buffer, descMarker, 7)) { 466 parser_debug("Description text reached\n"); 467 fPackageFile->Read(&length, 4); 468 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 469 470 char *description = new char[length + 1]; 471 fPackageFile->Read(description, length); 472 description[length] = 0; 473 fDescription = description; 474 475 // Truncate all leading newlines 476 for (i = 0;i < length;i++) 477 if (fDescription[i] != '\n') 478 break; 479 fDescription.Remove(0, i); 480 481 delete description; 482 parser_debug("Description text reached\n"); 483 484 // After this, there's a known size sequence of bytes, which meaning 485 // is yet to be determined. 486 487 // One is already known. The byte (or just its least significant bit) 488 // at offset 21 from the description text is responsible for the 489 // install folder existence information. If it is 0, there is no 490 // install folder, if it is 1 (or the least significant bit is set) 491 // it means we should install all 0xffffffff files/directories to 492 // the first directory existing in the package 493 fPackageFile->Seek(21, SEEK_CUR); 494 if (fPackageFile->Read(&installDirectoryFlag, 1) != 1) { 495 fStatus = B_ERROR; 496 return fStatus; 497 } 498 499 fPackageFile->Seek(11, SEEK_CUR); 500 } 501 else if (!memcmp(buffer, nameMarker, 7)) { 502 parser_debug("Package name reached\n"); 503 fPackageFile->Read(&length, 4); 504 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 505 506 char *name = new char[length + 1]; 507 fPackageFile->Read(name, length); 508 name[length] = 0; 509 fName = name; 510 delete name; 511 } 512 else if (!memcmp(buffer, versionMarker, 7)) { 513 parser_debug("Package version reached\n"); 514 fPackageFile->Read(&length, 4); 515 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 516 517 char *version = new char[length + 1]; 518 fPackageFile->Read(version, length); 519 version[length] = 0; 520 fVersion = version; 521 delete version; 522 } 523 else if (!memcmp(buffer, devMarker, 7)) { 524 parser_debug("Package developer reached\n"); 525 fPackageFile->Read(&length, 4); 526 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 527 528 char *dev = new char[length + 1]; 529 fPackageFile->Read(dev, length); 530 dev[length] = 0; 531 fDeveloper = dev; 532 delete dev; 533 } 534 else if (!memcmp(buffer, shortDescMarker, 7)) { 535 parser_debug("Package short description reached\n"); 536 fPackageFile->Read(&length, 4); 537 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 538 539 char *desc = new char[length + 1]; 540 fPackageFile->Read(desc, length); 541 desc[length] = 0; 542 fShortDesc = desc; 543 delete desc; 544 } 545 else if (!memcmp(buffer, helpMarker, 7)) { 546 // The help text is a stored in deflated state, preceded by a 64 bit 547 // compressed size, 64 bit inflated size and a 32 bit integer 548 // Since there was no discussion whether we need this help text, 549 // it will be skipped 550 parser_debug("Help text reached\n"); 551 //uint64 length64; 552 fPackageFile->Read(&length, 8); 553 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 554 555 fPackageFile->Seek(12 + length, SEEK_CUR); 556 } 557 break; 558 } 559 560 case P_USER_PATH_SECTION: 561 { 562 if (!memcmp(buffer, "DPat", 5)) { 563 parser_debug("DPat\n"); 564 continue; 565 } 566 else if (!memcmp(buffer, "PaNa", 5)) { 567 parser_debug("PaNa\n"); 568 fPackageFile->Read(&length, 4); 569 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 570 571 char *pathname = new char[length + 1]; 572 fPackageFile->Read(pathname, length); 573 pathname[length] = 0; 574 BString *path = new BString(pathname); 575 if (length > 0 && pathname[length - 1] == '/') 576 path->Remove(length - 1, 1); 577 userPaths.AddItem(path); 578 delete pathname; 579 } 580 else if (!memcmp(buffer, padding, 7)) { 581 parser_debug("Padding!\n"); 582 continue; 583 } 584 else { 585 fStatus = B_ERROR; 586 return fStatus; 587 } 588 break; 589 } 590 } 591 } 592 593 BString nameString, mimeString, signatureString, linkString; 594 BString itemPath = "", installDirectory = ""; 595 uint32 directoryCount = 0; 596 597 uint8 element = P_NONE; 598 uint32 itemGroups = 0, path = 0, cust = 0, ctime = 0, mtime = 0, 599 platform = 0xffffffff; 600 uint64 offset = 0, size = 0, originalSize = 0, mode = 0; 601 uint8 pathType = P_INSTALL_PATH; 602 603 status_t ret; 604 605 fPackageFile->Seek(infoOffset, SEEK_SET); 606 607 // Parse package file data 608 while (1) { 609 bytesRead = fPackageFile->Read(buffer, 7); 610 if (bytesRead != 7) { 611 fStatus = B_ERROR; 612 return fStatus; 613 } 614 615 // TODO: Here's the deal... there seems to be a strange ScrI tag that 616 // seems to mean script files (check this). It seems exaclty the same 617 // as a normal file (just as script files are normal files) so for 618 // now I'm treating those as files. Check if it's correct! 619 // No, it isn't and I will fix this soon. 620 if (!memcmp(buffer, "FilI", 5) || !memcmp(buffer, "ScrI", 5)) { 621 parser_debug("FilI\n"); 622 element = P_FILE; 623 624 mimeString = ""; 625 nameString = ""; 626 signatureString = ""; 627 628 itemGroups = 0; 629 ctime = 0; 630 mtime = 0; 631 offset = 0; 632 itemGroups = 0; 633 cust = 0; 634 mode = 0; 635 platform = 0xffffffff; 636 637 size = 0; 638 originalSize = 0; 639 } 640 else if (!memcmp(buffer, "FldI", 5)) { 641 parser_debug("FldI\n"); 642 element = P_DIRECTORY; 643 644 nameString = ""; 645 646 itemGroups = 0; 647 ctime = 0; 648 mtime = 0; 649 offset = 0; 650 itemGroups = 0; 651 cust = 0; 652 platform = 0xffffffff; 653 654 size = 0; 655 originalSize = 0; 656 } 657 else if (!memcmp(buffer, "LnkI", 5)) { 658 parser_debug("LnkI\n"); 659 element = P_LINK; 660 661 nameString = ""; 662 linkString = ""; 663 664 itemGroups = 0; 665 ctime = 0; 666 mtime = 0; 667 offset = 0; 668 itemGroups = 0; 669 cust = 0; 670 platform = 0xffffffff; 671 672 size = 0; 673 originalSize = 0; 674 } 675 else if (!memcmp(buffer, "Name", 5)) { 676 if (element == P_NONE) { 677 fStatus = B_ERROR; 678 return fStatus; 679 } 680 681 parser_debug("Name\n"); 682 fPackageFile->Read(&length, 4); 683 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 684 685 char *name = new char[length + 1]; 686 fPackageFile->Read(name, length); 687 name[length] = 0; 688 689 nameString = name; 690 delete name; 691 } 692 else if (!memcmp(buffer, "Grps", 5)) { 693 if (element == P_NONE) { 694 fStatus = B_ERROR; 695 return fStatus; 696 } 697 698 parser_debug("Grps\n"); 699 fPackageFile->Read(&itemGroups, 4); 700 swap_data(B_UINT32_TYPE, &itemGroups, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 701 } 702 else if (!memcmp(buffer, "Dest", 5)) { 703 if (element == P_NONE) { 704 fStatus = B_ERROR; 705 return fStatus; 706 } 707 708 parser_debug("Dest\n"); 709 fPackageFile->Read(&path, 4); 710 swap_data(B_UINT32_TYPE, &path, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 711 } 712 else if (!memcmp(buffer, "Cust", 5)) { 713 if (element == P_NONE) { 714 fStatus = B_ERROR; 715 return fStatus; 716 } 717 718 parser_debug("Cust\n"); 719 fPackageFile->Read(&cust, 4); 720 swap_data(B_UINT32_TYPE, &cust, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 721 } 722 else if (!memcmp(buffer, "Repl", 5)) { 723 if (element == P_NONE) { 724 fStatus = B_ERROR; 725 return fStatus; 726 } 727 728 parser_debug("Repl\n"); 729 fPackageFile->Seek(4, SEEK_CUR); 730 // TODO: Should the replace philosophy depend on this flag? For now 731 // I always leave the decision to the user 732 } 733 else if (!memcmp(buffer, "Plat", 5)) { 734 if (element == P_NONE) { 735 fStatus = B_ERROR; 736 return fStatus; 737 } 738 739 parser_debug("Plat\n"); 740 fPackageFile->Read(&platform, 4); 741 swap_data(B_UINT32_TYPE, &platform, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 742 } 743 else if (!memcmp(buffer, "CTim", 5)) { 744 if (element == P_NONE) { 745 fStatus = B_ERROR; 746 return fStatus; 747 } 748 749 parser_debug("CTim\n"); 750 fPackageFile->Read(&ctime, 4); 751 swap_data(B_UINT32_TYPE, &ctime, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 752 } 753 else if (!memcmp(buffer, "MTim", 5)) { 754 if (element == P_NONE) { 755 fStatus = B_ERROR; 756 return fStatus; 757 } 758 759 parser_debug("MTim\n"); 760 fPackageFile->Read(&mtime, 4); 761 swap_data(B_UINT32_TYPE, &mtime, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 762 } 763 else if (!memcmp(buffer, "OffT", 5)) { 764 if (element == P_NONE) { 765 fStatus = B_ERROR; 766 return fStatus; 767 } 768 769 parser_debug("OffT\n"); 770 fPackageFile->Read(&offset, 8); 771 swap_data(B_UINT64_TYPE, &offset, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 772 } 773 else if (!memcmp(buffer, "Mime", 5)) { 774 if (element != P_FILE) { 775 fStatus = B_ERROR; 776 return fStatus; 777 } 778 779 fPackageFile->Read(&length, 4); 780 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 781 782 char *mime = new char[length + 1]; 783 fPackageFile->Read(mime, length); 784 mime[length] = 0; 785 parser_debug("Mime: %s\n", mime); 786 787 mimeString = mime; 788 delete mime; 789 } 790 else if (!memcmp(buffer, "CmpS", 5)) { 791 if (element == P_NONE) { 792 fStatus = B_ERROR; 793 return fStatus; 794 } 795 796 parser_debug("CmpS\n"); 797 fPackageFile->Read(&size, 8); 798 swap_data(B_UINT64_TYPE, &size, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 799 } 800 else if (!memcmp(buffer, "OrgS", 5)) { 801 if (element != P_FILE && element != P_LINK) { 802 fStatus = B_ERROR; 803 return fStatus; 804 } 805 806 parser_debug("OrgS\n"); 807 fPackageFile->Read(&originalSize, 8); 808 swap_data(B_UINT64_TYPE, &originalSize, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); 809 } 810 else if (!memcmp(buffer, "VrsI", 5)) { 811 if (element != P_FILE) { 812 fStatus = B_ERROR; 813 return fStatus; 814 } 815 816 parser_debug("VrsI\n"); 817 fPackageFile->Seek(24, SEEK_CUR); 818 // TODO 819 // Also, check what those empty 20 bytes mean 820 } 821 else if (!memcmp(buffer, "Mode", 5)) { 822 if (element != P_FILE && element != P_LINK) { 823 fStatus = B_ERROR; 824 return fStatus; 825 } 826 827 parser_debug("Mode\n"); 828 fPackageFile->Read(&mode, 4); 829 swap_data(B_UINT32_TYPE, &mode, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 830 } 831 else if (!memcmp(buffer, "FDat", 5)) { 832 if (element != P_DIRECTORY) { 833 fStatus = B_ERROR; 834 return fStatus; 835 } 836 837 parser_debug("FDat\n"); 838 } 839 else if (!memcmp(buffer, "ASig", 5)) { 840 if (element != P_FILE) { 841 fStatus = B_ERROR; 842 return fStatus; 843 } 844 845 fPackageFile->Read(&length, 4); 846 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 847 848 char *signature = new char[length + 1]; 849 fPackageFile->Read(signature, length); 850 signature[length] = 0; 851 parser_debug("Signature: %s\n", signature); 852 853 signatureString = signature; 854 delete signature; 855 } 856 else if (!memcmp(buffer, "Link", 5)) { 857 if (element != P_LINK) { 858 fStatus = B_ERROR; 859 return fStatus; 860 } 861 862 fPackageFile->Read(&length, 4); 863 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST); 864 865 char *link = new char[length + 1]; 866 fPackageFile->Read(link, length); 867 link[length] = 0; 868 parser_debug("Link: %s\n", link); 869 870 linkString = link; 871 delete link; 872 } 873 else if (!memcmp(buffer, padding, 7)) { 874 PkgItem *item = 0; 875 876 parser_debug("Padding!\n"); 877 if (platform != 0xffffffff && 878 static_cast<platform_types>(platform) != sysinfo.platform_type) { 879 // If the file/directory/item's platform is different than the 880 // target platform (or different than the 'any' constant), ignore 881 // this file 882 } 883 else if (element == P_FILE) { 884 if (itemGroups && offset && size) { 885 BString dest = ""; 886 uint8 localType = pathType; 887 888 if (path == 0xfffffffe) 889 dest << itemPath << "/" << nameString.String(); 890 else if (path == 0xffffffff) { 891 localType = P_INSTALL_PATH; 892 dest = installDirectory; 893 dest << nameString; 894 } 895 else { 896 if (cust) { 897 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 898 if (!def) { 899 fStatus = B_ERROR; 900 return fStatus; 901 } 902 if ((*def)[0] == '/') 903 localType = P_SYSTEM_PATH; 904 else 905 localType = P_USER_PATH; 906 907 dest << *def << "/" << nameString; 908 } 909 else { 910 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 911 if (!def) { 912 fStatus = B_ERROR; 913 return fStatus; 914 } 915 localType = P_SYSTEM_PATH; 916 917 dest << def->Path() << "/" << nameString; 918 } 919 } 920 921 item = new PkgFile(fPackageFile, dest, localType, ctime, mtime, 922 offset, size, originalSize, 0, mimeString, signatureString, mode); 923 parser_debug("Adding file: %s!\n", dest.String()); 924 } 925 } 926 else if (element == P_DIRECTORY) { 927 if (itemGroups) { 928 if (installDirectoryFlag != 0) { 929 if (installDirectoryFlag < 0) { // Normal directory 930 if (path == 0xfffffffe) { // Install to current directory 931 itemPath << "/" << nameString.String(); 932 directoryCount++; 933 } 934 else if (path == 0xffffffff) { // Install to install directory 935 pathType = P_INSTALL_PATH; 936 itemPath = installDirectory; 937 itemPath << nameString; 938 directoryCount = 1; 939 } 940 else { // Install to defined directory 941 if (cust) { 942 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 943 if (!def) { 944 fStatus = B_ERROR; 945 return fStatus; 946 } 947 if ((*def)[0] == '/') 948 pathType = P_SYSTEM_PATH; 949 else 950 pathType = P_USER_PATH; 951 952 itemPath = *def; 953 } 954 else { 955 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 956 if (!def) { 957 fStatus = B_ERROR; 958 return fStatus; 959 } 960 pathType = P_SYSTEM_PATH; 961 962 itemPath = def->Path(); 963 } 964 965 itemPath << "/" << nameString; 966 directoryCount = 1; 967 } 968 } 969 else { // Install directory 970 if (path != 0xffffffff) { 971 fStatus = B_ERROR; 972 return fStatus; 973 } 974 975 installDirectory = nameString; 976 installDirectory << "/"; 977 pathType = P_INSTALL_PATH; 978 itemPath = nameString; 979 980 installDirectoryFlag = -1; 981 } 982 983 parser_debug("Adding the directory %s!\n", itemPath.String()); 984 item = new PkgDirectory(fPackageFile, itemPath, pathType, ctime, 985 mtime, offset, size); 986 } 987 else { 988 installDirectoryFlag = -1; 989 } 990 } 991 } 992 else if (element == P_LINK) { 993 if (itemGroups && linkString.Length()) { 994 BString dest = ""; 995 uint8 localType = pathType; 996 997 if (path == 0xfffffffe) 998 dest << itemPath << "/" << nameString.String(); 999 else if (path == 0xffffffff) { 1000 localType = P_INSTALL_PATH; 1001 dest = installDirectory; 1002 dest << nameString; 1003 } 1004 else { 1005 if (cust) { 1006 BString *def = static_cast<BString *>(userPaths.ItemAt(path)); 1007 if (!def) { 1008 fStatus = B_ERROR; 1009 return fStatus; 1010 } 1011 if ((*def)[0] == '/') 1012 localType = P_SYSTEM_PATH; 1013 else 1014 localType = P_USER_PATH; 1015 1016 dest << *def << "/" << nameString; 1017 } 1018 else { 1019 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 1020 if (!def) { 1021 fStatus = B_ERROR; 1022 return fStatus; 1023 } 1024 localType = P_SYSTEM_PATH; 1025 1026 dest << def->Path() << "/" << nameString; 1027 } 1028 } 1029 1030 parser_debug("Adding link: %s! (type %s)\n", dest.String(), 1031 pathType == P_SYSTEM_PATH ? "System" 1032 : (localType == P_INSTALL_PATH ? "Install" : "User")); 1033 item = new PkgLink(fPackageFile, dest, linkString, localType, 1034 ctime, mtime, mode, offset, size); 1035 } 1036 } 1037 else { 1038 // If the directory tree count is equal to zero, this means all 1039 // directory trees have been closed and a padding sequence means the 1040 // end of the section 1041 if (directoryCount == 0) 1042 break; 1043 ret = itemPath.FindLast('/'); 1044 if (ret == B_ERROR) { 1045 itemPath = ""; 1046 } 1047 else { 1048 itemPath.Truncate(ret); 1049 } 1050 directoryCount--; 1051 } 1052 1053 if (item) { 1054 _AddItem(item, originalSize, itemGroups, path, cust); 1055 } 1056 1057 element = P_NONE; 1058 } 1059 else { 1060 fStatus = B_ERROR; 1061 return fStatus; 1062 } 1063 } 1064 1065 if (static_cast<uint64>(actualSize) != fileSize) { 1066 // Inform the user of a possible error 1067 int32 selection; 1068 BAlert *warning = new BAlert(T("filesize_wrong"), 1069 T("There seems to be a filesize mismatch in the package file. " 1070 "The package might be corrupted or have been modified after its " 1071 "creation. Do you still wish to continue?"), T("Yes"), T("No"), NULL, 1072 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 1073 selection = warning->Go(); 1074 1075 if (selection == 1) { 1076 fStatus = B_ERROR; 1077 return fStatus; 1078 } 1079 } 1080 1081 if (!groups.IsEmpty()) 1082 fProfiles = groups; 1083 1084 return B_OK; 1085 } 1086 1087 1088 void 1089 PackageInfo::_AddItem(PkgItem *item, uint64 size, uint32 groups, uint32 path, 1090 uint32 cust) 1091 { 1092 // Add the item to all groups it resides in 1093 uint32 i, n = fProfiles.CountItems(), mask = 1; 1094 pkg_profile *profile; 1095 1096 for (i = 0;i < n;i++) { 1097 if (groups & mask) { 1098 profile = static_cast<pkg_profile *>(fProfiles.ItemAt(i)); 1099 profile->items.AddItem(item); 1100 profile->space_needed += size; 1101 // If there is at least one non-predefined destination element 1102 // in the package, we give the user the ability to select the 1103 // installation directory. 1104 // If there are only predefined path files in the package, but 1105 // such defined by the user, the user will be able to select 1106 // the destination volume 1107 if (path == 0xffffffff) 1108 profile->path_type = P_INSTALL_PATH; 1109 else if (path < 0xfffffffe && 1110 profile->path_type != P_INSTALL_PATH) { 1111 if (cust) { 1112 profile->path_type = P_USER_PATH; 1113 } 1114 } 1115 } 1116 mask = mask << 1; 1117 } 1118 } 1119 1120 1121 // #pragma mark - 1122 1123 1124 pkg_profile::~pkg_profile() 1125 { 1126 PkgItem *iter = 0; 1127 while (1) { 1128 iter = static_cast<PkgItem *>(items.RemoveItem((long int)0)); 1129 if (iter) 1130 delete iter; 1131 else 1132 break; 1133 } 1134 } 1135 1136