1 /* 2 * Copyright 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 "PackageItem.h" 11 12 #include <string.h> 13 14 #include <Alert.h> 15 #include <ByteOrder.h> 16 #include <Catalog.h> 17 #include <Directory.h> 18 #include <FindDirectory.h> 19 #include <fs_info.h> 20 #include <Locale.h> 21 #include <NodeInfo.h> 22 #include <OS.h> 23 #include <SymLink.h> 24 #include <Volume.h> 25 26 #include "zlib.h" 27 28 29 #undef B_TRANSLATION_CONTEXT 30 #define B_TRANSLATION_CONTEXT "PackageItem" 31 32 enum { 33 P_CHUNK_SIZE = 256 34 }; 35 36 static const uint32 kDefaultMode = 0777; 37 static const uint8 padding[7] = { 0, 0, 0, 0, 0, 0, 0 }; 38 39 extern bool gVerbose; 40 41 enum { 42 P_DATA = 0, 43 P_ATTRIBUTE 44 }; 45 46 extern const char **environ; 47 48 49 status_t 50 inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize) 51 { 52 parser_debug("inflate_data() called - input_size: %ld, output_size: %ld\n", 53 inSize, outSize); 54 z_stream stream; 55 stream.zalloc = Z_NULL; 56 stream.zfree = Z_NULL; 57 stream.opaque = Z_NULL; 58 stream.avail_in = inSize; 59 stream.next_in = in; 60 status_t ret; 61 62 ret = inflateInit(&stream); 63 if (ret != Z_OK) { 64 parser_debug("inflatInit failed\n"); 65 return B_ERROR; 66 } 67 68 stream.avail_out = outSize; 69 stream.next_out = out; 70 71 ret = inflate(&stream, Z_NO_FLUSH); 72 if (ret != Z_STREAM_END) { 73 // Uncompressed file size in package info corrupted 74 parser_debug("Left: %d\n", stream.avail_out); 75 return B_ERROR; 76 } 77 78 inflateEnd(&stream); 79 return B_OK; 80 } 81 82 83 static inline int 84 inflate_file_to_file(BFile *in, uint64 in_size, BFile *out, uint64 out_size) 85 { 86 z_stream stream; 87 stream.zalloc = Z_NULL; 88 stream.zfree = Z_NULL; 89 stream.opaque = Z_NULL; 90 stream.avail_in = 0; 91 stream.next_in = Z_NULL; 92 status_t ret; 93 94 uint8 buffer_out[P_CHUNK_SIZE], buffer_in[P_CHUNK_SIZE]; 95 uint64 bytes_read = 0, read = P_CHUNK_SIZE, write = 0; 96 97 ret = inflateInit(&stream); 98 if (ret != Z_OK) { 99 parser_debug("inflate_file_to_file: inflateInit failed\n"); 100 return B_ERROR; 101 } 102 103 do { 104 bytes_read += P_CHUNK_SIZE; 105 if (bytes_read > in_size) { 106 read = in_size - (bytes_read - P_CHUNK_SIZE); 107 bytes_read = in_size; 108 } 109 110 stream.avail_in = in->Read(buffer_in, read); 111 if (stream.avail_in != read) { 112 parser_debug("inflate_file_to_file: read failed\n"); 113 (void)inflateEnd(&stream); 114 return B_ERROR; 115 } 116 stream.next_in = buffer_in; 117 118 do { 119 stream.avail_out = P_CHUNK_SIZE; 120 stream.next_out = buffer_out; 121 122 ret = inflate(&stream, Z_NO_FLUSH); 123 if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) { 124 parser_debug("inflate_file_to_file: inflate failed\n"); 125 (void)inflateEnd(&stream); 126 return B_ERROR; 127 } 128 129 write = P_CHUNK_SIZE - stream.avail_out; 130 if (static_cast<uint64>(out->Write(buffer_out, write)) != write) { 131 parser_debug("inflate_file_to_file: write failed\n"); 132 (void)inflateEnd(&stream); 133 return B_ERROR; 134 } 135 } while (stream.avail_out == 0); 136 } while (bytes_read != in_size); 137 138 (void)inflateEnd(&stream); 139 140 return B_OK; 141 } 142 143 144 // #pragma mark - PackageItem 145 146 147 PackageItem::PackageItem(BFile* parent, const BString& path, uint8 type, 148 uint32 ctime, uint32 mtime, uint64 offset, uint64 size) 149 { 150 SetTo(parent, path, type, ctime, mtime, offset, size); 151 } 152 153 154 PackageItem::~PackageItem() 155 { 156 } 157 158 159 void 160 PackageItem::SetTo(BFile* parent, const BString& path, uint8 type, uint32 ctime, 161 uint32 mtime, uint64 offset, uint64 size) 162 { 163 fPackage = parent; 164 fPath = path; 165 166 fOffset = offset; 167 fSize = size; 168 fPathType = type; 169 fCreationTime = ctime; 170 fModificationTime = mtime; 171 } 172 173 174 status_t 175 PackageItem::InitPath(const char* path, BPath* destination) 176 { 177 status_t ret = B_OK; 178 179 if (fPathType == P_INSTALL_PATH) { 180 if (gVerbose) 181 printf("InitPath - relative: %s + %s\n", path, fPath.String()); 182 if (path == NULL) { 183 parser_debug("InitPath path is NULL\n"); 184 return B_ERROR; 185 } 186 ret = destination->SetTo(path, fPath.String()); 187 } else if (fPathType == P_SYSTEM_PATH) { 188 if (gVerbose) 189 printf("InitPath - absolute: %s\n", fPath.String()); 190 ret = destination->SetTo(fPath.String()); 191 } else { 192 if (gVerbose) 193 printf("InitPath - volume: %s + %s\n", path, fPath.String()); 194 if (path == NULL) { 195 parser_debug("InitPath path is NULL\n"); 196 return B_ERROR; 197 } 198 199 BVolume volume(dev_for_path(path)); 200 ret = volume.InitCheck(); 201 if (ret == B_OK) { 202 BDirectory temp; 203 ret = volume.GetRootDirectory(&temp); 204 if (ret == B_OK) { 205 BPath mountPoint(&temp, NULL); 206 ret = destination->SetTo(mountPoint.Path(), fPath.String()); 207 } 208 } 209 } 210 211 if (ret != B_OK) { 212 fprintf(stderr, "InitPath(%s): %s\n", path, strerror(ret)); 213 return ret; 214 } 215 216 BString pathString(destination->Path()); 217 218 // Hardcoded paths, the .pkg files hardcode this to the same 219 if (pathString.FindFirst("non-packaged") < 0) { 220 bool wasRewritten = false; 221 222 if (pathString.StartsWith("/boot/beos/system")) { 223 BPath systemNonPackagedDir; 224 find_directory(B_SYSTEM_NONPACKAGED_DIRECTORY, 225 &systemNonPackagedDir); 226 pathString.ReplaceFirst("/boot/beos/system", 227 systemNonPackagedDir.Path()); 228 wasRewritten = true; 229 } else if (pathString.StartsWith("/boot/system")) { 230 BPath systemNonPackagedDir; 231 find_directory(B_SYSTEM_NONPACKAGED_DIRECTORY, 232 &systemNonPackagedDir); 233 pathString.ReplaceFirst("/boot/system", 234 systemNonPackagedDir.Path()); 235 wasRewritten = true; 236 } else if (pathString.StartsWith("/boot/home/config")) { 237 BPath userNonPackagedDir; 238 find_directory(B_USER_NONPACKAGED_DIRECTORY, &userNonPackagedDir); 239 pathString.ReplaceFirst("/boot/home/config", 240 userNonPackagedDir.Path()); 241 wasRewritten = true; 242 } 243 244 if (wasRewritten) { 245 if (gVerbose) 246 printf("rewritten: %s\n", pathString.String()); 247 destination->SetTo(pathString.String()); 248 } 249 } 250 251 return ret; 252 } 253 254 255 status_t 256 PackageItem::HandleAttributes(BPath *destination, BNode *node, 257 const char *header) 258 { 259 status_t ret = B_OK; 260 261 BVolume volume(dev_for_path(destination->Path())); 262 if (volume.KnowsAttr()) { 263 parser_debug("We have an offset\n"); 264 if (!fPackage) 265 return B_ERROR; 266 267 ret = fPackage->InitCheck(); 268 if (ret != B_OK) 269 return ret; 270 271 // We need to parse the data section now 272 fPackage->Seek(fOffset, SEEK_SET); 273 uint8 buffer[7]; 274 if (fPackage->Read(buffer, 7) != 7 || memcmp(buffer, header, 5)) 275 return B_ERROR; 276 parser_debug("Header validated!\n"); 277 278 char *attrName = 0; 279 uint32 nameSize = 0; 280 uint8 *attrData = new uint8[P_CHUNK_SIZE]; 281 uint64 dataSize = P_CHUNK_SIZE; 282 uint8 *temp = new uint8[P_CHUNK_SIZE]; 283 uint64 tempSize = P_CHUNK_SIZE; 284 285 uint64 attrCSize = 0, attrOSize = 0; 286 uint32 attrType = 0; // type_code type 287 bool attrStarted = false, done = false; 288 289 while (fPackage->Read(buffer, 7) == 7) { 290 if (!memcmp(buffer, "FBeA", 5)) 291 continue; 292 293 ret = ParseAttribute(buffer, node, &attrName, &nameSize, &attrType, 294 &attrData, &dataSize, &temp, &tempSize, &attrCSize, &attrOSize, 295 &attrStarted, &done); 296 if (ret != B_OK || done) { 297 if (ret != B_OK) { 298 parser_debug("_ParseAttribute failed for %s\n", 299 destination->Path()); 300 } 301 break; 302 } 303 } 304 305 delete[] attrData; 306 delete[] temp; 307 } 308 309 return ret; 310 } 311 312 313 status_t 314 PackageItem::ParseAttribute(uint8* buffer, BNode* node, char** attrName, 315 uint32* nameSize, uint32* attrType, uint8** attrData, uint64* dataSize, 316 uint8** temp, uint64* tempSize, uint64* attrCSize, uint64* attrOSize, 317 bool* attrStarted, bool* done) 318 { 319 status_t ret = B_OK; 320 uint32 length; 321 322 if (!memcmp(buffer, "BeAI", 5)) { 323 parser_debug(" Attribute started.\n"); 324 if (*attrName) 325 *attrName[0] = 0; 326 *attrCSize = 0; 327 *attrOSize = 0; 328 329 *attrStarted = true; 330 } else if (!memcmp(buffer, "BeAN", 5)) { 331 if (!*attrStarted) { 332 ret = B_ERROR; 333 return ret; 334 } 335 336 parser_debug(" BeAN.\n"); 337 fPackage->Read(&length, 4); 338 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 339 B_SWAP_BENDIAN_TO_HOST); 340 341 if (*nameSize < (length + 1)) { 342 delete[] *attrName; 343 *nameSize = length + 1; 344 *attrName = new char[*nameSize]; 345 } 346 fPackage->Read(*attrName, length); 347 (*attrName)[length] = 0; 348 349 parser_debug(" (%ld) = %s\n", length, *attrName); 350 } else if (!memcmp(buffer, "BeAT", 5)) { 351 if (!*attrStarted) { 352 ret = B_ERROR; 353 return ret; 354 } 355 356 parser_debug(" BeAT.\n"); 357 fPackage->Read(attrType, 4); 358 swap_data(B_UINT32_TYPE, attrType, sizeof(*attrType), 359 B_SWAP_BENDIAN_TO_HOST); 360 } else if (!memcmp(buffer, "BeAD", 5)) { 361 if (!*attrStarted) { 362 ret = B_ERROR; 363 return ret; 364 } 365 366 parser_debug(" BeAD.\n"); 367 fPackage->Read(attrCSize, 8); 368 swap_data(B_UINT64_TYPE, attrCSize, sizeof(*attrCSize), 369 B_SWAP_BENDIAN_TO_HOST); 370 371 fPackage->Read(attrOSize, 8); 372 swap_data(B_UINT64_TYPE, attrOSize, sizeof(*attrOSize), 373 B_SWAP_BENDIAN_TO_HOST); 374 375 fPackage->Seek(4, SEEK_CUR); // TODO: Check what this means 376 377 if (*tempSize < *attrCSize) { 378 delete[] *temp; 379 *tempSize = *attrCSize; 380 *temp = new uint8[*tempSize]; 381 } 382 if (*dataSize < *attrOSize) { 383 delete[] *attrData; 384 *dataSize = *attrOSize; 385 *attrData = new uint8[*dataSize]; 386 } 387 388 if (fPackage->Read(*temp, *attrCSize) 389 != static_cast<ssize_t>(*attrCSize)) { 390 ret = B_ERROR; 391 return ret; 392 } 393 394 parser_debug(" Data read successfuly. Inflating!\n"); 395 ret = inflate_data(*temp, *tempSize, *attrData, *dataSize); 396 if (ret != B_OK) 397 return ret; 398 } else if (!memcmp(buffer, padding, 7)) { 399 if (!*attrStarted) { 400 *done = true; 401 return ret; 402 } 403 404 parser_debug(" Padding.\n"); 405 ssize_t wrote = node->WriteAttr(*attrName, *attrType, 0, *attrData, 406 *attrOSize); 407 if (wrote != static_cast<ssize_t>(*attrOSize)) { 408 parser_debug("Failed to write attribute %s %s\n", *attrName, strerror(wrote)); 409 return B_ERROR; 410 } 411 412 *attrStarted = false; 413 if (*attrName) 414 *attrName[0] = 0; 415 *attrCSize = 0; 416 *attrOSize = 0; 417 418 parser_debug(" > Attribute added.\n"); 419 } else { 420 parser_debug(" Unknown attribute\n"); 421 ret = B_ERROR; 422 } 423 424 return ret; 425 } 426 427 428 status_t 429 PackageItem::SkipAttribute(uint8* buffer, bool* attrStarted, bool* done) 430 { 431 status_t ret = B_OK; 432 uint32 length; 433 434 if (!memcmp(buffer, "BeAI", 5)) { 435 parser_debug(" Attribute started.\n"); 436 *attrStarted = true; 437 } else if (!memcmp(buffer, "BeAN", 5)) { 438 if (!*attrStarted) { 439 ret = B_ERROR; 440 return ret; 441 } 442 443 parser_debug(" BeAN.\n"); 444 fPackage->Read(&length, 4); 445 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 446 B_SWAP_BENDIAN_TO_HOST); 447 448 fPackage->Seek(length, SEEK_CUR); 449 } else if (!memcmp(buffer, "BeAT", 5)) { 450 if (!*attrStarted) { 451 ret = B_ERROR; 452 return ret; 453 } 454 455 parser_debug(" BeAT.\n"); 456 fPackage->Seek(4, SEEK_CUR); 457 } else if (!memcmp(buffer, "BeAD", 5)) { 458 if (!*attrStarted) { 459 ret = B_ERROR; 460 return ret; 461 } 462 463 parser_debug(" BeAD.\n"); 464 uint64 length64; 465 fPackage->Read(&length64, 8); 466 swap_data(B_UINT64_TYPE, &length64, sizeof(length64), 467 B_SWAP_BENDIAN_TO_HOST); 468 469 fPackage->Seek(12 + length64, SEEK_CUR); 470 471 parser_debug(" Data skipped successfuly.\n"); 472 } else if (!memcmp(buffer, padding, 7)) { 473 if (!*attrStarted) { 474 *done = true; 475 return ret; 476 } 477 478 parser_debug(" Padding.\n"); 479 *attrStarted = false; 480 parser_debug(" > Attribute skipped.\n"); 481 } else { 482 parser_debug(" Unknown attribute\n"); 483 ret = B_ERROR; 484 } 485 486 return ret; 487 } 488 489 490 status_t 491 PackageItem::ParseData(uint8* buffer, BFile* file, uint64 originalSize, 492 bool *done) 493 { 494 status_t ret = B_OK; 495 496 if (!memcmp(buffer, "FiMF", 5)) { 497 parser_debug(" Found file data.\n"); 498 uint64 compressed, original; 499 fPackage->Read(&compressed, 8); 500 swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64), 501 B_SWAP_BENDIAN_TO_HOST); 502 503 fPackage->Read(&original, 8); 504 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), 505 B_SWAP_BENDIAN_TO_HOST); 506 parser_debug(" Still good... (%llu : %llu)\n", original, 507 originalSize); 508 509 if (original != originalSize) { 510 parser_debug(" File size mismatch\n"); 511 return B_ERROR; // File size mismatch 512 } 513 parser_debug(" Still good...\n"); 514 515 if (fPackage->Read(buffer, 4) != 4) { 516 parser_debug(" Read(buffer, 4) failed\n"); 517 return B_ERROR; 518 } 519 parser_debug(" Still good...\n"); 520 521 ret = inflate_file_to_file(fPackage, compressed, file, original); 522 if (ret != B_OK) { 523 parser_debug(" inflate_file_to_file failed\n"); 524 return ret; 525 } 526 parser_debug(" File data inflation complete!\n"); 527 } else if (!memcmp(buffer, padding, 7)) { 528 *done = true; 529 return ret; 530 } else { 531 parser_debug("_ParseData unknown tag\n"); 532 ret = B_ERROR; 533 } 534 535 return ret; 536 } 537 538 539 // #pragma mark - PackageScript 540 541 542 PackageScript::PackageScript(BFile* parent, const BString& path, uint8 type, 543 uint64 offset, uint64 size, uint64 originalSize) 544 : 545 PackageItem(parent, path, type, 0, 0, offset, size), 546 fOriginalSize(originalSize), 547 fThreadId(-1) 548 { 549 } 550 551 552 status_t 553 PackageScript::DoInstall(const char* path, ItemState* state) 554 { 555 status_t ret = B_OK; 556 parser_debug("Script: DoInstall() called!\n"); 557 558 if (fOffset) { 559 parser_debug("We have an offset\n"); 560 if (!fPackage) 561 return B_ERROR; 562 563 ret = fPackage->InitCheck(); 564 if (ret != B_OK) 565 return ret; 566 567 // We need to parse the data section now 568 fPackage->Seek(fOffset, SEEK_SET); 569 uint8 buffer[7]; 570 bool attrStarted = false, done = false; 571 572 uint8 section = P_ATTRIBUTE; 573 574 while (fPackage->Read(buffer, 7) == 7) { 575 if (!memcmp(buffer, "FBeA", 5)) { 576 parser_debug("-> Attribute\n"); 577 section = P_ATTRIBUTE; 578 continue; 579 } else if (!memcmp(buffer, "FiDa", 5)) { 580 parser_debug("-> File data\n"); 581 section = P_DATA; 582 continue; 583 } 584 585 switch (section) { 586 case P_ATTRIBUTE: 587 ret = SkipAttribute(buffer, &attrStarted, &done); 588 break; 589 590 case P_DATA: 591 { 592 BString script; 593 ret = _ParseScript(buffer, fOriginalSize, script, &done); 594 if (ret == B_OK) { 595 // Rewrite Deskbar entry targets. NOTE: It would 596 // also work to Replace("/config/be", "/config...") 597 // but it would be less save. For example, an app 598 // could have a folder named "config/be..." inside 599 // its installation folder. 600 // TODO: Use find_paths() or we are no better than 601 // these scripts. 602 script.ReplaceAll( 603 "~/config/be", 604 "~/config/settings/deskbar/menu"); 605 script.ReplaceAll( 606 "/boot/home/config/be", 607 "/boot/home/config/settings/deskbar/menu"); 608 // Rewrite all sorts of other old BeOS paths 609 script.ReplaceAll( 610 "/boot/preferences", 611 "/boot/system/preferences"); 612 script.ReplaceAll( 613 "/boot/apps", 614 "/boot/system/non-packaged/apps"); 615 script.ReplaceAll( 616 "~/config/add-ons/Screen\\ Savers", 617 "~/config/non-packaged/add-ons/Screen\\ Savers"); 618 // TODO: More. These should also be put into a 619 // common source location, since it can also be used 620 // for the retargetting of install file locations. 621 // Packages seem to declare which system paths they 622 // use, and then package items can reference one of 623 // those global paths by index. A more elegent solution 624 // compared to what happens now in InitPath() would be 625 // to replace those global package paths. Or maybe 626 // that's more fragile... but a common source for 627 // the rewriting of BeOS paths is needed. 628 629 if (gVerbose) 630 printf("%s\n", script.String()); 631 632 BPath workingDirectory; 633 if (path != NULL) 634 ret = InitPath(path, &workingDirectory); 635 else 636 ret = workingDirectory.SetTo("."); 637 if (ret == B_OK) 638 ret = _RunScript(workingDirectory.Path(), script); 639 } 640 break; 641 } 642 643 default: 644 return B_ERROR; 645 } 646 647 if (ret != B_OK || done) 648 break; 649 } 650 } 651 652 parser_debug("Ret: %ld %s\n", ret, strerror(ret)); 653 return ret; 654 } 655 656 657 const uint32 658 PackageScript::ItemKind() 659 { 660 return P_KIND_SCRIPT; 661 } 662 663 664 status_t 665 PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, 666 BString& _script, bool *done) 667 { 668 status_t ret = B_OK; 669 670 if (!memcmp(buffer, "FiMF", 5)) { 671 parser_debug(" Found file (script) data.\n"); 672 uint64 compressed, original; 673 fPackage->Read(&compressed, 8); 674 swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64), 675 B_SWAP_BENDIAN_TO_HOST); 676 677 fPackage->Read(&original, 8); 678 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), 679 B_SWAP_BENDIAN_TO_HOST); 680 parser_debug(" Still good... (%llu : %llu)\n", original, 681 originalSize); 682 683 if (original != originalSize) { 684 parser_debug(" File size mismatch\n"); 685 return B_ERROR; // File size mismatch 686 } 687 parser_debug(" Still good...\n"); 688 689 if (fPackage->Read(buffer, 4) != 4) { 690 parser_debug(" Read(buffer, 4) failed\n"); 691 return B_ERROR; 692 } 693 parser_debug(" Still good...\n"); 694 695 uint8 *temp = new uint8[compressed]; 696 if (fPackage->Read(temp, compressed) != (int64)compressed) { 697 parser_debug(" Read(temp, compressed) failed\n"); 698 delete[] temp; 699 return B_ERROR; 700 } 701 702 uint8* script = new uint8[original]; 703 ret = inflate_data(temp, compressed, script, original); 704 if (ret != B_OK) { 705 parser_debug(" inflate_data failed\n"); 706 delete[] temp; 707 delete[] script; 708 return ret; 709 } 710 711 _script.SetTo((char*)script, originalSize); 712 713 delete[] script; 714 delete[] temp; 715 parser_debug(" Script data inflation complete!\n"); 716 } else if (!memcmp(buffer, padding, 7)) { 717 *done = true; 718 return ret; 719 } else { 720 parser_debug("_ParseData unknown tag\n"); 721 ret = B_ERROR; 722 } 723 724 return ret; 725 } 726 727 728 status_t 729 PackageScript::_RunScript(const char* workingDirectory, const BString& script) 730 { 731 // This function written by Peter Folk <pfolk@uni.uiuc.edu> 732 // and published in the BeDevTalk FAQ, modified for use in the 733 // PackageInstaller 734 // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 735 736 // Change current working directory to install path 737 char oldWorkingDirectory[B_PATH_NAME_LENGTH]; 738 getcwd(oldWorkingDirectory, sizeof(oldWorkingDirectory)); 739 chdir(workingDirectory); 740 741 // Save current FDs 742 int old_in = dup(0); 743 int old_out = dup(1); 744 int old_err = dup(2); 745 746 int filedes[2]; 747 748 /* Create new pipe FDs as stdin, stdout, stderr */ 749 pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); 750 int in = filedes[1]; // Write to in, appears on cmd's stdin 751 pipe(filedes); dup2(filedes[1], 1); close(filedes[1]); 752 pipe(filedes); dup2(filedes[1], 2); close(filedes[1]); 753 754 const char **argv = new const char * [3]; 755 argv[0] = strdup("/bin/sh"); 756 argv[1] = strdup("-s"); 757 argv[2] = NULL; 758 759 // "load" command. 760 fThreadId = load_image(2, argv, environ); 761 762 int i; 763 for (i = 0; i < 2; i++) 764 delete argv[i]; 765 delete [] argv; 766 767 if (fThreadId < B_OK) 768 return fThreadId; 769 770 // thread id is now suspended. 771 setpgid(fThreadId, fThreadId); 772 773 // Restore old FDs 774 close(0); dup(old_in); close(old_in); 775 close(1); dup(old_out); close(old_out); 776 close(2); dup(old_err); close(old_err); 777 778 set_thread_priority(fThreadId, B_LOW_PRIORITY); 779 resume_thread(fThreadId); 780 781 // Write the script 782 if (write(in, script.String(), script.Length() - 1) != script.Length() - 1 783 || write(in, "\nexit\n", 6) != 6) { 784 parser_debug("Writing script failed\n"); 785 kill_thread(fThreadId); 786 return B_ERROR; 787 } 788 789 // Restore current working directory 790 chdir(oldWorkingDirectory); 791 792 return B_OK; 793 } 794 795 796 // #pragma mark - PackageDirectory 797 798 799 PackageDirectory::PackageDirectory(BFile* parent, const BString& path, 800 uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size) 801 : 802 PackageItem(parent, path, type, ctime, mtime, offset, size) 803 { 804 } 805 806 807 status_t 808 PackageDirectory::DoInstall(const char* path, ItemState* state) 809 { 810 BPath &destination = state->destination; 811 status_t ret; 812 parser_debug("Directory: %s DoInstall() called!\n", fPath.String()); 813 814 ret = InitPath(path, &destination); 815 parser_debug("Ret: %ld %s\n", ret, strerror(ret)); 816 if (ret != B_OK) 817 return ret; 818 819 // Since Haiku is single-user right now, we give the newly 820 // created directory default permissions 821 ret = create_directory(destination.Path(), kDefaultMode); 822 parser_debug("Create dir ret: %ld %s\n", ret, strerror(ret)); 823 if (ret != B_OK) 824 return ret; 825 BDirectory dir(destination.Path()); 826 parser_debug("Directory created!\n"); 827 828 if (fCreationTime) 829 dir.SetCreationTime(static_cast<time_t>(fCreationTime)); 830 831 if (fModificationTime) 832 dir.SetModificationTime(static_cast<time_t>(fModificationTime)); 833 834 // Since directories can only have attributes in the offset section, 835 // we can check here whether it is necessary to continue 836 if (fOffset) 837 ret = HandleAttributes(&destination, &dir, "FoDa"); 838 839 parser_debug("Ret: %ld %s\n", ret, strerror(ret)); 840 return ret; 841 } 842 843 844 const uint32 845 PackageDirectory::ItemKind() 846 { 847 return P_KIND_DIRECTORY; 848 } 849 850 851 // #pragma mark - PackageFile 852 853 854 PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type, 855 uint32 ctime, uint32 mtime, uint64 offset, uint64 size, 856 uint64 originalSize, uint32 platform, const BString &mime, 857 const BString &signature, uint32 mode) 858 : 859 PackageItem(parent, path, type, ctime, mtime, offset, size), 860 fOriginalSize(originalSize), 861 fPlatform(platform), 862 fMode(mode), 863 fMimeType(mime), 864 fSignature(signature) 865 { 866 } 867 868 869 status_t 870 PackageFile::DoInstall(const char* path, ItemState* state) 871 { 872 if (state == NULL) 873 return B_ERROR; 874 875 BPath& destination = state->destination; 876 status_t ret = B_OK; 877 parser_debug("File: %s DoInstall() called!\n", fPath.String()); 878 879 BFile file; 880 if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) { 881 ret = InitPath(path, &destination); 882 if (ret != B_OK) 883 return ret; 884 885 ret = file.SetTo(destination.Path(), 886 B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS); 887 if (ret == B_ENTRY_NOT_FOUND) { 888 BPath directory; 889 destination.GetParent(&directory); 890 if (create_directory(directory.Path(), kDefaultMode) != B_OK) 891 return B_ERROR; 892 893 ret = file.SetTo(destination.Path(), B_WRITE_ONLY | B_CREATE_FILE); 894 } else if (ret == B_FILE_EXISTS) 895 state->status = B_FILE_EXISTS; 896 897 if (ret != B_OK) 898 return ret; 899 } 900 901 if (state->status == B_FILE_EXISTS) { 902 switch (state->policy) { 903 case P_EXISTS_OVERWRITE: 904 ret = file.SetTo(destination.Path(), 905 B_WRITE_ONLY | B_ERASE_FILE); 906 break; 907 908 case P_EXISTS_NONE: 909 case P_EXISTS_ASK: 910 ret = B_FILE_EXISTS; 911 break; 912 913 case P_EXISTS_SKIP: 914 return B_OK; 915 } 916 } 917 918 if (ret != B_OK) 919 return ret; 920 921 parser_debug(" File created!\n"); 922 923 // Set the file permissions, creation and modification times 924 ret = file.SetPermissions(static_cast<mode_t>(fMode)); 925 if (fCreationTime && ret == B_OK) 926 ret = file.SetCreationTime(static_cast<time_t>(fCreationTime)); 927 if (fModificationTime && ret == B_OK) 928 ret = file.SetModificationTime(static_cast<time_t>(fModificationTime)); 929 930 if (ret != B_OK) 931 return ret; 932 933 // Set the mimetype and application signature if present 934 BNodeInfo info(&file); 935 if (fMimeType.Length() > 0) { 936 ret = info.SetType(fMimeType.String()); 937 if (ret != B_OK) 938 return ret; 939 } 940 if (fSignature.Length() > 0) { 941 ret = info.SetPreferredApp(fSignature.String()); 942 if (ret != B_OK) 943 return ret; 944 } 945 946 if (fOffset) { 947 parser_debug("We have an offset\n"); 948 if (!fPackage) 949 return B_ERROR; 950 951 ret = fPackage->InitCheck(); 952 if (ret != B_OK) 953 return ret; 954 955 // We need to parse the data section now 956 fPackage->Seek(fOffset, SEEK_SET); 957 uint8 buffer[7]; 958 959 char *attrName = 0; 960 uint32 nameSize = 0; 961 uint8 *attrData = new uint8[P_CHUNK_SIZE]; 962 uint64 dataSize = P_CHUNK_SIZE; 963 uint8 *temp = new uint8[P_CHUNK_SIZE]; 964 uint64 tempSize = P_CHUNK_SIZE; 965 966 uint64 attrCSize = 0, attrOSize = 0; 967 uint32 attrType = 0; // type_code type 968 bool attrStarted = false, done = false; 969 970 uint8 section = P_ATTRIBUTE; 971 972 while (fPackage->Read(buffer, 7) == 7) { 973 if (!memcmp(buffer, "FBeA", 5)) { 974 parser_debug("-> Attribute\n"); 975 section = P_ATTRIBUTE; 976 continue; 977 } else if (!memcmp(buffer, "FiDa", 5)) { 978 parser_debug("-> File data\n"); 979 section = P_DATA; 980 continue; 981 } 982 983 switch (section) { 984 case P_ATTRIBUTE: 985 ret = ParseAttribute(buffer, &file, &attrName, &nameSize, 986 &attrType, &attrData, &dataSize, &temp, &tempSize, 987 &attrCSize, &attrOSize, &attrStarted, &done); 988 break; 989 990 case P_DATA: 991 ret = ParseData(buffer, &file, fOriginalSize, &done); 992 break; 993 994 default: 995 return B_ERROR; 996 } 997 998 if (ret != B_OK || done) 999 break; 1000 } 1001 1002 delete[] attrData; 1003 delete[] temp; 1004 } 1005 1006 return ret; 1007 } 1008 1009 1010 const uint32 1011 PackageFile::ItemKind() 1012 { 1013 return P_KIND_FILE; 1014 } 1015 1016 1017 // #pragma mark - 1018 1019 1020 PackageLink::PackageLink(BFile *parent, const BString &path, 1021 const BString &link, uint8 type, uint32 ctime, uint32 mtime, 1022 uint32 mode, uint64 offset, uint64 size) 1023 : 1024 PackageItem(parent, path, type, ctime, mtime, offset, size), 1025 fMode(mode), 1026 fLink(link) 1027 { 1028 } 1029 1030 1031 status_t 1032 PackageLink::DoInstall(const char *path, ItemState *state) 1033 { 1034 if (state == NULL) 1035 return B_ERROR; 1036 1037 status_t ret = B_OK; 1038 BSymLink symlink; 1039 parser_debug("Symlink: %s DoInstall() called!\n", fPath.String()); 1040 1041 BPath &destination = state->destination; 1042 BDirectory *dir = &state->parent; 1043 1044 if (state->status == B_NO_INIT || destination.InitCheck() != B_OK 1045 || dir->InitCheck() != B_OK) { 1046 // Not yet initialized 1047 ret = InitPath(path, &destination); 1048 if (ret != B_OK) 1049 return ret; 1050 1051 BString linkName(destination.Leaf()); 1052 parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(), 1053 linkName.String()); 1054 1055 BPath dirPath; 1056 ret = destination.GetParent(&dirPath); 1057 ret = dir->SetTo(dirPath.Path()); 1058 1059 if (ret == B_ENTRY_NOT_FOUND) { 1060 ret = create_directory(dirPath.Path(), kDefaultMode); 1061 if (ret != B_OK) { 1062 parser_debug("create_directory()) failed\n"); 1063 return B_ERROR; 1064 } 1065 } 1066 if (ret != B_OK) { 1067 parser_debug("destination InitCheck failed %s for %s\n", 1068 strerror(ret), dirPath.Path()); 1069 return ret; 1070 } 1071 1072 ret = dir->CreateSymLink(destination.Path(), fLink.String(), &symlink); 1073 if (ret == B_FILE_EXISTS) { 1074 // We need to check if the existing symlink is pointing at the same path 1075 // as our new one - if not, let's prompt the user 1076 symlink.SetTo(destination.Path()); 1077 BPath oldLink; 1078 1079 ret = symlink.MakeLinkedPath(dir, &oldLink); 1080 chdir(dirPath.Path()); 1081 1082 if (ret == B_BAD_VALUE || oldLink != fLink.String()) 1083 state->status = ret = B_FILE_EXISTS; 1084 else 1085 ret = B_OK; 1086 } 1087 } 1088 1089 if (state->status == B_FILE_EXISTS) { 1090 switch (state->policy) { 1091 case P_EXISTS_OVERWRITE: 1092 { 1093 BEntry entry; 1094 ret = entry.SetTo(destination.Path()); 1095 if (ret != B_OK) 1096 return ret; 1097 1098 entry.Remove(); 1099 ret = dir->CreateSymLink(destination.Path(), fLink.String(), 1100 &symlink); 1101 break; 1102 } 1103 1104 case P_EXISTS_NONE: 1105 case P_EXISTS_ASK: 1106 ret = B_FILE_EXISTS; 1107 break; 1108 1109 case P_EXISTS_SKIP: 1110 return B_OK; 1111 } 1112 } 1113 1114 if (ret != B_OK) { 1115 parser_debug("CreateSymLink failed\n"); 1116 return ret; 1117 } 1118 1119 parser_debug(" Symlink created!\n"); 1120 1121 ret = symlink.SetPermissions(static_cast<mode_t>(fMode)); 1122 1123 if (fCreationTime && ret == B_OK) 1124 ret = symlink.SetCreationTime(static_cast<time_t>(fCreationTime)); 1125 1126 if (fModificationTime && ret == B_OK) { 1127 ret = symlink.SetModificationTime(static_cast<time_t>( 1128 fModificationTime)); 1129 } 1130 1131 if (ret != B_OK) { 1132 parser_debug("Failed to set symlink attributes\n"); 1133 return ret; 1134 } 1135 1136 if (fOffset) { 1137 // Symlinks also seem to have attributes - so parse them 1138 ret = HandleAttributes(&destination, &symlink, "LnDa"); 1139 } 1140 1141 return ret; 1142 } 1143 1144 1145 const uint32 1146 PackageLink::ItemKind() 1147 { 1148 return P_KIND_SYM_LINK; 1149 } 1150 1151