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 RETURN_AND_SET_STATUS(B_ERROR); 354 } 355 356 parser_debug("%s\n", path->Path()); 357 358 systemPaths.AddItem(path); 359 } else if (!memcmp(buffer, "PaNa", 5)) { 360 parser_debug("PaNa\n"); 361 if (fPackageFile->Read(&length, 4) != 4) { 362 RETURN_AND_SET_STATUS(B_ERROR); 363 } 364 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 365 B_SWAP_BENDIAN_TO_HOST); 366 // Since its a default, system path, we can ignore the path 367 // name - all information needed is beside the FDst tag. 368 fPackageFile->Seek(length, SEEK_CUR); 369 } else if (!memcmp(buffer, padding, 7)) { 370 parser_debug("Padding!\n"); 371 continue; 372 } else { 373 RETURN_AND_SET_STATUS(B_ERROR); 374 } 375 break; 376 } 377 378 case P_GROUPS_SECTION: 379 { 380 if (!memcmp(buffer, "IGrp", 5)) { 381 // Creata a new group 382 groupStarted = true; 383 group = pkg_profile(); 384 parser_debug("IGrp\n"); 385 } else if (!memcmp(buffer, "GrpN", 5)) { 386 if (!groupStarted) { 387 RETURN_AND_SET_STATUS(B_ERROR); 388 } 389 390 parser_debug("GrpN\n"); 391 fPackageFile->Read(&length, 4); 392 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 393 B_SWAP_BENDIAN_TO_HOST); 394 395 char *name = new char[length + 1]; 396 fPackageFile->Read(name, length); 397 name[length] = 0; 398 group.name = name; 399 delete[] name; 400 } else if (!memcmp(buffer, "GrpD", 5)) { 401 if (!groupStarted) { 402 RETURN_AND_SET_STATUS(B_ERROR); 403 } 404 405 parser_debug("GrpD\n"); 406 fPackageFile->Read(&length, 4); 407 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 408 B_SWAP_BENDIAN_TO_HOST); 409 410 char *desc = new char[length + 1]; 411 fPackageFile->Read(desc, length); 412 desc[length] = 0; 413 group.description = desc; 414 delete[] desc; 415 } else if (!memcmp(buffer, "GrHt", 5)) { 416 if (!groupStarted) { 417 RETURN_AND_SET_STATUS(B_ERROR); 418 } 419 420 parser_debug("GrHt\n"); 421 // For now, we don't need group help 422 fPackageFile->Read(&length, 4); 423 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 424 B_SWAP_BENDIAN_TO_HOST); 425 fPackageFile->Seek(length, SEEK_CUR); 426 } else if (!memcmp(buffer, padding, 5)) { 427 if (!groupStarted) { 428 parser_debug("No group - padding!\n"); 429 continue; 430 } 431 432 fProfiles.AddItem(new pkg_profile(group)); 433 parser_debug("Group added: %s %s\n", group.name.String(), 434 group.description.String()); 435 436 groupStarted = false; 437 } else if (!memcmp(buffer, "GrId", 5)) { 438 uint32 id; 439 fPackageFile->Read(&id, 4); 440 swap_data(B_UINT32_TYPE, &id, sizeof(uint32), 441 B_SWAP_BENDIAN_TO_HOST); 442 443 parser_debug("GrId\n"); 444 445 if (id == 0xffffffff) 446 groups.AddItem(NULL); 447 else 448 groups.AddItem(fProfiles.ItemAt(id)); 449 } else if (!memcmp(buffer, idMarker, 7) 450 || !memcmp(buffer, groupsMarker, 7)) { 451 parser_debug("Marker, jumping!\n"); 452 continue; 453 } else { 454 RETURN_AND_SET_STATUS(B_ERROR); 455 } 456 break; 457 } 458 459 case P_LICENSE_SECTION: 460 { 461 if (!memcmp(buffer, "Lic?", 5)) { 462 parser_debug("Lic?\n"); 463 // This tag informs whether a license is present in the 464 // package or not. Since we don't care about licenses right 465 // now, just skip this section 466 fPackageFile->Seek(4, SEEK_CUR); 467 } else if (!memcmp(buffer, "LicP", 5)) { 468 parser_debug("LicP\n"); 469 fPackageFile->Read(&length, 4); 470 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 471 B_SWAP_BENDIAN_TO_HOST); 472 473 fPackageFile->Seek(length, SEEK_CUR); 474 } else if (!memcmp(buffer, padding, 7)) { 475 continue; 476 } else if (!memcmp(buffer, descMarker, 7)) { 477 parser_debug("Description text reached\n"); 478 fPackageFile->Read(&length, 4); 479 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 480 B_SWAP_BENDIAN_TO_HOST); 481 482 char *description = new char[length + 1]; 483 fPackageFile->Read(description, length); 484 description[length] = 0; 485 fDescription = description; 486 487 // Truncate all leading newlines 488 for (i = 0; i < length; i++) { 489 if (fDescription[i] != '\n') 490 break; 491 } 492 fDescription.Remove(0, i); 493 494 delete[] description; 495 parser_debug("Description text reached\n"); 496 497 // After this, there's a known size sequence of bytes, which 498 // meaning is yet to be determined. 499 500 // One is already known. The byte (or just its least 501 // significant bit) at offset 21 from the description text 502 // is responsible for the install folder existence 503 // information. If it is 0, there is no install folder, if 504 // it is 1 (or the least significant bit is set) it means 505 // we should install all 0xffffffff files/directories to 506 // the first directory existing in the package 507 fPackageFile->Seek(21, SEEK_CUR); 508 if (fPackageFile->Read(&installDirectoryFlag, 1) != 1) { 509 RETURN_AND_SET_STATUS(B_ERROR); 510 } 511 512 fPackageFile->Seek(11, SEEK_CUR); 513 } else if (!memcmp(buffer, nameMarker, 7)) { 514 parser_debug("Package name reached\n"); 515 fPackageFile->Read(&length, 4); 516 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 517 B_SWAP_BENDIAN_TO_HOST); 518 519 char *name = new char[length + 1]; 520 fPackageFile->Read(name, length); 521 name[length] = 0; 522 fName = name; 523 delete[] name; 524 } else if (!memcmp(buffer, versionMarker, 7)) { 525 parser_debug("Package version reached\n"); 526 fPackageFile->Read(&length, 4); 527 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 528 B_SWAP_BENDIAN_TO_HOST); 529 530 char *version = new char[length + 1]; 531 fPackageFile->Read(version, length); 532 version[length] = 0; 533 fVersion = version; 534 delete[] version; 535 } else if (!memcmp(buffer, devMarker, 7)) { 536 parser_debug("Package developer reached\n"); 537 fPackageFile->Read(&length, 4); 538 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 539 B_SWAP_BENDIAN_TO_HOST); 540 541 char *dev = new char[length + 1]; 542 fPackageFile->Read(dev, length); 543 dev[length] = 0; 544 fDeveloper = dev; 545 delete[] dev; 546 } else if (!memcmp(buffer, shortDescMarker, 7)) { 547 parser_debug("Package short description reached\n"); 548 fPackageFile->Read(&length, 4); 549 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 550 B_SWAP_BENDIAN_TO_HOST); 551 552 char *desc = new char[length + 1]; 553 fPackageFile->Read(desc, length); 554 desc[length] = 0; 555 fShortDesc = desc; 556 delete[] desc; 557 } else if (!memcmp(buffer, helpMarker, 7)) { 558 // The help text is a stored in deflated state, preceded by a 64 bit 559 // compressed size, 64 bit inflated size and a 32 bit integer 560 // Since there was no discussion whether we need this help text, 561 // it will be skipped 562 parser_debug("Help text reached\n"); 563 //uint64 length64; 564 fPackageFile->Read(&length, 8); 565 swap_data(B_UINT64_TYPE, &length, sizeof(uint64), 566 B_SWAP_BENDIAN_TO_HOST); 567 568 fPackageFile->Seek(12 + length, SEEK_CUR); 569 } 570 break; 571 } 572 573 case P_USER_PATH_SECTION: 574 { 575 if (!memcmp(buffer, "DPat", 5)) { 576 parser_debug("DPat\n"); 577 continue; 578 } else if (!memcmp(buffer, "DQue", 5)) { 579 parser_debug("DQue\n"); 580 continue; 581 } else if (!memcmp(buffer, "DQTi", 5)) { 582 parser_debug("DQTi\n"); 583 uint32 length; 584 if (fPackageFile->Read(&length, 4) != 4) { 585 RETURN_AND_SET_STATUS(B_ERROR); 586 } 587 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 588 B_SWAP_BENDIAN_TO_HOST); 589 char *ti = new char[length + 1]; 590 fPackageFile->Read(ti, length); 591 ti[length] = 0; 592 parser_debug("DQTi - %s\n", ti); 593 delete[] ti; 594 } else if (!memcmp(buffer, "DQSz", 5)) { 595 parser_debug("DQSz\n"); 596 uint64 size; 597 if (fPackageFile->Read(&size, 8) != 8) { 598 RETURN_AND_SET_STATUS(B_ERROR); 599 } 600 swap_data(B_UINT64_TYPE, &size, sizeof(uint64), 601 B_SWAP_BENDIAN_TO_HOST); 602 parser_debug("DQSz - %Ld\n", size); 603 } else if (!memcmp(buffer, "DQMi", 5)) { 604 // TODO actually check if the query finds a file with 605 // size found previously 606 parser_debug("DQMi\n"); 607 uint32 length; 608 if (fPackageFile->Read(&length, 4) != 4) { 609 RETURN_AND_SET_STATUS(B_ERROR); 610 } 611 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 612 B_SWAP_BENDIAN_TO_HOST); 613 char *signature = new char[length + 1]; 614 fPackageFile->Read(signature, length); 615 signature[length] = 0; 616 parser_debug("DQMi - %s\n", signature); 617 delete[] signature; 618 } else if (!memcmp(buffer, "PaNa", 5)) { 619 parser_debug("PaNa\n"); 620 fPackageFile->Read(&length, 4); 621 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 622 B_SWAP_BENDIAN_TO_HOST); 623 624 char *pathname = new char[length + 1]; 625 fPackageFile->Read(pathname, length); 626 pathname[length] = 0; 627 BString *path = new BString(pathname); 628 if (length > 0 && pathname[length - 1] == '/') 629 path->Remove(length - 1, 1); 630 userPaths.AddItem(path); 631 delete[] pathname; 632 } else if (!memcmp(buffer, padding, 7)) { 633 parser_debug("Padding!\n"); 634 continue; 635 } else { 636 parser_debug("Unknown user path section %s\n", buffer); 637 RETURN_AND_SET_STATUS(B_ERROR); 638 } 639 break; 640 } 641 } 642 } 643 644 BString nameString, mimeString, signatureString, linkString; 645 BString itemPath = "", installDirectory = ""; 646 uint32 directoryCount = 0; 647 648 uint8 element = P_NONE; 649 uint32 itemGroups = 0, path = 0, cust = 0, ctime = 0, mtime = 0; 650 uint32 platform = 0xffffffff; 651 uint64 offset = 0, size = 0, originalSize = 0, mode = 0; 652 uint8 pathType = P_INSTALL_PATH; 653 status_t ret; 654 655 fPackageFile->Seek(infoOffset, SEEK_SET); 656 657 // Parse package file data 658 while (true) { 659 bytesRead = fPackageFile->Read(buffer, 7); 660 if (bytesRead != 7) { 661 RETURN_AND_SET_STATUS(B_ERROR); 662 } 663 664 #define INIT_VARS(tag, type) \ 665 parser_debug(tag "\n"); \ 666 element = type; \ 667 mimeString = ""; \ 668 nameString = ""; \ 669 linkString = ""; \ 670 signatureString = ""; \ 671 itemGroups = 0; \ 672 ctime = 0; \ 673 mtime = 0; \ 674 offset = 0; \ 675 cust = 0; \ 676 mode = 0; \ 677 platform = 0xffffffff; \ 678 size = 0; \ 679 originalSize = 0 680 681 if (!memcmp(buffer, "FilI", 5)) { 682 INIT_VARS("FilI", P_FILE); 683 } else if (!memcmp(buffer, "FldI", 5)) { 684 INIT_VARS("FldI", P_DIRECTORY); 685 } else if (!memcmp(buffer, "LnkI", 5)) { 686 INIT_VARS("LnkI", P_LINK); 687 } else if (!memcmp(buffer, "ScrI", 5)) { 688 INIT_VARS("ScrI", P_SCRIPT); 689 } else if (!memcmp(buffer, "Name", 5)) { 690 if (element == P_NONE) { 691 RETURN_AND_SET_STATUS(B_ERROR); 692 } 693 694 parser_debug("Name\n"); 695 fPackageFile->Read(&length, 4); 696 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 697 B_SWAP_BENDIAN_TO_HOST); 698 699 char *name = new char[length + 1]; 700 fPackageFile->Read(name, length); 701 name[length] = 0; 702 703 nameString = name; 704 delete[] name; 705 } else if (!memcmp(buffer, "Grps", 5)) { 706 if (element == P_NONE) { 707 RETURN_AND_SET_STATUS(B_ERROR); 708 } 709 710 parser_debug("Grps\n"); 711 fPackageFile->Read(&itemGroups, 4); 712 swap_data(B_UINT32_TYPE, &itemGroups, sizeof(uint32), 713 B_SWAP_BENDIAN_TO_HOST); 714 } else if (!memcmp(buffer, "Dest", 5)) { 715 if (element == P_NONE) { 716 RETURN_AND_SET_STATUS(B_ERROR); 717 } 718 719 parser_debug("Dest\n"); 720 fPackageFile->Read(&path, 4); 721 swap_data(B_UINT32_TYPE, &path, sizeof(uint32), 722 B_SWAP_BENDIAN_TO_HOST); 723 } else if (!memcmp(buffer, "Cust", 5)) { 724 if (element == P_NONE) { 725 RETURN_AND_SET_STATUS(B_ERROR); 726 } 727 728 parser_debug("Cust\n"); 729 fPackageFile->Read(&cust, 4); 730 swap_data(B_UINT32_TYPE, &cust, sizeof(uint32), 731 B_SWAP_BENDIAN_TO_HOST); 732 } else if (!memcmp(buffer, "Repl", 5)) { 733 if (element == P_NONE) { 734 RETURN_AND_SET_STATUS(B_ERROR); 735 } 736 737 parser_debug("Repl\n"); 738 fPackageFile->Seek(4, SEEK_CUR); 739 // TODO: Should the replace philosophy depend on this flag? For now 740 // I always leave the decision to the user 741 } else if (!memcmp(buffer, "Plat", 5)) { 742 if (element == P_NONE) { 743 RETURN_AND_SET_STATUS(B_ERROR); 744 } 745 746 parser_debug("Plat\n"); 747 fPackageFile->Read(&platform, 4); 748 swap_data(B_UINT32_TYPE, &platform, sizeof(uint32), 749 B_SWAP_BENDIAN_TO_HOST); 750 } else if (!memcmp(buffer, "CTim", 5)) { 751 if (element == P_NONE) { 752 RETURN_AND_SET_STATUS(B_ERROR); 753 } 754 755 parser_debug("CTim\n"); 756 fPackageFile->Read(&ctime, 4); 757 swap_data(B_UINT32_TYPE, &ctime, sizeof(uint32), 758 B_SWAP_BENDIAN_TO_HOST); 759 } else if (!memcmp(buffer, "MTim", 5)) { 760 if (element == P_NONE) { 761 RETURN_AND_SET_STATUS(B_ERROR); 762 } 763 764 parser_debug("MTim\n"); 765 fPackageFile->Read(&mtime, 4); 766 swap_data(B_UINT32_TYPE, &mtime, sizeof(uint32), 767 B_SWAP_BENDIAN_TO_HOST); 768 } else if (!memcmp(buffer, "OffT", 5)) { 769 if (element == P_NONE) { 770 RETURN_AND_SET_STATUS(B_ERROR); 771 } 772 773 parser_debug("OffT\n"); 774 fPackageFile->Read(&offset, 8); 775 swap_data(B_UINT64_TYPE, &offset, sizeof(uint64), 776 B_SWAP_BENDIAN_TO_HOST); 777 } else if (!memcmp(buffer, "Mime", 5)) { 778 if (element != P_FILE) { 779 RETURN_AND_SET_STATUS(B_ERROR); 780 } 781 782 fPackageFile->Read(&length, 4); 783 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 784 B_SWAP_BENDIAN_TO_HOST); 785 786 char *mime = new char[length + 1]; 787 fPackageFile->Read(mime, length); 788 mime[length] = 0; 789 parser_debug("Mime: %s\n", mime); 790 791 mimeString = mime; 792 delete[] mime; 793 } else if (!memcmp(buffer, "CmpS", 5)) { 794 if (element == P_NONE) { 795 RETURN_AND_SET_STATUS(B_ERROR); 796 } 797 798 parser_debug("CmpS\n"); 799 fPackageFile->Read(&size, 8); 800 swap_data(B_UINT64_TYPE, &size, sizeof(uint64), 801 B_SWAP_BENDIAN_TO_HOST); 802 } else if (!memcmp(buffer, "OrgS", 5)) { 803 if (element != P_FILE && element != P_LINK && element != P_SCRIPT) { 804 RETURN_AND_SET_STATUS(B_ERROR); 805 } 806 807 parser_debug("OrgS\n"); 808 fPackageFile->Read(&originalSize, 8); 809 swap_data(B_UINT64_TYPE, &originalSize, sizeof(uint64), 810 B_SWAP_BENDIAN_TO_HOST); 811 } else if (!memcmp(buffer, "VrsI", 5)) { 812 if (element != P_FILE) { 813 RETURN_AND_SET_STATUS(B_ERROR); 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 } else if (!memcmp(buffer, "Mode", 5)) { 821 if (element != P_FILE && element != P_LINK) { 822 RETURN_AND_SET_STATUS(B_ERROR); 823 } 824 825 parser_debug("Mode\n"); 826 fPackageFile->Read(&mode, 4); 827 swap_data(B_UINT32_TYPE, &mode, sizeof(uint32), 828 B_SWAP_BENDIAN_TO_HOST); 829 } else if (!memcmp(buffer, "FDat", 5)) { 830 if (element != P_DIRECTORY) { 831 RETURN_AND_SET_STATUS(B_ERROR); 832 } 833 834 parser_debug("FDat\n"); 835 } else if (!memcmp(buffer, "ASig", 5)) { 836 if (element != P_FILE) { 837 RETURN_AND_SET_STATUS(B_ERROR); 838 } 839 840 fPackageFile->Read(&length, 4); 841 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 842 B_SWAP_BENDIAN_TO_HOST); 843 844 char *signature = new char[length + 1]; 845 fPackageFile->Read(signature, length); 846 signature[length] = 0; 847 parser_debug("Signature: %s\n", signature); 848 849 signatureString = signature; 850 delete[] signature; 851 } else if (!memcmp(buffer, "Link", 5)) { 852 if (element != P_LINK) { 853 RETURN_AND_SET_STATUS(B_ERROR); 854 } 855 856 fPackageFile->Read(&length, 4); 857 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 858 B_SWAP_BENDIAN_TO_HOST); 859 860 char *link = new char[length + 1]; 861 fPackageFile->Read(link, length); 862 link[length] = 0; 863 parser_debug("Link: %s\n", link); 864 865 linkString = link; 866 delete[] link; 867 } else if (!memcmp(buffer, padding, 7)) { 868 PackageItem *item = NULL; 869 870 parser_debug("Padding!\n"); 871 if (platform != 0xffffffff 872 && static_cast<platform_type>(platform) != thisPlatform) { 873 // If the file/directory/item's platform is different than the 874 // target platform (or different than the 'any' constant), 875 // ignore this file 876 } else if (element == P_FILE) { 877 if (itemGroups && offset && size) { 878 BString dest = ""; 879 uint8 localType = pathType; 880 881 if (path == 0xfffffffe) 882 dest << itemPath << "/" << nameString.String(); 883 else if (path == 0xffffffff) { 884 localType = P_INSTALL_PATH; 885 dest = installDirectory; 886 dest << nameString; 887 } else { 888 if (cust) { 889 BString *def = static_cast<BString *>( 890 userPaths.ItemAt(path)); 891 if (!def) { 892 RETURN_AND_SET_STATUS(B_ERROR); 893 } 894 if ((*def)[0] == '/') 895 localType = P_SYSTEM_PATH; 896 else 897 localType = P_USER_PATH; 898 899 dest << *def << "/" << nameString; 900 } else { 901 BPath *def = static_cast<BPath *>( 902 systemPaths.ItemAt(path)); 903 if (!def) { 904 RETURN_AND_SET_STATUS(B_ERROR); 905 } 906 localType = P_SYSTEM_PATH; 907 908 dest << def->Path() << "/" << nameString; 909 } 910 } 911 912 parser_debug("Adding file: %s!\n", dest.String()); 913 914 item = new PackageFile(fPackageFile, dest, localType, ctime, 915 mtime, offset, size, originalSize, 0, mimeString, 916 signatureString, mode); 917 } 918 } else if (element == P_DIRECTORY) { 919 if (itemGroups) { 920 if (installDirectoryFlag != 0) { 921 if (installDirectoryFlag < 0) { 922 // Normal directory 923 if (path == 0xfffffffe) { 924 // Install to current directory 925 itemPath << "/" << nameString.String(); 926 directoryCount++; 927 } else if (path == 0xffffffff) { 928 // Install to install directory 929 pathType = P_INSTALL_PATH; 930 itemPath = installDirectory; 931 itemPath << nameString; 932 directoryCount = 1; 933 } else { 934 // Install to defined directory 935 if (cust) { 936 BString *def = static_cast<BString *>( 937 userPaths.ItemAt(path)); 938 if (!def) { 939 RETURN_AND_SET_STATUS(B_ERROR); 940 } 941 if ((*def)[0] == '/') 942 pathType = P_SYSTEM_PATH; 943 else 944 pathType = P_USER_PATH; 945 946 itemPath = *def; 947 } else { 948 BPath *def = static_cast<BPath *>( 949 systemPaths.ItemAt(path)); 950 if (!def) { 951 RETURN_AND_SET_STATUS(B_ERROR); 952 } 953 pathType = P_SYSTEM_PATH; 954 955 itemPath = def->Path(); 956 } 957 958 itemPath << "/" << nameString; 959 directoryCount = 1; 960 } 961 } else { 962 // Install directory 963 if (path != 0xffffffff) { 964 RETURN_AND_SET_STATUS(B_ERROR); 965 } 966 967 installDirectory = nameString; 968 installDirectory << "/"; 969 pathType = P_INSTALL_PATH; 970 itemPath = nameString; 971 972 installDirectoryFlag = -1; 973 } 974 975 parser_debug("Adding the directory %s!\n", 976 itemPath.String()); 977 978 item = new PackageDirectory(fPackageFile, itemPath, 979 pathType, ctime, mtime, offset, size); 980 } else 981 installDirectoryFlag = -1; 982 } 983 } else if (element == P_LINK) { 984 if (itemGroups && linkString.Length()) { 985 BString dest = ""; 986 uint8 localType = pathType; 987 988 if (path == 0xfffffffe) 989 dest << itemPath << "/" << nameString.String(); 990 else if (path == 0xffffffff) { 991 localType = P_INSTALL_PATH; 992 dest = installDirectory; 993 dest << nameString; 994 } else { 995 if (cust) { 996 BString *def = static_cast<BString *>( 997 userPaths.ItemAt(path)); 998 if (!def) { 999 RETURN_AND_SET_STATUS(B_ERROR); 1000 } 1001 if ((*def)[0] == '/') 1002 localType = P_SYSTEM_PATH; 1003 else 1004 localType = P_USER_PATH; 1005 1006 dest << *def << "/" << nameString; 1007 } else { 1008 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path)); 1009 if (!def) { 1010 RETURN_AND_SET_STATUS(B_ERROR); 1011 } 1012 localType = P_SYSTEM_PATH; 1013 1014 dest << def->Path() << "/" << nameString; 1015 } 1016 } 1017 1018 parser_debug("Adding link: %s! (type %s)\n", dest.String(), 1019 pathType == P_SYSTEM_PATH 1020 ? "System" : localType == P_INSTALL_PATH 1021 ? "Install" : "User"); 1022 1023 item = new PackageLink(fPackageFile, dest, linkString, 1024 localType, ctime, mtime, mode, offset, size); 1025 } 1026 } else if (element == P_SCRIPT) { 1027 parser_debug("Adding the script %s!\n", 1028 nameString.String()); 1029 1030 BString workingDirectory; 1031 uint8 localType = P_SYSTEM_PATH; 1032 if (path == 1) 1033 workingDirectory << itemPath; 1034 else if (path == 0xffffffff) { 1035 workingDirectory << installDirectory; 1036 localType = P_INSTALL_PATH; 1037 } 1038 1039 fScripts.AddItem(new PackageScript(fPackageFile, 1040 workingDirectory, localType, offset, size, originalSize)); 1041 } else { 1042 // If the directory tree count is equal to zero, this means all 1043 // directory trees have been closed and a padding sequence means the 1044 // end of the section 1045 if (directoryCount == 0) 1046 break; 1047 ret = itemPath.FindLast('/'); 1048 if (ret == B_ERROR) { 1049 itemPath = ""; 1050 } 1051 else { 1052 itemPath.Truncate(ret); 1053 } 1054 directoryCount--; 1055 } 1056 1057 if (item) { 1058 _AddItem(item, originalSize, itemGroups, path, cust); 1059 } 1060 1061 element = P_NONE; 1062 } else if (!memcmp(buffer, "PkgA", 5)) { 1063 parser_debug("PkgA\n"); 1064 break; 1065 } else if (!memcmp(buffer, "PtcI", 5)) { 1066 parser_debug("PtcI\n"); 1067 break; 1068 } else { 1069 fprintf(stderr, "Unknown file tag %s\n", buffer); 1070 RETURN_AND_SET_STATUS(B_ERROR); 1071 } 1072 } 1073 1074 if (static_cast<uint64>(actualSize) != fileSize) { 1075 // Inform the user of a possible error 1076 int32 selection; 1077 BAlert *warning = new BAlert("filesize_wrong", 1078 B_TRANSLATE("There seems to be a file size mismatch in the " 1079 "package file. The package might be corrupted or have been " 1080 "modified after its creation. Do you still wish to continue?"), 1081 B_TRANSLATE("Continue"), 1082 B_TRANSLATE("Abort"), NULL, 1083 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 1084 warning->SetShortcut(1, B_ESCAPE); 1085 selection = warning->Go(); 1086 1087 if (selection == 1) { 1088 RETURN_AND_SET_STATUS(B_ERROR); 1089 } 1090 } 1091 1092 if (!groups.IsEmpty()) 1093 fProfiles = groups; 1094 1095 return B_OK; 1096 } 1097 1098 1099 void 1100 PackageInfo::_AddItem(PackageItem *item, uint64 size, uint32 groups, 1101 uint32 path, uint32 cust) 1102 { 1103 // Add the item to all groups it resides in 1104 uint32 i, n = fProfiles.CountItems(), mask = 1; 1105 pkg_profile *profile; 1106 1107 fFiles.AddItem(item); 1108 1109 for (i = 0;i < n;i++) { 1110 if (groups & mask) { 1111 profile = static_cast<pkg_profile *>(fProfiles.ItemAt(i)); 1112 profile->items.AddItem(item); 1113 profile->space_needed += size; 1114 // If there is at least one non-predefined destination element 1115 // in the package, we give the user the ability to select the 1116 // installation directory. 1117 // If there are only predefined path files in the package, but 1118 // such defined by the user, the user will be able to select 1119 // the destination volume 1120 if (path == 0xffffffff) 1121 profile->path_type = P_INSTALL_PATH; 1122 else if (path < 0xfffffffe && 1123 profile->path_type != P_INSTALL_PATH) { 1124 if (cust) { 1125 profile->path_type = P_USER_PATH; 1126 } 1127 } 1128 } 1129 mask = mask << 1; 1130 } 1131 } 1132 1133