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