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