1 /* 2 * Copyright (c) 2001-2010, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Erik Jaesler (erik@cgsoftware.com) 7 * Alex Wilson (yourpalal2@gmail.com) 8 */ 9 10 /*! BArchivable mix-in class defines the archiving protocol. 11 Also some global archiving functions. 12 */ 13 14 15 #include <ctype.h> 16 #include <errno.h> 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <string> 20 #include <syslog.h> 21 #include <typeinfo> 22 #include <vector> 23 24 #include <AppFileInfo.h> 25 #include <Archivable.h> 26 #include <Entry.h> 27 #include <List.h> 28 #include <OS.h> 29 #include <Path.h> 30 #include <Roster.h> 31 #include <String.h> 32 33 #include <binary_compatibility/Support.h> 34 35 #include "ArchivingManagers.h" 36 37 38 using std::string; 39 using std::vector; 40 41 using namespace BPrivate::Archiving; 42 43 const char* B_CLASS_FIELD = "class"; 44 const char* B_ADD_ON_FIELD = "add_on"; 45 const int32 FUNC_NAME_LEN = 1024; 46 47 // TODO: consider moving these to a separate module, and making them more 48 // full-featured (e.g., taking NS::ClassName::Function(Param p) instead 49 // of just NS::ClassName) 50 51 52 static status_t 53 demangle_class_name(const char* name, BString& out) 54 { 55 // TODO: add support for template classes 56 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl 57 58 out = ""; 59 60 #if __GNUC__ >= 4 61 if (name[0] == 'N') 62 name++; 63 int nameLen; 64 bool first = true; 65 while ((nameLen = strtoul(name, (char**)&name, 10))) { 66 if (!first) 67 out += "::"; 68 else 69 first = false; 70 out.Append(name, nameLen); 71 name += nameLen; 72 } 73 if (first) 74 return B_BAD_VALUE; 75 76 #else 77 if (name[0] == 'Q') { 78 // The name is in a namespace 79 int namespaceCount = 0; 80 name++; 81 if (name[0] == '_') { 82 // more than 10 namespaces deep 83 if (!isdigit(*++name)) 84 return B_BAD_VALUE; 85 86 namespaceCount = strtoul(name, (char**)&name, 10); 87 if (name[0] != '_') 88 return B_BAD_VALUE; 89 } else 90 namespaceCount = name[0] - '0'; 91 92 name++; 93 94 for (int i = 0; i < namespaceCount - 1; i++) { 95 if (!isdigit(name[0])) 96 return B_BAD_VALUE; 97 98 int nameLength = strtoul(name, (char**)&name, 10); 99 out.Append(name, nameLength); 100 out += "::"; 101 name += nameLength; 102 } 103 } 104 105 int nameLength = strtoul(name, (char**)&name, 10); 106 out.Append(name, nameLength); 107 #endif 108 109 return B_OK; 110 } 111 112 113 static void 114 mangle_class_name(const char* name, BString& out) 115 { 116 // TODO: add support for template classes 117 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl 118 119 // Chop this: 120 // testthree::testfour::Testthree::Testfour 121 // up into little bite-sized pieces 122 int count = 0; 123 string origName(name); 124 vector<string> spacenames; 125 126 string::size_type pos = 0; 127 string::size_type oldpos = 0; 128 while (pos != string::npos) { 129 pos = origName.find_first_of("::", oldpos); 130 spacenames.push_back(string(origName, oldpos, pos - oldpos)); 131 pos = origName.find_first_not_of("::", pos); 132 oldpos = pos; 133 ++count; 134 } 135 136 // Now mangle it into this: 137 // 9testthree8testfour9Testthree8Testfour 138 // (for __GNUC__ > 2) 139 // this isn't always the proper mangled class name, it should 140 // actually have an 'N' prefix and 'E' suffix if the name is 141 // in > 0 namespaces, but these would have to be removed in 142 // build_function_name() (the only place this function is called) 143 // so we don't add them. 144 // or this: 145 // Q49testthree8testfour9Testthree8Testfour 146 // (for __GNUC__ == 2) 147 148 out = ""; 149 #if __GNUC__ == 2 150 if (count > 1) { 151 out += 'Q'; 152 if (count > 10) 153 out += '_'; 154 out << count; 155 if (count > 10) 156 out += '_'; 157 } 158 #endif 159 160 for (unsigned int i = 0; i < spacenames.size(); ++i) { 161 out << (int)spacenames[i].length(); 162 out += spacenames[i].c_str(); 163 } 164 } 165 166 167 static void 168 build_function_name(const BString& className, BString& funcName) 169 { 170 funcName = ""; 171 172 // This is what we're after: 173 // Instantiate__Q28OpenBeOS11BArchivableP8BMessage 174 mangle_class_name(className.String(), funcName); 175 #if __GNUC__ >= 4 176 funcName.Prepend("_ZN"); 177 funcName.Append("11InstantiateE"); 178 #else 179 funcName.Prepend("Instantiate__"); 180 #endif 181 funcName.Append("P8BMessage"); 182 } 183 184 185 static bool 186 add_private_namespace(BString& name) 187 { 188 if (name.Compare("_", 1) != 0) 189 return false; 190 191 name.Prepend("BPrivate::"); 192 return true; 193 } 194 195 196 static instantiation_func 197 find_function_in_image(BString& funcName, image_id id, status_t& err) 198 { 199 instantiation_func instantiationFunc = NULL; 200 err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, 201 (void**)&instantiationFunc); 202 if (err != B_OK) 203 return NULL; 204 205 return instantiationFunc; 206 } 207 208 209 static status_t 210 check_signature(const char* signature, image_info& info) 211 { 212 if (signature == NULL) { 213 // If it wasn't specified, anything "matches" 214 return B_OK; 215 } 216 217 // Get image signature 218 BFile file(info.name, B_READ_ONLY); 219 status_t err = file.InitCheck(); 220 if (err != B_OK) 221 return err; 222 223 char imageSignature[B_MIME_TYPE_LENGTH]; 224 BAppFileInfo appFileInfo(&file); 225 err = appFileInfo.GetSignature(imageSignature); 226 if (err != B_OK) { 227 syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", 228 info.name); 229 return err; 230 } 231 232 if (strcmp(signature, imageSignature)) 233 return B_MISMATCHED_VALUES; 234 235 return B_OK; 236 } 237 238 239 // #pragma mark - 240 241 242 BArchivable::BArchivable() 243 : 244 fArchivingToken(NULL_TOKEN) 245 { 246 } 247 248 249 BArchivable::BArchivable(BMessage* from) 250 : 251 fArchivingToken(NULL_TOKEN) 252 { 253 if (BUnarchiver::IsArchiveManaged(from)) { 254 BUnarchiver::PrepareArchive(from); 255 BUnarchiver(from).RegisterArchivable(this); 256 } 257 } 258 259 260 BArchivable::~BArchivable() 261 { 262 } 263 264 265 status_t 266 BArchivable::Archive(BMessage* into, bool deep) const 267 { 268 if (!into) { 269 // TODO: logging/other error reporting? 270 return B_BAD_VALUE; 271 } 272 273 if (BManagerBase::ArchiveManager(into)) 274 BArchiver(into).RegisterArchivable(this); 275 276 BString name; 277 status_t status = demangle_class_name(typeid(*this).name(), name); 278 if (status != B_OK) 279 return status; 280 281 return into->AddString(B_CLASS_FIELD, name); 282 } 283 284 285 BArchivable* 286 BArchivable::Instantiate(BMessage* from) 287 { 288 debugger("Can't create a plain BArchivable object"); 289 return NULL; 290 } 291 292 293 status_t 294 BArchivable::Perform(perform_code d, void* arg) 295 { 296 switch (d) { 297 case PERFORM_CODE_ALL_UNARCHIVED: 298 { 299 perform_data_all_unarchived* data = 300 (perform_data_all_unarchived*)arg; 301 302 data->return_value = BArchivable::AllUnarchived(data->archive); 303 return B_OK; 304 } 305 306 case PERFORM_CODE_ALL_ARCHIVED: 307 { 308 perform_data_all_archived* data = 309 (perform_data_all_archived*)arg; 310 311 data->return_value = BArchivable::AllArchived(data->archive); 312 return B_OK; 313 } 314 } 315 return B_NAME_NOT_FOUND; 316 } 317 318 319 status_t 320 BArchivable::AllUnarchived(const BMessage* archive) 321 { 322 return B_OK; 323 } 324 325 326 status_t 327 BArchivable::AllArchived(BMessage* archive) const 328 { 329 return B_OK; 330 } 331 332 333 // #pragma mark - 334 335 336 BArchiver::BArchiver(BMessage* archive) 337 : 338 fManager(BManagerBase::ArchiveManager(archive)), 339 fArchive(archive), 340 fFinished(false) 341 { 342 if (!fManager) 343 fManager = new BArchiveManager(this); 344 } 345 346 347 BArchiver::~BArchiver() 348 { 349 if (!fFinished) 350 fManager->ArchiverLeaving(this, B_OK); 351 } 352 353 354 status_t 355 BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep) 356 { 357 int32 token; 358 status_t err = GetTokenForArchivable(archivable, deep, token); 359 360 if (err != B_OK) 361 return err; 362 363 return fArchive->AddInt32(name, token); 364 } 365 366 367 status_t 368 BArchiver::GetTokenForArchivable(BArchivable* archivable, 369 bool deep, int32& _token) 370 { 371 return fManager->ArchiveObject(archivable, deep, _token); 372 } 373 374 375 bool 376 BArchiver::IsArchived(BArchivable* archivable) 377 { 378 return fManager->IsArchived(archivable); 379 } 380 381 382 status_t 383 BArchiver::Finish(status_t err) 384 { 385 if (fFinished) 386 debugger("Finish() called multiple times on same BArchiver."); 387 388 fFinished = true; 389 390 return fManager->ArchiverLeaving(this, err); 391 } 392 393 394 BMessage* 395 BArchiver::ArchiveMessage() const 396 { 397 return fArchive; 398 } 399 400 401 void 402 BArchiver::RegisterArchivable(const BArchivable* archivable) 403 { 404 fManager->RegisterArchivable(archivable); 405 } 406 407 408 // #pragma mark - 409 410 411 BUnarchiver::BUnarchiver(const BMessage* archive) 412 : 413 fManager(BManagerBase::UnarchiveManager(archive)), 414 fArchive(archive), 415 fFinished(false) 416 { 417 } 418 419 420 BUnarchiver::~BUnarchiver() 421 { 422 if (!fFinished && fManager) 423 fManager->UnarchiverLeaving(this, B_OK); 424 } 425 426 427 template<> 428 status_t 429 BUnarchiver::GetObject<BArchivable>(int32 token, 430 ownership_policy owning, BArchivable*& object) 431 { 432 _CallDebuggerIfManagerNull(); 433 return fManager->GetArchivableForToken(token, owning, object); 434 } 435 436 437 template<> 438 status_t 439 BUnarchiver::FindObject<BArchivable>(const char* name, 440 int32 index, ownership_policy owning, BArchivable*& archivable) 441 { 442 archivable = NULL; 443 int32 token; 444 status_t err = fArchive->FindInt32(name, index, &token); 445 if (err != B_OK) 446 return err; 447 448 return GetObject(token, owning, archivable); 449 } 450 451 452 bool 453 BUnarchiver::IsInstantiated(int32 token) 454 { 455 _CallDebuggerIfManagerNull(); 456 return fManager->IsInstantiated(token); 457 } 458 459 460 bool 461 BUnarchiver::IsInstantiated(const char* field, int32 index) 462 { 463 int32 token; 464 if (fArchive->FindInt32(field, index, &token) == B_OK) 465 return IsInstantiated(token); 466 return false; 467 } 468 469 470 status_t 471 BUnarchiver::Finish(status_t err) 472 { 473 if (fFinished) 474 debugger("Finish() called multiple times on same BArchiver."); 475 476 fFinished = true; 477 if (fManager) 478 return fManager->UnarchiverLeaving(this, err); 479 else 480 return B_OK; 481 } 482 483 484 const BMessage* 485 BUnarchiver::ArchiveMessage() const 486 { 487 return fArchive; 488 } 489 490 491 void 492 BUnarchiver::AssumeOwnership(BArchivable* archivable) 493 { 494 _CallDebuggerIfManagerNull(); 495 fManager->AssumeOwnership(archivable); 496 } 497 498 499 void 500 BUnarchiver::RelinquishOwnership(BArchivable* archivable) 501 { 502 _CallDebuggerIfManagerNull(); 503 fManager->RelinquishOwnership(archivable); 504 } 505 506 507 bool 508 BUnarchiver::IsArchiveManaged(const BMessage* archive) 509 { 510 // managed child archives will return here 511 if (BManagerBase::ManagerPointer(archive)) 512 return true; 513 514 if (!archive) 515 return false; 516 517 // managed top level archives return here 518 bool dummy; 519 if (archive->FindBool(kManagedField, &dummy) == B_OK) 520 return true; 521 522 return false; 523 } 524 525 526 template<> 527 status_t 528 BUnarchiver::InstantiateObject<BArchivable>(BMessage* from, 529 BArchivable*& object) 530 { 531 BUnarchiver unarchiver(BUnarchiver::PrepareArchive(from)); 532 object = instantiate_object(from); 533 return unarchiver.Finish(); 534 } 535 536 537 BMessage* 538 BUnarchiver::PrepareArchive(BMessage*& archive) 539 { 540 // this check allows PrepareArchive to be 541 // called on new or old-style archives 542 if (BUnarchiver::IsArchiveManaged(archive)) { 543 BUnarchiveManager* manager = BManagerBase::UnarchiveManager(archive); 544 if (!manager) 545 manager = new BUnarchiveManager(archive); 546 manager->Acquire(); 547 } 548 return archive; 549 } 550 551 552 void 553 BUnarchiver::RegisterArchivable(BArchivable* archivable) 554 { 555 _CallDebuggerIfManagerNull(); 556 fManager->RegisterArchivable(archivable); 557 } 558 559 560 void 561 BUnarchiver::_CallDebuggerIfManagerNull() 562 { 563 if (!fManager) 564 debugger("BUnarchiver used with legacy or unprepared archive."); 565 } 566 567 568 // #pragma mark - 569 570 571 BArchivable* 572 instantiate_object(BMessage* archive, image_id* _id) 573 { 574 status_t statusBuffer; 575 status_t* status = &statusBuffer; 576 if (_id != NULL) 577 status = _id; 578 579 // Check our params 580 if (archive == NULL) { 581 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 582 *status = B_BAD_VALUE; 583 return NULL; 584 } 585 586 // Get class name from archive 587 const char* className = NULL; 588 status_t err = archive->FindString(B_CLASS_FIELD, &className); 589 if (err) { 590 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 591 "defining the class name (%s).", strerror(err)); 592 *status = B_BAD_VALUE; 593 return NULL; 594 } 595 596 // Get sig from archive 597 const char* signature = NULL; 598 bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK; 599 600 instantiation_func instantiationFunc = find_instantiation_func(className, 601 signature); 602 603 // if find_instantiation_func() can't locate Class::Instantiate() 604 // and a signature was specified 605 if (!instantiationFunc && hasSignature) { 606 // use BRoster::FindApp() to locate an app or add-on with the symbol 607 BRoster Roster; 608 entry_ref ref; 609 err = Roster.FindApp(signature, &ref); 610 611 // if an entry_ref is obtained 612 BEntry entry; 613 if (err == B_OK) 614 err = entry.SetTo(&ref); 615 616 BPath path; 617 if (err == B_OK) 618 err = entry.GetPath(&path); 619 620 if (err != B_OK) { 621 syslog(LOG_ERR, "instantiate_object failed: Error finding app " 622 "with signature \"%s\" (%s)", signature, strerror(err)); 623 *status = err; 624 return NULL; 625 } 626 627 // load the app/add-on 628 image_id addOn = load_add_on(path.Path()); 629 if (addOn < B_OK) { 630 syslog(LOG_ERR, "instantiate_object failed: Could not load " 631 "add-on %s: %s.", path.Path(), strerror(addOn)); 632 *status = addOn; 633 return NULL; 634 } 635 636 // Save the image_id 637 if (_id != NULL) 638 *_id = addOn; 639 640 BString name = className; 641 for (int32 pass = 0; pass < 2; pass++) { 642 BString funcName; 643 build_function_name(name, funcName); 644 645 instantiationFunc = find_function_in_image(funcName, addOn, err); 646 if (instantiationFunc != NULL) 647 break; 648 649 // Check if we have a private class, and add the BPrivate namespace 650 // (for backwards compatibility) 651 if (!add_private_namespace(name)) 652 break; 653 } 654 655 if (instantiationFunc == NULL) { 656 syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 657 "Instantiate static function for class %s.", className); 658 *status = B_NAME_NOT_FOUND; 659 return NULL; 660 } 661 } else if (instantiationFunc == NULL) { 662 syslog(LOG_ERR, "instantiate_object failed: No signature specified " 663 "in archive, looking for class \"%s\".", className); 664 *status = B_NAME_NOT_FOUND; 665 return NULL; 666 } 667 668 // if Class::Instantiate(BMessage*) was found 669 if (instantiationFunc != NULL) { 670 // use to create and return an object instance 671 return instantiationFunc(archive); 672 } 673 674 return NULL; 675 } 676 677 678 BArchivable* 679 instantiate_object(BMessage* from) 680 { 681 return instantiate_object(from, NULL); 682 } 683 684 685 bool 686 validate_instantiation(BMessage* from, const char* className) 687 { 688 // Make sure our params are kosher -- original skimped here =P 689 if (!from) { 690 errno = B_BAD_VALUE; 691 return false; 692 } 693 694 BString name = className; 695 for (int32 pass = 0; pass < 2; pass++) { 696 const char* archiveClassName; 697 for (int32 index = 0; from->FindString(B_CLASS_FIELD, index, 698 &archiveClassName) == B_OK; ++index) { 699 if (name == archiveClassName) 700 return true; 701 } 702 703 if (!add_private_namespace(name)) 704 break; 705 } 706 707 errno = B_MISMATCHED_VALUES; 708 syslog(LOG_ERR, "validate_instantiation failed on class %s.", className); 709 710 return false; 711 } 712 713 714 instantiation_func 715 find_instantiation_func(const char* className, const char* signature) 716 { 717 if (className == NULL) { 718 errno = B_BAD_VALUE; 719 return NULL; 720 } 721 722 thread_info threadInfo; 723 status_t err = get_thread_info(find_thread(NULL), &threadInfo); 724 if (err != B_OK) { 725 errno = err; 726 return NULL; 727 } 728 729 instantiation_func instantiationFunc = NULL; 730 image_info imageInfo; 731 732 BString name = className; 733 for (int32 pass = 0; pass < 2; pass++) { 734 BString funcName; 735 build_function_name(name, funcName); 736 737 // for each image_id in team_id 738 int32 cookie = 0; 739 while (instantiationFunc == NULL 740 && get_next_image_info(threadInfo.team, &cookie, &imageInfo) 741 == B_OK) { 742 instantiationFunc = find_function_in_image(funcName, imageInfo.id, 743 err); 744 } 745 if (instantiationFunc != NULL) 746 break; 747 748 // Check if we have a private class, and add the BPrivate namespace 749 // (for backwards compatibility) 750 if (!add_private_namespace(name)) 751 break; 752 } 753 754 if (instantiationFunc != NULL 755 && check_signature(signature, imageInfo) != B_OK) 756 return NULL; 757 758 return instantiationFunc; 759 } 760 761 762 instantiation_func 763 find_instantiation_func(const char* className) 764 { 765 return find_instantiation_func(className, NULL); 766 } 767 768 769 instantiation_func 770 find_instantiation_func(BMessage* archive) 771 { 772 if (archive == NULL) { 773 errno = B_BAD_VALUE; 774 return NULL; 775 } 776 777 const char* name = NULL; 778 const char* signature = NULL; 779 if (archive->FindString(B_CLASS_FIELD, &name) != B_OK 780 || archive->FindString(B_ADD_ON_FIELD, &signature)) { 781 errno = B_BAD_VALUE; 782 return NULL; 783 } 784 785 return find_instantiation_func(name, signature); 786 } 787 788 789 // BArchivable binary compatability 790 #if __GNUC__ == 2 791 792 793 extern "C" status_t 794 _ReservedArchivable1__11BArchivable(BArchivable* archivable, 795 const BMessage* archive) 796 { 797 // AllUnarchived 798 perform_data_all_unarchived performData; 799 performData.archive = archive; 800 801 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 802 return performData.return_value; 803 } 804 805 806 extern "C" status_t 807 _ReservedArchivable2__11BArchivable(BArchivable* archivable, 808 BMessage* archive) 809 { 810 // AllArchived 811 perform_data_all_archived performData; 812 performData.archive = archive; 813 814 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 815 return performData.return_value; 816 } 817 818 819 #elif __GNUC__ > 2 820 821 822 extern "C" status_t 823 _ZN11BArchivable20_ReservedArchivable1Ev(BArchivable* archivable, 824 const BMessage* archive) 825 { 826 // AllUnarchived 827 perform_data_all_unarchived performData; 828 performData.archive = archive; 829 830 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 831 return performData.return_value; 832 } 833 834 835 extern "C" status_t 836 _ZN11BArchivable20_ReservedArchivable2Ev(BArchivable* archivable, 837 BMessage* archive) 838 { 839 // AllArchived 840 perform_data_all_archived performData; 841 performData.archive = archive; 842 843 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 844 return performData.return_value; 845 } 846 847 848 #endif // _GNUC__ > 2 849 850 851 void BArchivable::_ReservedArchivable3() {} 852 853 854