1 /* 2 * Copyright (c) 2001-2012, Haiku, Inc. 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)) 234 return B_MISMATCHED_VALUES; 235 236 return B_OK; 237 } 238 239 240 namespace BPrivate 241 { 242 243 244 instantiation_func 245 find_instantiation_func(const char* className, const char* signature, 246 image_id* id) 247 { 248 if (className == NULL) { 249 errno = B_BAD_VALUE; 250 return NULL; 251 } 252 253 thread_info threadInfo; 254 status_t err = get_thread_info(find_thread(NULL), &threadInfo); 255 if (err != B_OK) { 256 errno = err; 257 return NULL; 258 } 259 260 instantiation_func instantiationFunc = NULL; 261 image_info imageInfo; 262 263 BString name = className; 264 for (int32 pass = 0; pass < 2; pass++) { 265 BString funcName; 266 build_function_name(name, funcName); 267 268 // for each image_id in team_id 269 int32 cookie = 0; 270 while (instantiationFunc == NULL 271 && get_next_image_info(threadInfo.team, &cookie, &imageInfo) 272 == B_OK) { 273 instantiationFunc = find_function_in_image(funcName, imageInfo.id, 274 err); 275 } 276 if (instantiationFunc != NULL) { 277 // if requested, save the image id in 278 // which the function was found 279 if (id != NULL) 280 *id = imageInfo.id; 281 break; 282 } 283 284 // Check if we have a private class, and add the BPrivate namespace 285 // (for backwards compatibility) 286 if (!add_private_namespace(name)) 287 break; 288 } 289 290 if (instantiationFunc != NULL 291 && check_signature(signature, imageInfo) != B_OK) 292 return NULL; 293 294 return instantiationFunc; 295 } 296 297 298 } 299 300 301 // #pragma mark - 302 303 304 BArchivable::BArchivable() 305 : 306 fArchivingToken(NULL_TOKEN) 307 { 308 } 309 310 311 BArchivable::BArchivable(BMessage* from) 312 : 313 fArchivingToken(NULL_TOKEN) 314 { 315 if (BUnarchiver::IsArchiveManaged(from)) { 316 BUnarchiver::PrepareArchive(from); 317 BUnarchiver(from).RegisterArchivable(this); 318 } 319 } 320 321 322 BArchivable::~BArchivable() 323 { 324 } 325 326 327 status_t 328 BArchivable::Archive(BMessage* into, bool deep) const 329 { 330 if (!into) { 331 // TODO: logging/other error reporting? 332 return B_BAD_VALUE; 333 } 334 335 if (BManagerBase::ArchiveManager(into)) 336 BArchiver(into).RegisterArchivable(this); 337 338 BString name; 339 status_t status = demangle_class_name(typeid(*this).name(), name); 340 if (status != B_OK) 341 return status; 342 343 return into->AddString(B_CLASS_FIELD, name); 344 } 345 346 347 BArchivable* 348 BArchivable::Instantiate(BMessage* from) 349 { 350 debugger("Can't create a plain BArchivable object"); 351 return NULL; 352 } 353 354 355 status_t 356 BArchivable::Perform(perform_code d, void* arg) 357 { 358 switch (d) { 359 case PERFORM_CODE_ALL_UNARCHIVED: 360 { 361 perform_data_all_unarchived* data = 362 (perform_data_all_unarchived*)arg; 363 364 data->return_value = BArchivable::AllUnarchived(data->archive); 365 return B_OK; 366 } 367 368 case PERFORM_CODE_ALL_ARCHIVED: 369 { 370 perform_data_all_archived* data = 371 (perform_data_all_archived*)arg; 372 373 data->return_value = BArchivable::AllArchived(data->archive); 374 return B_OK; 375 } 376 } 377 return B_NAME_NOT_FOUND; 378 } 379 380 381 status_t 382 BArchivable::AllUnarchived(const BMessage* archive) 383 { 384 return B_OK; 385 } 386 387 388 status_t 389 BArchivable::AllArchived(BMessage* archive) const 390 { 391 return B_OK; 392 } 393 394 395 // #pragma mark - 396 397 398 BArchiver::BArchiver(BMessage* archive) 399 : 400 fManager(BManagerBase::ArchiveManager(archive)), 401 fArchive(archive), 402 fFinished(false) 403 { 404 if (!fManager) 405 fManager = new BArchiveManager(this); 406 } 407 408 409 BArchiver::~BArchiver() 410 { 411 if (!fFinished) 412 fManager->ArchiverLeaving(this, B_OK); 413 } 414 415 416 status_t 417 BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep) 418 { 419 int32 token; 420 status_t err = GetTokenForArchivable(archivable, deep, token); 421 422 if (err != B_OK) 423 return err; 424 425 return fArchive->AddInt32(name, token); 426 } 427 428 429 status_t 430 BArchiver::GetTokenForArchivable(BArchivable* archivable, 431 bool deep, int32& _token) 432 { 433 return fManager->ArchiveObject(archivable, deep, _token); 434 } 435 436 437 bool 438 BArchiver::IsArchived(BArchivable* archivable) 439 { 440 return fManager->IsArchived(archivable); 441 } 442 443 444 status_t 445 BArchiver::Finish(status_t err) 446 { 447 if (fFinished) 448 debugger("Finish() called multiple times on same BArchiver."); 449 450 fFinished = true; 451 452 return fManager->ArchiverLeaving(this, err); 453 } 454 455 456 BMessage* 457 BArchiver::ArchiveMessage() const 458 { 459 return fArchive; 460 } 461 462 463 void 464 BArchiver::RegisterArchivable(const BArchivable* archivable) 465 { 466 fManager->RegisterArchivable(archivable); 467 } 468 469 470 // #pragma mark - 471 472 473 BUnarchiver::BUnarchiver(const BMessage* archive) 474 : 475 fManager(BManagerBase::UnarchiveManager(archive)), 476 fArchive(archive), 477 fFinished(false) 478 { 479 } 480 481 482 BUnarchiver::~BUnarchiver() 483 { 484 if (!fFinished && fManager) 485 fManager->UnarchiverLeaving(this, B_OK); 486 } 487 488 489 template<> 490 status_t 491 BUnarchiver::GetObject<BArchivable>(int32 token, 492 ownership_policy owning, BArchivable*& object) 493 { 494 _CallDebuggerIfManagerNull(); 495 return fManager->GetArchivableForToken(token, owning, object); 496 } 497 498 499 template<> 500 status_t 501 BUnarchiver::FindObject<BArchivable>(const char* name, 502 int32 index, ownership_policy owning, BArchivable*& archivable) 503 { 504 archivable = NULL; 505 int32 token; 506 status_t err = fArchive->FindInt32(name, index, &token); 507 if (err != B_OK) 508 return err; 509 510 return GetObject(token, owning, archivable); 511 } 512 513 514 bool 515 BUnarchiver::IsInstantiated(int32 token) 516 { 517 _CallDebuggerIfManagerNull(); 518 return fManager->IsInstantiated(token); 519 } 520 521 522 bool 523 BUnarchiver::IsInstantiated(const char* field, int32 index) 524 { 525 int32 token; 526 if (fArchive->FindInt32(field, index, &token) == B_OK) 527 return IsInstantiated(token); 528 return false; 529 } 530 531 532 status_t 533 BUnarchiver::Finish(status_t err) 534 { 535 if (fFinished) 536 debugger("Finish() called multiple times on same BArchiver."); 537 538 fFinished = true; 539 if (fManager) 540 return fManager->UnarchiverLeaving(this, err); 541 else 542 return B_OK; 543 } 544 545 546 const BMessage* 547 BUnarchiver::ArchiveMessage() const 548 { 549 return fArchive; 550 } 551 552 553 void 554 BUnarchiver::AssumeOwnership(BArchivable* archivable) 555 { 556 _CallDebuggerIfManagerNull(); 557 fManager->AssumeOwnership(archivable); 558 } 559 560 561 void 562 BUnarchiver::RelinquishOwnership(BArchivable* archivable) 563 { 564 _CallDebuggerIfManagerNull(); 565 fManager->RelinquishOwnership(archivable); 566 } 567 568 569 bool 570 BUnarchiver::IsArchiveManaged(const BMessage* archive) 571 { 572 // managed child archives will return here 573 if (BManagerBase::ManagerPointer(archive)) 574 return true; 575 576 if (!archive) 577 return false; 578 579 // managed top level archives return here 580 bool dummy; 581 if (archive->FindBool(kManagedField, &dummy) == B_OK) 582 return true; 583 584 return false; 585 } 586 587 588 template<> 589 status_t 590 BUnarchiver::InstantiateObject<BArchivable>(BMessage* from, 591 BArchivable*& object) 592 { 593 BUnarchiver unarchiver(BUnarchiver::PrepareArchive(from)); 594 object = instantiate_object(from); 595 return unarchiver.Finish(); 596 } 597 598 599 BMessage* 600 BUnarchiver::PrepareArchive(BMessage*& archive) 601 { 602 // this check allows PrepareArchive to be 603 // called on new or old-style archives 604 if (BUnarchiver::IsArchiveManaged(archive)) { 605 BUnarchiveManager* manager = BManagerBase::UnarchiveManager(archive); 606 if (!manager) 607 manager = new BUnarchiveManager(archive); 608 manager->Acquire(); 609 } 610 return archive; 611 } 612 613 614 void 615 BUnarchiver::RegisterArchivable(BArchivable* archivable) 616 { 617 _CallDebuggerIfManagerNull(); 618 fManager->RegisterArchivable(archivable); 619 } 620 621 622 void 623 BUnarchiver::_CallDebuggerIfManagerNull() 624 { 625 if (!fManager) 626 debugger("BUnarchiver used with legacy or unprepared archive."); 627 } 628 629 630 // #pragma mark - 631 632 633 BArchivable* 634 instantiate_object(BMessage* archive, image_id* _id) 635 { 636 status_t statusBuffer; 637 status_t* status = &statusBuffer; 638 if (_id != NULL) 639 status = _id; 640 641 // Check our params 642 if (archive == NULL) { 643 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 644 *status = B_BAD_VALUE; 645 return NULL; 646 } 647 648 // Get class name from archive 649 const char* className = NULL; 650 status_t err = archive->FindString(B_CLASS_FIELD, &className); 651 if (err) { 652 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 653 "defining the class name (%s).", strerror(err)); 654 *status = B_BAD_VALUE; 655 return NULL; 656 } 657 658 // Get sig from archive 659 const char* signature = NULL; 660 bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK; 661 662 instantiation_func instantiationFunc = BPrivate::find_instantiation_func( 663 className, signature, _id); 664 665 // if find_instantiation_func() can't locate Class::Instantiate() 666 // and a signature was specified 667 if (!instantiationFunc && hasSignature) { 668 // use BRoster::FindApp() to locate an app or add-on with the symbol 669 BRoster Roster; 670 entry_ref ref; 671 err = Roster.FindApp(signature, &ref); 672 673 // if an entry_ref is obtained 674 BEntry entry; 675 if (err == B_OK) 676 err = entry.SetTo(&ref); 677 678 BPath path; 679 if (err == B_OK) 680 err = entry.GetPath(&path); 681 682 if (err != B_OK) { 683 syslog(LOG_ERR, "instantiate_object failed: Error finding app " 684 "with signature \"%s\" (%s)", signature, strerror(err)); 685 *status = err; 686 return NULL; 687 } 688 689 // load the app/add-on 690 image_id addOn = load_add_on(path.Path()); 691 if (addOn < B_OK) { 692 syslog(LOG_ERR, "instantiate_object failed: Could not load " 693 "add-on %s: %s.", path.Path(), strerror(addOn)); 694 *status = addOn; 695 return NULL; 696 } 697 698 // Save the image_id 699 if (_id != NULL) 700 *_id = addOn; 701 702 BString name = className; 703 for (int32 pass = 0; pass < 2; pass++) { 704 BString funcName; 705 build_function_name(name, funcName); 706 707 instantiationFunc = find_function_in_image(funcName, addOn, err); 708 if (instantiationFunc != NULL) 709 break; 710 711 // Check if we have a private class, and add the BPrivate namespace 712 // (for backwards compatibility) 713 if (!add_private_namespace(name)) 714 break; 715 } 716 717 if (instantiationFunc == NULL) { 718 syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 719 "Instantiate static function for class %s.", className); 720 *status = B_NAME_NOT_FOUND; 721 return NULL; 722 } 723 } else if (instantiationFunc == NULL) { 724 syslog(LOG_ERR, "instantiate_object failed: No signature specified " 725 "in archive, looking for class \"%s\".", className); 726 *status = B_NAME_NOT_FOUND; 727 return NULL; 728 } 729 730 // if Class::Instantiate(BMessage*) was found 731 if (instantiationFunc != NULL) { 732 // use to create and return an object instance 733 return instantiationFunc(archive); 734 } 735 736 return NULL; 737 } 738 739 740 BArchivable* 741 instantiate_object(BMessage* from) 742 { 743 return instantiate_object(from, NULL); 744 } 745 746 747 bool 748 validate_instantiation(BMessage* from, const char* className) 749 { 750 // Make sure our params are kosher -- original skimped here =P 751 if (!from) { 752 errno = B_BAD_VALUE; 753 return false; 754 } 755 756 BString name = className; 757 for (int32 pass = 0; pass < 2; pass++) { 758 const char* archiveClassName; 759 for (int32 index = 0; from->FindString(B_CLASS_FIELD, index, 760 &archiveClassName) == B_OK; ++index) { 761 if (name == archiveClassName) 762 return true; 763 } 764 765 if (!add_private_namespace(name)) 766 break; 767 } 768 769 errno = B_MISMATCHED_VALUES; 770 syslog(LOG_ERR, "validate_instantiation failed on class %s.", className); 771 772 return false; 773 } 774 775 776 instantiation_func 777 find_instantiation_func(const char* className, const char* signature) 778 { 779 return BPrivate::find_instantiation_func(className, signature, NULL); 780 } 781 782 783 instantiation_func 784 find_instantiation_func(const char* className) 785 { 786 return find_instantiation_func(className, NULL); 787 } 788 789 790 instantiation_func 791 find_instantiation_func(BMessage* archive) 792 { 793 if (archive == NULL) { 794 errno = B_BAD_VALUE; 795 return NULL; 796 } 797 798 const char* name = NULL; 799 const char* signature = NULL; 800 if (archive->FindString(B_CLASS_FIELD, &name) != B_OK 801 || archive->FindString(B_ADD_ON_FIELD, &signature)) { 802 errno = B_BAD_VALUE; 803 return NULL; 804 } 805 806 return find_instantiation_func(name, signature); 807 } 808 809 810 // BArchivable binary compatibility 811 #if __GNUC__ == 2 812 813 814 extern "C" status_t 815 _ReservedArchivable1__11BArchivable(BArchivable* archivable, 816 const BMessage* archive) 817 { 818 // AllUnarchived 819 perform_data_all_unarchived performData; 820 performData.archive = archive; 821 822 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 823 return performData.return_value; 824 } 825 826 827 extern "C" status_t 828 _ReservedArchivable2__11BArchivable(BArchivable* archivable, 829 BMessage* archive) 830 { 831 // AllArchived 832 perform_data_all_archived performData; 833 performData.archive = archive; 834 835 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 836 return performData.return_value; 837 } 838 839 840 #elif __GNUC__ > 2 841 842 843 extern "C" status_t 844 _ZN11BArchivable20_ReservedArchivable1Ev(BArchivable* archivable, 845 const BMessage* archive) 846 { 847 // AllUnarchived 848 perform_data_all_unarchived performData; 849 performData.archive = archive; 850 851 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 852 return performData.return_value; 853 } 854 855 856 extern "C" status_t 857 _ZN11BArchivable20_ReservedArchivable2Ev(BArchivable* archivable, 858 BMessage* archive) 859 { 860 // AllArchived 861 perform_data_all_archived performData; 862 performData.archive = archive; 863 864 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 865 return performData.return_value; 866 } 867 868 869 #endif // _GNUC__ > 2 870 871 872 void BArchivable::_ReservedArchivable3() {} 873 874 875