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