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