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