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