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 // managed top level archives return here 515 bool dummy; 516 if (archive->FindBool(kManagedField, &dummy) == B_OK) 517 return true; 518 519 return false; 520 } 521 522 523 template<> 524 status_t 525 BUnarchiver::InstantiateObject<BArchivable>(BMessage* from, 526 BArchivable*& object) 527 { 528 BUnarchiver unarchiver(BUnarchiver::PrepareArchive(from)); 529 object = instantiate_object(from); 530 return unarchiver.Finish(); 531 } 532 533 534 BMessage* 535 BUnarchiver::PrepareArchive(BMessage*& archive) 536 { 537 // this check allows PrepareArchive to be 538 // called on new or old-style archives 539 if (BUnarchiver::IsArchiveManaged(archive)) { 540 BUnarchiveManager* manager = BManagerBase::UnarchiveManager(archive); 541 if (!manager) 542 manager = new BUnarchiveManager(archive); 543 manager->Acquire(); 544 } 545 return archive; 546 } 547 548 549 void 550 BUnarchiver::RegisterArchivable(BArchivable* archivable) 551 { 552 _CallDebuggerIfManagerNull(); 553 fManager->RegisterArchivable(archivable); 554 } 555 556 557 void 558 BUnarchiver::_CallDebuggerIfManagerNull() 559 { 560 if (!fManager) 561 debugger("BUnarchiver used with legacy or unprepared archive."); 562 } 563 564 565 // #pragma mark - 566 567 568 BArchivable* 569 instantiate_object(BMessage* archive, image_id* _id) 570 { 571 status_t statusBuffer; 572 status_t* status = &statusBuffer; 573 if (_id != NULL) 574 status = _id; 575 576 // Check our params 577 if (archive == NULL) { 578 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 579 *status = B_BAD_VALUE; 580 return NULL; 581 } 582 583 // Get class name from archive 584 const char* className = NULL; 585 status_t err = archive->FindString(B_CLASS_FIELD, &className); 586 if (err) { 587 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 588 "defining the class name (%s).", strerror(err)); 589 *status = B_BAD_VALUE; 590 return NULL; 591 } 592 593 // Get sig from archive 594 const char* signature = NULL; 595 bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK; 596 597 instantiation_func instantiationFunc = find_instantiation_func(className, 598 signature); 599 600 // if find_instantiation_func() can't locate Class::Instantiate() 601 // and a signature was specified 602 if (!instantiationFunc && hasSignature) { 603 // use BRoster::FindApp() to locate an app or add-on with the symbol 604 BRoster Roster; 605 entry_ref ref; 606 err = Roster.FindApp(signature, &ref); 607 608 // if an entry_ref is obtained 609 BEntry entry; 610 if (err == B_OK) 611 err = entry.SetTo(&ref); 612 613 BPath path; 614 if (err == B_OK) 615 err = entry.GetPath(&path); 616 617 if (err != B_OK) { 618 syslog(LOG_ERR, "instantiate_object failed: Error finding app " 619 "with signature \"%s\" (%s)", signature, strerror(err)); 620 *status = err; 621 return NULL; 622 } 623 624 // load the app/add-on 625 image_id addOn = load_add_on(path.Path()); 626 if (addOn < B_OK) { 627 syslog(LOG_ERR, "instantiate_object failed: Could not load " 628 "add-on %s: %s.", path.Path(), strerror(addOn)); 629 *status = addOn; 630 return NULL; 631 } 632 633 // Save the image_id 634 if (_id != NULL) 635 *_id = addOn; 636 637 BString name = className; 638 for (int32 pass = 0; pass < 2; pass++) { 639 BString funcName; 640 build_function_name(name, funcName); 641 642 instantiationFunc = find_function_in_image(funcName, addOn, err); 643 if (instantiationFunc != NULL) 644 break; 645 646 // Check if we have a private class, and add the BPrivate namespace 647 // (for backwards compatibility) 648 if (!add_private_namespace(name)) 649 break; 650 } 651 652 if (instantiationFunc == NULL) { 653 syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 654 "Instantiate static function for class %s.", className); 655 *status = B_NAME_NOT_FOUND; 656 return NULL; 657 } 658 } else if (instantiationFunc == NULL) { 659 syslog(LOG_ERR, "instantiate_object failed: No signature specified " 660 "in archive, looking for class \"%s\".", className); 661 *status = B_NAME_NOT_FOUND; 662 return NULL; 663 } 664 665 // if Class::Instantiate(BMessage*) was found 666 if (instantiationFunc != NULL) { 667 // use to create and return an object instance 668 return instantiationFunc(archive); 669 } 670 671 return NULL; 672 } 673 674 675 BArchivable* 676 instantiate_object(BMessage* from) 677 { 678 return instantiate_object(from, NULL); 679 } 680 681 682 bool 683 validate_instantiation(BMessage* from, const char* className) 684 { 685 // Make sure our params are kosher -- original skimped here =P 686 if (!from) { 687 errno = B_BAD_VALUE; 688 return false; 689 } 690 691 BString name = className; 692 for (int32 pass = 0; pass < 2; pass++) { 693 const char* archiveClassName; 694 for (int32 index = 0; from->FindString(B_CLASS_FIELD, index, 695 &archiveClassName) == B_OK; ++index) { 696 if (name == archiveClassName) 697 return true; 698 } 699 700 if (!add_private_namespace(name)) 701 break; 702 } 703 704 errno = B_MISMATCHED_VALUES; 705 syslog(LOG_ERR, "validate_instantiation failed on class %s.", className); 706 707 return false; 708 } 709 710 711 instantiation_func 712 find_instantiation_func(const char* className, const char* signature) 713 { 714 if (className == NULL) { 715 errno = B_BAD_VALUE; 716 return NULL; 717 } 718 719 thread_info threadInfo; 720 status_t err = get_thread_info(find_thread(NULL), &threadInfo); 721 if (err != B_OK) { 722 errno = err; 723 return NULL; 724 } 725 726 instantiation_func instantiationFunc = NULL; 727 image_info imageInfo; 728 729 BString name = className; 730 for (int32 pass = 0; pass < 2; pass++) { 731 BString funcName; 732 build_function_name(name, funcName); 733 734 // for each image_id in team_id 735 int32 cookie = 0; 736 while (instantiationFunc == NULL 737 && get_next_image_info(threadInfo.team, &cookie, &imageInfo) 738 == B_OK) { 739 instantiationFunc = find_function_in_image(funcName, imageInfo.id, 740 err); 741 } 742 if (instantiationFunc != NULL) 743 break; 744 745 // Check if we have a private class, and add the BPrivate namespace 746 // (for backwards compatibility) 747 if (!add_private_namespace(name)) 748 break; 749 } 750 751 if (instantiationFunc != NULL 752 && check_signature(signature, imageInfo) != B_OK) 753 return NULL; 754 755 return instantiationFunc; 756 } 757 758 759 instantiation_func 760 find_instantiation_func(const char* className) 761 { 762 return find_instantiation_func(className, NULL); 763 } 764 765 766 instantiation_func 767 find_instantiation_func(BMessage* archive) 768 { 769 if (archive == NULL) { 770 errno = B_BAD_VALUE; 771 return NULL; 772 } 773 774 const char* name = NULL; 775 const char* signature = NULL; 776 if (archive->FindString(B_CLASS_FIELD, &name) != B_OK 777 || archive->FindString(B_ADD_ON_FIELD, &signature)) { 778 errno = B_BAD_VALUE; 779 return NULL; 780 } 781 782 return find_instantiation_func(name, signature); 783 } 784 785 786 // BArchivable binary compatability 787 #if __GNUC__ == 2 788 789 790 extern "C" status_t 791 _ReservedArchivable1__11BArchivable(BArchivable* archivable, 792 const BMessage* archive) 793 { 794 // AllUnarchived 795 perform_data_all_unarchived performData; 796 performData.archive = archive; 797 798 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 799 return performData.return_value; 800 } 801 802 803 extern "C" status_t 804 _ReservedArchivable2__11BArchivable(BArchivable* archivable, 805 BMessage* archive) 806 { 807 // AllArchived 808 perform_data_all_archived performData; 809 performData.archive = archive; 810 811 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 812 return performData.return_value; 813 } 814 815 816 #elif __GNUC__ > 2 817 818 819 extern "C" status_t 820 _ZN11BArchivable20_ReservedArchivable1Ev(BArchivable* archivable, 821 const BMessage* archive) 822 { 823 // AllUnarchived 824 perform_data_all_unarchived performData; 825 performData.archive = archive; 826 827 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData); 828 return performData.return_value; 829 } 830 831 832 extern "C" status_t 833 _ZN11BArchivable20_ReservedArchivable2Ev(BArchivable* archivable, 834 BMessage* archive) 835 { 836 // AllArchived 837 perform_data_all_archived performData; 838 performData.archive = archive; 839 840 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData); 841 return performData.return_value; 842 } 843 844 845 #endif // _GNUC__ > 2 846 847 848 void BArchivable::_ReservedArchivable3() {} 849 850 851