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