1 /* 2 * Copyright 2002-2014 Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Rene Gollent, rene@gollent.com 8 * Ingo Weinhold, ingo_weinhold@gmx.de 9 */ 10 11 12 #include <mime/DatabaseLocation.h> 13 14 #include <stdlib.h> 15 #include <syslog.h> 16 17 #include <new> 18 19 #include <Bitmap.h> 20 #include <DataIO.h> 21 #include <Directory.h> 22 #include <File.h> 23 #include <fs_attr.h> 24 #include <IconUtils.h> 25 #include <Message.h> 26 #include <Node.h> 27 28 #include <AutoDeleter.h> 29 #include <mime/database_support.h> 30 31 32 namespace BPrivate { 33 namespace Storage { 34 namespace Mime { 35 36 37 DatabaseLocation::DatabaseLocation() 38 : 39 fDirectories() 40 { 41 } 42 43 44 DatabaseLocation::~DatabaseLocation() 45 { 46 } 47 48 49 bool 50 DatabaseLocation::AddDirectory(const BString& directory) 51 { 52 return !directory.IsEmpty() && fDirectories.Add(directory); 53 } 54 55 56 /*! Opens a BNode on the given type, failing if the type has no 57 corresponding file in the database. 58 59 \param type The MIME type to open. 60 \param _node Node opened on the given MIME type. 61 */ 62 status_t 63 DatabaseLocation::OpenType(const char* type, BNode& _node) const 64 { 65 if (type == NULL) 66 return B_BAD_VALUE; 67 68 int32 index; 69 return _OpenType(type, _node, index); 70 } 71 72 73 /*! Opens a BNode on the given type, creating a node of the 74 appropriate flavor if requested (and necessary). 75 76 All MIME types are converted to lowercase for use in the filesystem. 77 78 \param type The MIME type to open. 79 \param _node Node opened on the given MIME type. 80 \param _didCreate If not \c NULL, the variable the pointer refers to is 81 set to \c true, if the node has been newly created, to \c false 82 otherwise. 83 84 \return A status code. 85 */ 86 status_t 87 DatabaseLocation::OpenWritableType(const char* type, BNode& _node, bool create, 88 bool* _didCreate) const 89 { 90 if (_didCreate) 91 *_didCreate = false; 92 93 // See, if the type already exists. 94 int32 index; 95 status_t result = _OpenType(type, _node, index); 96 if (result == B_OK) { 97 if (index == 0) 98 return B_OK; 99 else if (!create) 100 return B_ENTRY_NOT_FOUND; 101 102 // The caller wants a editable node, but the node found is not in the 103 // user's settings directory. Copy the node. 104 BNode nodeToClone(_node); 105 if (nodeToClone.InitCheck() != B_OK) 106 return nodeToClone.InitCheck(); 107 108 result = _CopyTypeNode(nodeToClone, type, _node); 109 if (result != B_OK) { 110 _node.Unset(); 111 return result; 112 } 113 114 if (_didCreate != NULL) 115 *_didCreate = true; 116 117 return result; 118 } else if (!create) 119 return B_ENTRY_NOT_FOUND; 120 121 // type doesn't exist yet -- create the respective node 122 result = _CreateTypeNode(type, _node); 123 if (result != B_OK) 124 return result; 125 126 // write the type attribute 127 size_t toWrite = strlen(type) + 1; 128 ssize_t bytesWritten = _node.WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, 129 toWrite); 130 if (bytesWritten < 0) 131 result = bytesWritten; 132 else if ((size_t)bytesWritten != toWrite) 133 result = B_FILE_ERROR; 134 135 if (result != B_OK) { 136 _node.Unset(); 137 return result; 138 } 139 140 if (_didCreate != NULL) 141 *_didCreate = true; 142 return B_OK; 143 } 144 145 146 /*! Reads up to \c length bytes of the given data from the given attribute 147 for the given MIME type. 148 149 If no entry for the given type exists in the database, the function fails, 150 and the contents of \c data are undefined. 151 152 \param type The MIME type. 153 \param attribute The attribute name. 154 \param data Pointer to a memory buffer into which the data should be copied. 155 \param length The maximum number of bytes to read. 156 \param datatype The expected data type. 157 158 \return If successful, the number of bytes read is returned, otherwise, an 159 error code is returned. 160 */ 161 ssize_t 162 DatabaseLocation::ReadAttribute(const char* type, const char* attribute, 163 void* data, size_t length, type_code datatype) const 164 { 165 if (type == NULL || attribute == NULL || data == NULL) 166 return B_BAD_VALUE; 167 168 BNode node; 169 status_t result = OpenType(type, node); 170 if (result != B_OK) 171 return result; 172 173 return node.ReadAttr(attribute, datatype, 0, data, length); 174 } 175 176 177 /*! Reads a flattened BMessage from the given attribute of the given 178 MIME type. 179 180 If no entry for the given type exists in the database, or if the data 181 stored in the attribute is not a flattened BMessage, the function fails 182 and the contents of \c msg are undefined. 183 184 \param type The MIME type. 185 \param attribute The attribute name. 186 \param data Reference to a pre-allocated BMessage into which the attribute 187 data is unflattened. 188 189 \return A status code. 190 */ 191 status_t 192 DatabaseLocation::ReadMessageAttribute(const char* type, const char* attribute, 193 BMessage& _message) const 194 { 195 if (type == NULL || attribute == NULL) 196 return B_BAD_VALUE; 197 198 BNode node; 199 attr_info info; 200 201 status_t result = OpenType(type, node); 202 if (result != B_OK) 203 return result; 204 205 result = node.GetAttrInfo(attribute, &info); 206 if (result != B_OK) 207 return result; 208 209 if (info.type != B_MESSAGE_TYPE) 210 return B_BAD_VALUE; 211 212 void* buffer = malloc(info.size); 213 if (buffer == NULL) 214 return B_NO_MEMORY; 215 MemoryDeleter bufferDeleter(buffer); 216 217 ssize_t bytesRead = node.ReadAttr(attribute, B_MESSAGE_TYPE, 0, buffer, 218 info.size); 219 if (bytesRead != info.size) 220 return bytesRead < 0 ? (status_t)bytesRead : (status_t)B_FILE_ERROR; 221 222 return _message.Unflatten((const char*)buffer); 223 } 224 225 226 /*! Reads a BString from the given attribute of the given MIME type. 227 228 If no entry for the given type exists in the database, the function fails 229 and the contents of \c str are undefined. 230 231 \param type The MIME type. 232 \param attribute The attribute name. 233 \param _string Reference to a pre-allocated BString into which the attribute 234 data stored. 235 236 \return A status code. 237 */ 238 status_t 239 DatabaseLocation::ReadStringAttribute(const char* type, const char* attribute, 240 BString& _string) const 241 { 242 if (type == NULL || attribute == NULL) 243 return B_BAD_VALUE; 244 245 BNode node; 246 status_t result = OpenType(type, node); 247 if (result != B_OK) 248 return result; 249 250 return node.ReadAttrString(attribute, &_string); 251 } 252 253 254 /*! Writes \c len bytes of the given data to the given attribute 255 for the given MIME type. 256 257 If no entry for the given type exists in the database, it is created. 258 259 \param type The MIME type. 260 \param attribute The attribute name. 261 \param data Pointer to the data to write. 262 \param length The number of bytes to write. 263 \param datatype The data type of the given data. 264 265 \return A status code. 266 */ 267 status_t 268 DatabaseLocation::WriteAttribute(const char* type, const char* attribute, 269 const void* data, size_t length, type_code datatype, bool* _didCreate) const 270 { 271 if (type == NULL || attribute == NULL || data == NULL) 272 return B_BAD_VALUE; 273 274 BNode node; 275 status_t result = OpenWritableType(type, node, true, _didCreate); 276 if (result != B_OK) 277 return result; 278 279 ssize_t bytesWritten = node.WriteAttr(attribute, datatype, 0, data, length); 280 if (bytesWritten < 0) 281 return bytesWritten; 282 return bytesWritten == (ssize_t)length 283 ? (status_t)B_OK : (status_t)B_FILE_ERROR; 284 } 285 286 287 /*! Flattens the given \c BMessage and writes it to the given attribute 288 of the given MIME type. 289 290 If no entry for the given type exists in the database, it is created. 291 292 \param type The MIME type. 293 \param attribute The attribute name. 294 \param message The BMessage to flatten and write. 295 296 \return A status code. 297 */ 298 status_t 299 DatabaseLocation::WriteMessageAttribute(const char* type, const char* attribute, 300 const BMessage& message, bool* _didCreate) const 301 { 302 BMallocIO data; 303 status_t result = data.SetSize(message.FlattenedSize()); 304 if (result != B_OK) 305 return result; 306 307 ssize_t bytes; 308 result = message.Flatten(&data, &bytes); 309 if (result != B_OK) 310 return result; 311 312 return WriteAttribute(type, attribute, data.Buffer(), data.BufferLength(), 313 B_MESSAGE_TYPE, _didCreate); 314 } 315 316 317 /*! Deletes the given attribute for the given type 318 319 \param type The mime type 320 \param attribute The attribute name 321 322 \return A status code, \c B_OK on success or an error code on failure. 323 \retval B_OK Success. 324 \retval B_ENTRY_NOT_FOUND No such type or attribute. 325 */ 326 status_t 327 DatabaseLocation::DeleteAttribute(const char* type, const char* attribute) const 328 { 329 if (type == NULL || attribute == NULL) 330 return B_BAD_VALUE; 331 332 BNode node; 333 status_t result = OpenWritableType(type, node, false); 334 if (result != B_OK) 335 return result; 336 337 return node.RemoveAttr(attribute); 338 } 339 340 341 /*! Fetches the application hint for the given MIME type. 342 343 The entry_ref pointed to by \c ref must be pre-allocated. 344 345 \param type The MIME type of interest 346 \param _ref Reference to a pre-allocated \c entry_ref struct into 347 which the location of the hint application is copied. 348 349 \return A status code, \c B_OK on success or an error code on failure. 350 \retval B_OK Success. 351 \retval B_ENTRY_NOT_FOUND No app hint exists for the given type 352 */ 353 status_t 354 DatabaseLocation::GetAppHint(const char* type, entry_ref& _ref) 355 { 356 if (type == NULL) 357 return B_BAD_VALUE; 358 359 char path[B_PATH_NAME_LENGTH]; 360 BEntry entry; 361 ssize_t status = ReadAttribute(type, kAppHintAttr, path, B_PATH_NAME_LENGTH, 362 kAppHintType); 363 364 if (status >= B_OK) 365 status = entry.SetTo(path); 366 if (status == B_OK) 367 status = entry.GetRef(&_ref); 368 369 return status; 370 } 371 372 373 /*! Fetches from the MIME database a BMessage describing the attributes 374 typically associated with files of the given MIME type 375 376 The attribute information is returned in a pre-allocated BMessage pointed to 377 by the \c info parameter (note that the any prior contents of the message 378 will be destroyed). Please see BMimeType::SetAttrInfo() for a description 379 of the expected format of such a message. 380 381 \param _info Reference to a pre-allocated BMessage into which information 382 about the MIME type's associated file attributes is stored. 383 384 \return A status code, \c B_OK on success or an error code on failure. 385 */ 386 status_t 387 DatabaseLocation::GetAttributesInfo(const char* type, BMessage& _info) 388 { 389 status_t result = ReadMessageAttribute(type, kAttrInfoAttr, _info); 390 391 if (result == B_ENTRY_NOT_FOUND) { 392 // return an empty message 393 _info.MakeEmpty(); 394 result = B_OK; 395 } 396 397 if (result == B_OK) { 398 _info.what = 233; 399 // Don't know why, but that's what R5 does. 400 result = _info.AddString("type", type); 401 } 402 403 return result; 404 } 405 406 407 /*! Fetches the short description for the given MIME type. 408 409 The string pointed to by \c description must be long enough to 410 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 411 recommended. 412 413 \param type The MIME type of interest 414 \param description Pointer to a pre-allocated string into which the short 415 description is copied. If the function fails, the contents of the 416 string are undefined. 417 418 \return A status code, \c B_OK on success or an error code on failure. 419 \retval B_OK Success. 420 \retval B_ENTRY_NOT_FOUND No short description exists for the given type. 421 */ 422 status_t 423 DatabaseLocation::GetShortDescription(const char* type, char* description) 424 { 425 ssize_t result = ReadAttribute(type, kShortDescriptionAttr, description, 426 B_MIME_TYPE_LENGTH, kShortDescriptionType); 427 428 return result >= 0 ? B_OK : result; 429 } 430 431 432 /*! Fetches the long description for the given MIME type. 433 434 The string pointed to by \c description must be long enough to 435 hold the long description; a length of \c B_MIME_TYPE_LENGTH is 436 recommended. 437 438 \param type The MIME type of interest 439 \param description Pointer to a pre-allocated string into which the long 440 description is copied. If the function fails, the contents of the 441 string are undefined. 442 443 \return A status code, \c B_OK on success or an error code on failure. 444 \retval B_OK Success. 445 \retval B_ENTRY_NOT_FOUND No long description exists for the given type 446 */ 447 status_t 448 DatabaseLocation::GetLongDescription(const char* type, char* description) 449 { 450 ssize_t result = ReadAttribute(type, kLongDescriptionAttr, description, 451 B_MIME_TYPE_LENGTH, kLongDescriptionType); 452 453 return result >= 0 ? B_OK : result; 454 } 455 456 457 /*! Fetches a BMessage describing the MIME type's associated filename 458 extensions. 459 460 The list of extensions is returned in a pre-allocated BMessage pointed to 461 by the \c extensions parameter (note that the any prior contents of the 462 message will be destroyed). Please see BMimeType::GetFileExtensions() for 463 a description of the message format. 464 465 \param extensions Reference to a pre-allocated BMessage into which the MIME 466 type's associated file extensions will be stored. 467 468 \return A status code, \c B_OK on success or an error code on failure. 469 */ 470 status_t 471 DatabaseLocation::GetFileExtensions(const char* type, BMessage& _extensions) 472 { 473 status_t result = ReadMessageAttribute(type, kFileExtensionsAttr, _extensions); 474 if (result == B_ENTRY_NOT_FOUND) { 475 // return an empty message 476 _extensions.MakeEmpty(); 477 result = B_OK; 478 } 479 480 if (result == B_OK) { 481 _extensions.what = 234; // Don't know why, but that's what R5 does. 482 result = _extensions.AddString("type", type); 483 } 484 485 return result; 486 } 487 488 489 /*! Fetches the icon of given size associated with the given MIME type. 490 491 The bitmap pointed to by \c icon must be of the proper size (\c 32x32 492 for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth 493 (\c B_CMAP8). 494 495 \param type The mime type 496 \param icon Reference to a pre-allocated bitmap of proper dimensions and 497 color depth 498 \param size The size icon you're interested in (\c B_LARGE_ICON or 499 \c B_MINI_ICON) 500 501 \return A status code. 502 */ 503 status_t 504 DatabaseLocation::GetIcon(const char* type, BBitmap& _icon, icon_size size) 505 { 506 return GetIconForType(type, NULL, _icon, size); 507 } 508 509 510 /*! Fetches the vector icon associated with the given MIME type. 511 512 \param type The mime type 513 \param _data Reference via which the allocated icon data is returned. You 514 need to free the buffer once you're done with it. 515 \param _size Reference via which the size of the icon data is returned. 516 517 \return A status code. 518 */ 519 status_t 520 DatabaseLocation::GetIcon(const char* type, uint8*& _data, size_t& _size) 521 { 522 return GetIconForType(type, NULL, _data, _size); 523 } 524 525 526 /*! Fetches the large or mini icon used by an application of this type 527 for files of the given type. 528 529 The type of the \c BMimeType object is not required to actually be a subtype 530 of \c "application/"; that is the intended use however, and calling 531 \c GetIconForType() on a non-application type will likely return 532 \c B_ENTRY_NOT_FOUND. 533 534 The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap 535 must be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini 536 icon. 537 538 \param type The MIME type 539 \param fileType Pointer to a pre-allocated string containing the MIME type 540 whose custom icon you wish to fetch. If NULL, works just like 541 GetIcon(). 542 \param icon Reference to a pre-allocated \c BBitmap of proper size and 543 colorspace into which the icon is copied. 544 \param icon_size Value that specifies which icon to return. Currently 545 \c B_LARGE_ICON and \c B_MINI_ICON are supported. 546 547 \return A status code, \c B_OK on success or an error code on failure. 548 \retval B_OK Success. 549 \retval B_ENTRY_NOT_FOUND No icon of the given size exists for the given type 550 */ 551 status_t 552 DatabaseLocation::GetIconForType(const char* type, const char* fileType, 553 BBitmap& _icon, icon_size which) 554 { 555 if (type == NULL) 556 return B_BAD_VALUE; 557 558 // open the node for the given type 559 BNode node; 560 status_t result = OpenType(type, node); 561 if (result != B_OK) 562 return result; 563 564 // construct our attribute name 565 BString vectorIconAttrName; 566 BString smallIconAttrName; 567 BString largeIconAttrName; 568 569 if (fileType != NULL) { 570 BString lowerCaseFileType(fileType); 571 lowerCaseFileType.ToLower(); 572 573 vectorIconAttrName << kIconAttrPrefix << lowerCaseFileType; 574 smallIconAttrName << kMiniIconAttrPrefix << lowerCaseFileType; 575 largeIconAttrName << kLargeIconAttrPrefix << lowerCaseFileType; 576 } else { 577 vectorIconAttrName = kIconAttr; 578 smallIconAttrName = kMiniIconAttr; 579 largeIconAttrName = kLargeIconAttr; 580 } 581 582 return BIconUtils::GetIcon(&node, vectorIconAttrName, smallIconAttrName, 583 largeIconAttrName, which, &_icon); 584 } 585 586 587 /*! Fetches the vector icon used by an application of this type for files 588 of the given type. 589 590 The type of the \c BMimeType object is not required to actually be a subtype 591 of \c "application/"; that is the intended use however, and calling 592 \c GetIconForType() on a non-application type will likely return 593 \c B_ENTRY_NOT_FOUND. 594 595 The icon data is allocated and returned in \a _data. 596 597 \param type The MIME type 598 \param fileType Reference to a pre-allocated string containing the MIME type 599 whose custom icon you wish to fetch. If NULL, works just like 600 GetIcon(). 601 \param _data Reference via which the icon data is returned on success. 602 \param _size Reference via which the size of the icon data is returned. 603 604 \return A status code, \c B_OK on success or another code on failure. 605 \retval B_OK Success. 606 \retval B_ENTRY_NOT_FOUND No vector icon existed for the given type. 607 */ 608 status_t 609 DatabaseLocation::GetIconForType(const char* type, const char* fileType, 610 uint8*& _data, size_t& _size) 611 { 612 if (type == NULL) 613 return B_BAD_VALUE; 614 615 // open the node for the given type 616 BNode node; 617 status_t result = OpenType(type, node); 618 if (result != B_OK) 619 return result; 620 621 // construct our attribute name 622 BString iconAttrName; 623 624 if (fileType != NULL) 625 iconAttrName << kIconAttrPrefix << BString(fileType).ToLower(); 626 else 627 iconAttrName = kIconAttr; 628 629 // get info about attribute for that name 630 attr_info info; 631 if (result == B_OK) 632 result = node.GetAttrInfo(iconAttrName, &info); 633 634 // validate attribute type 635 if (result == B_OK) 636 result = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE; 637 638 // allocate a buffer and read the attribute data into it 639 if (result == B_OK) { 640 uint8* buffer = new(std::nothrow) uint8[info.size]; 641 if (buffer == NULL) 642 result = B_NO_MEMORY; 643 644 ssize_t bytesRead = -1; 645 if (result == B_OK) { 646 bytesRead = node.ReadAttr(iconAttrName, B_VECTOR_ICON_TYPE, 0, buffer, 647 info.size); 648 } 649 650 if (bytesRead >= 0) 651 result = bytesRead == info.size ? B_OK : B_FILE_ERROR; 652 653 if (result == B_OK) { 654 // success, set data pointer and size 655 _data = buffer; 656 _size = info.size; 657 } else 658 delete[] buffer; 659 } 660 661 return result; 662 } 663 664 665 /*! Fetches signature of the MIME type's preferred application for the 666 given action. 667 668 The string pointed to by \c signature must be long enough to 669 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 670 recommended. 671 672 Currently, the only supported app verb is \c B_OPEN. 673 674 \param type The MIME type of interest 675 \param description Pointer to a pre-allocated string into which the 676 preferred application's signature is copied. If the function fails, 677 the contents of the string are undefined. 678 \param verb \c The action of interest 679 680 \return A status code, \c B_OK on success or another code on failure. 681 \retval B_OK Success. 682 \retval B_ENTRY_NOT_FOUND No such preferred application exists 683 */ 684 status_t 685 DatabaseLocation::GetPreferredApp(const char* type, char* signature, 686 app_verb verb) 687 { 688 // Since B_OPEN is the currently the only app_verb, it is essentially 689 // ignored 690 ssize_t result = ReadAttribute(type, kPreferredAppAttr, signature, 691 B_MIME_TYPE_LENGTH, kPreferredAppType); 692 693 return result >= 0 ? B_OK : result; 694 } 695 696 697 /*! Fetches the sniffer rule for the given MIME type. 698 \param type The MIME type of interest 699 \param _result Pointer to a pre-allocated BString into which the type's 700 sniffer rule is copied. 701 702 \return A status code, \c B_OK on success or another code on failure. 703 \retval B_OK Success. 704 \retval B_ENTRY_NOT_FOUND No such preferred application exists. 705 */ 706 status_t 707 DatabaseLocation::GetSnifferRule(const char* type, BString& _result) 708 { 709 return ReadStringAttribute(type, kSnifferRuleAttr, _result); 710 } 711 712 713 status_t 714 DatabaseLocation::GetSupportedTypes(const char* type, BMessage& _types) 715 { 716 status_t result = ReadMessageAttribute(type, kSupportedTypesAttr, _types); 717 if (result == B_ENTRY_NOT_FOUND) { 718 // return an empty message 719 _types.MakeEmpty(); 720 result = B_OK; 721 } 722 if (result == B_OK) { 723 _types.what = 0; 724 result = _types.AddString("type", type); 725 } 726 727 return result; 728 } 729 730 731 //! Checks if the given MIME type is present in the database 732 bool 733 DatabaseLocation::IsInstalled(const char* type) 734 { 735 BNode node; 736 return OpenType(type, node) == B_OK; 737 } 738 739 740 BString 741 DatabaseLocation::_TypeToFilename(const char* type, int32 index) const 742 { 743 BString path = fDirectories.StringAt(index); 744 return path << '/' << BString(type).ToLower(); 745 } 746 747 748 status_t 749 DatabaseLocation::_OpenType(const char* type, BNode& _node, int32& _index) const 750 { 751 int32 count = fDirectories.CountStrings(); 752 for (int32 i = 0; i < count; i++) { 753 status_t result = _node.SetTo(_TypeToFilename(type, i)); 754 attr_info attrInfo; 755 if (result == B_OK && _node.GetAttrInfo(kTypeAttr, &attrInfo) == B_OK) { 756 _index = i; 757 return B_OK; 758 } 759 } 760 761 return B_ENTRY_NOT_FOUND; 762 } 763 764 765 status_t 766 DatabaseLocation::_CreateTypeNode(const char* type, BNode& _node) const 767 { 768 const char* slash = strchr(type, '/'); 769 BString superTypeName; 770 if (slash != NULL) 771 superTypeName.SetTo(type, slash - type); 772 else 773 superTypeName = type; 774 superTypeName.ToLower(); 775 776 // open/create the directory for the supertype 777 BDirectory parent(WritableDirectory()); 778 status_t result = parent.InitCheck(); 779 if (result != B_OK) 780 return result; 781 782 BDirectory superTypeDirectory; 783 if (BEntry(&parent, superTypeName).Exists()) 784 result = superTypeDirectory.SetTo(&parent, superTypeName); 785 else 786 result = parent.CreateDirectory(superTypeName, &superTypeDirectory); 787 788 if (result != B_OK) 789 return result; 790 791 // create the subtype 792 BFile subTypeFile; 793 if (slash != NULL) { 794 result = superTypeDirectory.CreateFile(BString(slash + 1).ToLower(), 795 &subTypeFile); 796 if (result != B_OK) 797 return result; 798 } 799 800 // assign the result 801 if (slash != NULL) 802 _node = subTypeFile; 803 else 804 _node = superTypeDirectory; 805 return _node.InitCheck(); 806 } 807 808 809 status_t 810 DatabaseLocation::_CopyTypeNode(BNode& source, const char* type, BNode& _target) 811 const 812 { 813 status_t result = _CreateTypeNode(type, _target); 814 if (result != B_OK) 815 return result; 816 817 // copy the attributes 818 MemoryDeleter bufferDeleter; 819 size_t bufferSize = 0; 820 821 source.RewindAttrs(); 822 char attribute[B_ATTR_NAME_LENGTH]; 823 while (source.GetNextAttrName(attribute) == B_OK) { 824 attr_info info; 825 result = source.GetAttrInfo(attribute, &info); 826 if (result != B_OK) { 827 syslog(LOG_ERR, "Failed to get info for attribute \"%s\" of MIME " 828 "type \"%s\": %s", attribute, type, strerror(result)); 829 continue; 830 } 831 832 // resize our buffer, if necessary 833 if (info.size > (off_t)bufferSize) { 834 bufferDeleter.SetTo(malloc(info.size)); 835 if (!bufferDeleter.IsSet()) 836 return B_NO_MEMORY; 837 bufferSize = info.size; 838 } 839 840 ssize_t bytesRead = source.ReadAttr(attribute, info.type, 0, 841 bufferDeleter.Get(), info.size); 842 if (bytesRead != info.size) { 843 syslog(LOG_ERR, "Failed to read attribute \"%s\" of MIME " 844 "type \"%s\": %s", attribute, type, 845 bytesRead < 0 ? strerror(bytesRead) : "short read"); 846 continue; 847 } 848 849 ssize_t bytesWritten = _target.WriteAttr(attribute, info.type, 0, 850 bufferDeleter.Get(), info.size); 851 if (bytesWritten < 0) { 852 syslog(LOG_ERR, "Failed to write attribute \"%s\" of MIME " 853 "type \"%s\": %s", attribute, type, 854 bytesWritten < 0 ? strerror(bytesWritten) : "short write"); 855 continue; 856 } 857 } 858 859 return B_OK; 860 } 861 862 863 } // namespace Mime 864 } // namespace Storage 865 } // namespace BPrivate 866