1 // Volume.cpp 2 // 3 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // You can alternatively use *this file* under the terms of the the MIT 20 // license included in this package. 21 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "Block.h" 30 #include "BlockAllocator.h" 31 #include "Debug.h" 32 #include "Directory.h" 33 #include "Entry.h" 34 #include "EntryListener.h" 35 #include "IndexDirectory.h" 36 #include "Locking.h" 37 #include "Misc.h" 38 #include "NameIndex.h" 39 #include "Node.h" 40 #include "NodeChildTable.h" 41 #include "NodeListener.h" 42 #include "NodeTable.h" 43 #include "TwoKeyAVLTree.h" 44 #include "Volume.h" 45 46 // default block size 47 static const off_t kDefaultBlockSize = 4096; 48 49 static const size_t kDefaultAreaSize = kDefaultBlockSize * 128; 50 51 // default volume name 52 static const char *kDefaultVolumeName = "RAM FS"; 53 54 // NodeListenerGetPrimaryKey 55 class NodeListenerGetPrimaryKey { 56 public: 57 inline Node *operator()(const NodeListenerValue &a) 58 { 59 return a.node; 60 } 61 62 inline Node *operator()(const NodeListenerValue &a) const 63 { 64 return a.node; 65 } 66 }; 67 68 // NodeListenerGetSecondaryKey 69 class NodeListenerGetSecondaryKey { 70 public: 71 inline NodeListener *operator()(const NodeListenerValue &a) 72 { 73 return a.listener; 74 } 75 76 inline NodeListener *operator()(const NodeListenerValue &a) const 77 { 78 return a.listener; 79 } 80 }; 81 82 // NodeListenerTree 83 typedef TwoKeyAVLTree<NodeListenerValue, Node*, 84 TwoKeyAVLTreeStandardCompare<Node*>, 85 NodeListenerGetPrimaryKey, NodeListener*, 86 TwoKeyAVLTreeStandardCompare<NodeListener*>, 87 NodeListenerGetSecondaryKey > _NodeListenerTree; 88 class NodeListenerTree : public _NodeListenerTree {}; 89 90 // EntryListenerGetPrimaryKey 91 class EntryListenerGetPrimaryKey { 92 public: 93 inline Entry *operator()(const EntryListenerValue &a) 94 { 95 return a.entry; 96 } 97 98 inline Entry *operator()(const EntryListenerValue &a) const 99 { 100 return a.entry; 101 } 102 }; 103 104 // EntryListenerGetSecondaryKey 105 class EntryListenerGetSecondaryKey { 106 public: 107 inline EntryListener *operator()(const EntryListenerValue &a) 108 { 109 return a.listener; 110 } 111 112 inline EntryListener *operator()(const EntryListenerValue &a) const 113 { 114 return a.listener; 115 } 116 }; 117 118 // EntryListenerTree 119 typedef TwoKeyAVLTree<EntryListenerValue, Entry*, 120 TwoKeyAVLTreeStandardCompare<Entry*>, 121 EntryListenerGetPrimaryKey, EntryListener*, 122 TwoKeyAVLTreeStandardCompare<EntryListener*>, 123 EntryListenerGetSecondaryKey > _EntryListenerTree; 124 class EntryListenerTree : public _EntryListenerTree {}; 125 126 127 /*! 128 \class Volume 129 \brief Represents a volume. 130 */ 131 132 // constructor 133 Volume::Volume() 134 : fID(0), 135 fNextNodeID(kRootParentID + 1), 136 fNodeTable(NULL), 137 fDirectoryEntryTable(NULL), 138 fNodeAttributeTable(NULL), 139 fIndexDirectory(NULL), 140 fRootDirectory(NULL), 141 fName(kDefaultVolumeName), 142 fLocker("volume"), 143 fIteratorLocker("iterators"), 144 fQueryLocker("queries"), 145 fNodeListeners(NULL), 146 fAnyNodeListeners(), 147 fEntryListeners(NULL), 148 fAnyEntryListeners(), 149 fBlockAllocator(NULL), 150 fBlockSize(kDefaultBlockSize), 151 fAllocatedBlocks(0), 152 fAccessTime(0), 153 fMounted(false) 154 { 155 } 156 157 // destructor 158 Volume::~Volume() 159 { 160 Unmount(); 161 } 162 163 // Mount 164 status_t 165 Volume::Mount(dev_t id) 166 { 167 Unmount(); 168 169 // check the locker's semaphores 170 if (fLocker.Sem() < 0) 171 return fLocker.Sem(); 172 if (fIteratorLocker.Sem() < 0) 173 return fIteratorLocker.Sem(); 174 if (fQueryLocker.Sem() < 0) 175 return fQueryLocker.Sem(); 176 177 status_t error = B_OK; 178 fID = id; 179 // create a block allocator 180 if (error == B_OK) { 181 fBlockAllocator = new(nothrow) BlockAllocator(kDefaultAreaSize); 182 if (fBlockAllocator) 183 error = fBlockAllocator->InitCheck(); 184 else 185 SET_ERROR(error, B_NO_MEMORY); 186 } 187 // create the listener trees 188 if (error == B_OK) { 189 fNodeListeners = new(nothrow) NodeListenerTree; 190 if (!fNodeListeners) 191 error = B_NO_MEMORY; 192 } 193 if (error == B_OK) { 194 fEntryListeners = new(nothrow) EntryListenerTree; 195 if (!fEntryListeners) 196 error = B_NO_MEMORY; 197 } 198 // create the node table 199 if (error == B_OK) { 200 fNodeTable = new(nothrow) NodeTable; 201 if (fNodeTable) 202 error = fNodeTable->InitCheck(); 203 else 204 SET_ERROR(error, B_NO_MEMORY); 205 } 206 // create the directory entry table 207 if (error == B_OK) { 208 fDirectoryEntryTable = new(nothrow) DirectoryEntryTable; 209 if (fDirectoryEntryTable) 210 error = fDirectoryEntryTable->InitCheck(); 211 else 212 SET_ERROR(error, B_NO_MEMORY); 213 } 214 // create the node attribute table 215 if (error == B_OK) { 216 fNodeAttributeTable = new(nothrow) NodeAttributeTable; 217 if (fNodeAttributeTable) 218 error = fNodeAttributeTable->InitCheck(); 219 else 220 SET_ERROR(error, B_NO_MEMORY); 221 } 222 // create the index directory 223 if (error == B_OK) { 224 fIndexDirectory = new(nothrow) IndexDirectory(this); 225 if (!fIndexDirectory) 226 SET_ERROR(error, B_NO_MEMORY); 227 } 228 // create the root dir 229 if (error == B_OK) { 230 fRootDirectory = new(nothrow) Directory(this); 231 if (fRootDirectory) { 232 // set permissions: -rwxr-xr-x 233 fRootDirectory->SetMode( 234 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 235 error = fRootDirectory->Link(NULL); 236 } else 237 SET_ERROR(error, B_NO_MEMORY); 238 } 239 // set mounted flag / cleanup on error 240 if (error == B_OK) 241 fMounted = true; 242 else 243 Unmount(); 244 RETURN_ERROR(error); 245 } 246 247 // Unmount 248 status_t 249 Volume::Unmount() 250 { 251 fMounted = false; 252 // delete the root directory 253 if (fRootDirectory) { 254 // deleting the root directory destroys the complete hierarchy 255 delete fRootDirectory; 256 fRootDirectory = NULL; 257 } 258 // delete the index directory 259 if (fIndexDirectory) { 260 delete fIndexDirectory; 261 fIndexDirectory = NULL; 262 } 263 // delete the listener trees 264 if (fEntryListeners) { 265 delete fEntryListeners; 266 fEntryListeners = NULL; 267 } 268 if (fNodeListeners) { 269 delete fNodeListeners; 270 fNodeListeners = NULL; 271 } 272 // delete the tables 273 if (fNodeAttributeTable) { 274 delete fNodeAttributeTable; 275 fNodeAttributeTable = NULL; 276 } 277 if (fDirectoryEntryTable) { 278 delete fDirectoryEntryTable; 279 fDirectoryEntryTable = NULL; 280 } 281 if (fNodeTable) { 282 delete fNodeTable; 283 fNodeTable = NULL; 284 } 285 // delete the block allocator 286 if (fBlockAllocator) { 287 delete fBlockAllocator; 288 fBlockAllocator = NULL; 289 } 290 fID = 0; 291 return B_OK; 292 } 293 294 // GetBlockSize 295 off_t 296 Volume::GetBlockSize() const 297 { 298 return fBlockSize; 299 } 300 301 // CountBlocks 302 off_t 303 Volume::CountBlocks() const 304 { 305 size_t bytes = 0; 306 system_info sysInfo; 307 if (get_system_info(&sysInfo) == B_OK) { 308 int32 freePages = sysInfo.max_pages - sysInfo.used_pages; 309 bytes = (uint32)freePages * B_PAGE_SIZE 310 + fBlockAllocator->GetAvailableBytes(); 311 } 312 return bytes / kDefaultBlockSize; 313 } 314 315 // CountFreeBlocks 316 off_t 317 Volume::CountFreeBlocks() const 318 { 319 // TODO:... 320 return CountBlocks() - fBlockAllocator->GetUsedBytes() / kDefaultBlockSize; 321 } 322 323 // SetName 324 status_t 325 Volume::SetName(const char *name) 326 { 327 status_t error = (name ? B_OK : B_BAD_VALUE); 328 if (error == B_OK) { 329 if (!fName.SetTo(name)) 330 SET_ERROR(error, B_NO_MEMORY); 331 } 332 return error; 333 } 334 335 // GetName 336 const char * 337 Volume::GetName() const 338 { 339 return fName.GetString(); 340 } 341 342 // NewVNode 343 status_t 344 Volume::NewVNode(Node *node) 345 { 346 status_t error = NodeAdded(node); 347 if (error == B_OK) { 348 error = new_vnode(GetID(), node->GetID(), node); 349 if (error != B_OK) 350 NodeRemoved(node); 351 } 352 return error; 353 } 354 355 // PublishVNode 356 status_t 357 Volume::PublishVNode(Node *node) 358 { 359 status_t error = NodeAdded(node); 360 if (error == B_OK) { 361 error = publish_vnode(GetID(), node->GetID(), node); 362 if (error != B_OK) 363 NodeRemoved(node); 364 } 365 return error; 366 } 367 368 // GetVNode 369 status_t 370 Volume::GetVNode(ino_t id, Node **node) 371 { 372 return (fMounted ? get_vnode(GetID(), id, (void**)node) : B_BAD_VALUE); 373 } 374 375 // GetVNode 376 status_t 377 Volume::GetVNode(Node *node) 378 { 379 Node *dummy = NULL; 380 status_t error = (fMounted ? GetVNode(node->GetID(), &dummy) 381 : B_BAD_VALUE ); 382 if (error == B_OK && dummy != node) { 383 FATAL(("Two Nodes have the same ID: %Ld!\n", node->GetID())); 384 PutVNode(dummy); 385 error = B_ERROR; 386 } 387 return error; 388 } 389 390 // PutVNode 391 status_t 392 Volume::PutVNode(ino_t id) 393 { 394 return (fMounted ? put_vnode(GetID(), id) : B_BAD_VALUE); 395 } 396 397 // PutVNode 398 status_t 399 Volume::PutVNode(Node *node) 400 { 401 return (fMounted ? put_vnode(GetID(), node->GetID()) : B_BAD_VALUE); 402 } 403 404 // RemoveVNode 405 status_t 406 Volume::RemoveVNode(Node *node) 407 { 408 if (fMounted) 409 return remove_vnode(GetID(), node->GetID()); 410 status_t error = NodeRemoved(node); 411 if (error == B_OK) 412 delete node; 413 return error; 414 } 415 416 // UnremoveVNode 417 status_t 418 Volume::UnremoveVNode(Node *node) 419 { 420 return (fMounted ? unremove_vnode(GetID(), node->GetID()) : B_BAD_VALUE); 421 } 422 423 // NodeAdded 424 status_t 425 Volume::NodeAdded(Node *node) 426 { 427 status_t error = (node ? B_OK : B_BAD_VALUE); 428 if (error == B_OK) { 429 error = fNodeTable->AddNode(node); 430 // notify listeners 431 if (error == B_OK) { 432 // listeners interested in that node 433 NodeListenerTree::Iterator it; 434 if (fNodeListeners->FindFirst(node, &it)) { 435 for (NodeListenerValue *value = it.GetCurrent(); 436 value && value->node == node; 437 value = it.GetNext()) { 438 if (value->flags & NODE_LISTEN_ADDED) 439 value->listener->NodeAdded(node); 440 } 441 } 442 // listeners interested in any node 443 int32 count = fAnyNodeListeners.CountItems(); 444 for (int32 i = 0; i < count; i++) { 445 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 446 if (value.flags & NODE_LISTEN_ADDED) 447 value.listener->NodeAdded(node); 448 } 449 } 450 } 451 return error; 452 } 453 454 // NodeRemoved 455 status_t 456 Volume::NodeRemoved(Node *node) 457 { 458 status_t error = (node ? B_OK : B_BAD_VALUE); 459 if (error == B_OK) { 460 error = fNodeTable->RemoveNode(node); 461 // notify listeners 462 if (error == B_OK) { 463 // listeners interested in that node 464 NodeListenerTree::Iterator it; 465 if (fNodeListeners->FindFirst(node, &it)) { 466 for (NodeListenerValue *value = it.GetCurrent(); 467 value && value->node == node; 468 value = it.GetNext()) { 469 if (value->flags & NODE_LISTEN_REMOVED) 470 value->listener->NodeRemoved(node); 471 } 472 } 473 // listeners interested in any node 474 int32 count = fAnyNodeListeners.CountItems(); 475 for (int32 i = 0; i < count; i++) { 476 const NodeListenerValue &value = fAnyNodeListeners.ItemAt(i); 477 if (value.flags & NODE_LISTEN_REMOVED) 478 value.listener->NodeRemoved(node); 479 } 480 } 481 } 482 return error; 483 } 484 485 // FindNode 486 /*! \brief Finds the node identified by a ino_t. 487 488 \note The method does not initialize the parent ID for non-directory nodes. 489 490 \param id ID of the node to be found. 491 \param node pointer to a pre-allocated Node* to be set to the found node. 492 \return \c B_OK, if everything went fine. 493 */ 494 status_t 495 Volume::FindNode(ino_t id, Node **node) 496 { 497 status_t error = (node ? B_OK : B_BAD_VALUE); 498 if (error == B_OK) { 499 *node = fNodeTable->GetNode(id); 500 if (!*node) 501 error = B_ENTRY_NOT_FOUND; 502 } 503 return error; 504 } 505 506 // AddNodeListener 507 status_t 508 Volume::AddNodeListener(NodeListener *listener, Node *node, uint32 flags) 509 { 510 // check parameters 511 if (!listener || !node && !(flags & NODE_LISTEN_ANY_NODE) 512 || !(flags & NODE_LISTEN_ALL)) { 513 return B_BAD_VALUE; 514 } 515 // add the listener to the right container 516 status_t error = B_OK; 517 NodeListenerValue value(listener, node, flags); 518 if (flags & NODE_LISTEN_ANY_NODE) { 519 if (!fAnyNodeListeners.AddItem(value)) 520 error = B_NO_MEMORY; 521 } else 522 error = fNodeListeners->Insert(value); 523 return error; 524 } 525 526 // RemoveNodeListener 527 status_t 528 Volume::RemoveNodeListener(NodeListener *listener, Node *node) 529 { 530 if (!listener) 531 return B_BAD_VALUE; 532 status_t error = B_OK; 533 if (node) 534 error = fNodeListeners->Remove(node, listener); 535 else { 536 NodeListenerValue value(listener, node, 0); 537 if (!fAnyNodeListeners.RemoveItem(value)) 538 error = B_ENTRY_NOT_FOUND; 539 } 540 return error; 541 } 542 543 // EntryAdded 544 status_t 545 Volume::EntryAdded(ino_t id, Entry *entry) 546 { 547 status_t error = (entry ? B_OK : B_BAD_VALUE); 548 if (error == B_OK) { 549 error = fDirectoryEntryTable->AddNodeChild(id, entry); 550 if (error == B_OK) { 551 // notify listeners 552 // listeners interested in that entry 553 EntryListenerTree::Iterator it; 554 if (fEntryListeners->FindFirst(entry, &it)) { 555 for (EntryListenerValue *value = it.GetCurrent(); 556 value && value->entry == entry; 557 value = it.GetNext()) { 558 if (value->flags & ENTRY_LISTEN_ADDED) 559 value->listener->EntryAdded(entry); 560 } 561 } 562 // listeners interested in any entry 563 int32 count = fAnyEntryListeners.CountItems(); 564 for (int32 i = 0; i < count; i++) { 565 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 566 if (value.flags & ENTRY_LISTEN_ADDED) 567 value.listener->EntryAdded(entry); 568 } 569 } 570 } 571 return error; 572 } 573 574 // EntryRemoved 575 status_t 576 Volume::EntryRemoved(ino_t id, Entry *entry) 577 { 578 status_t error = (entry ? B_OK : B_BAD_VALUE); 579 if (error == B_OK) { 580 error = fDirectoryEntryTable->RemoveNodeChild(id, entry); 581 if (error == B_OK) { 582 // notify listeners 583 // listeners interested in that entry 584 EntryListenerTree::Iterator it; 585 if (fEntryListeners->FindFirst(entry, &it)) { 586 for (EntryListenerValue *value = it.GetCurrent(); 587 value && value->entry == entry; 588 value = it.GetNext()) { 589 if (value->flags & ENTRY_LISTEN_REMOVED) 590 value->listener->EntryRemoved(entry); 591 } 592 } 593 // listeners interested in any entry 594 int32 count = fAnyEntryListeners.CountItems(); 595 for (int32 i = 0; i < count; i++) { 596 const EntryListenerValue &value = fAnyEntryListeners.ItemAt(i); 597 if (value.flags & ENTRY_LISTEN_REMOVED) 598 value.listener->EntryRemoved(entry); 599 } 600 } 601 } 602 return error; 603 } 604 605 // FindEntry 606 status_t 607 Volume::FindEntry(ino_t id, const char *name, Entry **entry) 608 { 609 status_t error = (entry ? B_OK : B_BAD_VALUE); 610 if (error == B_OK) { 611 *entry = fDirectoryEntryTable->GetNodeChild(id, name); 612 if (!*entry) 613 error = B_ENTRY_NOT_FOUND; 614 } 615 return error; 616 } 617 618 // AddEntryListener 619 status_t 620 Volume::AddEntryListener(EntryListener *listener, Entry *entry, uint32 flags) 621 { 622 // check parameters 623 if (!listener || !entry && !(flags & ENTRY_LISTEN_ANY_ENTRY) 624 || !(flags & ENTRY_LISTEN_ALL)) { 625 return B_BAD_VALUE; 626 } 627 // add the listener to the right container 628 status_t error = B_OK; 629 EntryListenerValue value(listener, entry, flags); 630 if (flags & ENTRY_LISTEN_ANY_ENTRY) { 631 if (!fAnyEntryListeners.AddItem(value)) 632 error = B_NO_MEMORY; 633 } else 634 error = fEntryListeners->Insert(value); 635 return error; 636 } 637 638 // RemoveEntryListener 639 status_t 640 Volume::RemoveEntryListener(EntryListener *listener, Entry *entry) 641 { 642 if (!listener) 643 return B_BAD_VALUE; 644 status_t error = B_OK; 645 if (entry) 646 error = fEntryListeners->Remove(entry, listener); 647 else { 648 EntryListenerValue value(listener, entry, 0); 649 if (!fAnyEntryListeners.RemoveItem(value)) 650 error = B_ENTRY_NOT_FOUND; 651 } 652 return error; 653 } 654 655 // NodeAttributeAdded 656 status_t 657 Volume::NodeAttributeAdded(ino_t id, Attribute *attribute) 658 { 659 status_t error = (attribute ? B_OK : B_BAD_VALUE); 660 if (error == B_OK) { 661 error = fNodeAttributeTable->AddNodeChild(id, attribute); 662 // notify the respective attribute index 663 if (error == B_OK) { 664 if (AttributeIndex *index = FindAttributeIndex( 665 attribute->GetName(), attribute->GetType())) { 666 index->Added(attribute); 667 } 668 } 669 } 670 return error; 671 } 672 673 // NodeAttributeRemoved 674 status_t 675 Volume::NodeAttributeRemoved(ino_t id, Attribute *attribute) 676 { 677 status_t error = (attribute ? B_OK : B_BAD_VALUE); 678 if (error == B_OK) { 679 error = fNodeAttributeTable->RemoveNodeChild(id, attribute); 680 // notify the respective attribute index 681 if (error == B_OK) { 682 if (AttributeIndex *index = FindAttributeIndex( 683 attribute->GetName(), attribute->GetType())) { 684 index->Removed(attribute); 685 } 686 } 687 688 // update live queries 689 if (error == B_OK && attribute->GetNode()) { 690 const uint8* oldKey; 691 size_t oldLength; 692 attribute->GetKey(&oldKey, &oldLength); 693 UpdateLiveQueries(NULL, attribute->GetNode(), attribute->GetName(), 694 attribute->GetType(), oldKey, oldLength, NULL, 0); 695 } 696 } 697 return error; 698 } 699 700 // FindNodeAttribute 701 status_t 702 Volume::FindNodeAttribute(ino_t id, const char *name, Attribute **attribute) 703 { 704 status_t error = (attribute ? B_OK : B_BAD_VALUE); 705 if (error == B_OK) { 706 *attribute = fNodeAttributeTable->GetNodeChild(id, name); 707 if (!*attribute) 708 error = B_ENTRY_NOT_FOUND; 709 } 710 return error; 711 } 712 713 // GetNameIndex 714 NameIndex * 715 Volume::GetNameIndex() const 716 { 717 return (fIndexDirectory ? fIndexDirectory->GetNameIndex() : NULL); 718 } 719 720 // GetLastModifiedIndex 721 LastModifiedIndex * 722 Volume::GetLastModifiedIndex() const 723 { 724 return (fIndexDirectory ? fIndexDirectory->GetLastModifiedIndex() : NULL); 725 } 726 727 // GetSizeIndex 728 SizeIndex * 729 Volume::GetSizeIndex() const 730 { 731 return (fIndexDirectory ? fIndexDirectory->GetSizeIndex() : NULL); 732 } 733 734 // FindIndex 735 Index * 736 Volume::FindIndex(const char *name) 737 { 738 return (fIndexDirectory ? fIndexDirectory->FindIndex(name) : NULL); 739 } 740 741 // FindAttributeIndex 742 AttributeIndex * 743 Volume::FindAttributeIndex(const char *name, uint32 type) 744 { 745 return (fIndexDirectory 746 ? fIndexDirectory->FindAttributeIndex(name, type) : NULL); 747 } 748 749 // AddQuery 750 void 751 Volume::AddQuery(Query *query) 752 { 753 AutoLocker<Locker> _(fQueryLocker); 754 755 if (query) 756 fQueries.Insert(query); 757 } 758 759 // RemoveQuery 760 void 761 Volume::RemoveQuery(Query *query) 762 { 763 AutoLocker<Locker> _(fQueryLocker); 764 765 if (query) 766 fQueries.Remove(query); 767 } 768 769 // UpdateLiveQueries 770 void 771 Volume::UpdateLiveQueries(Entry *entry, Node* node, const char *attribute, 772 int32 type, const uint8 *oldKey, size_t oldLength, const uint8 *newKey, 773 size_t newLength) 774 { 775 AutoLocker<Locker> _(fQueryLocker); 776 777 for (Query* query = fQueries.First(); 778 query; 779 query = fQueries.GetNext(query)) { 780 query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength, 781 newKey, newLength); 782 } 783 } 784 785 // AllocateBlock 786 status_t 787 Volume::AllocateBlock(size_t size, BlockReference **block) 788 { 789 status_t error = (size > 0 && size <= fBlockSize && block 790 ? B_OK : B_BAD_VALUE); 791 if (error == B_OK) { 792 *block = fBlockAllocator->AllocateBlock(size); 793 if (*block) 794 fAllocatedBlocks++; 795 else 796 SET_ERROR(error, B_NO_MEMORY); 797 } 798 return error; 799 } 800 801 // FreeBlock 802 void 803 Volume::FreeBlock(BlockReference *block) 804 { 805 if (block) { 806 fBlockAllocator->FreeBlock(block); 807 fAllocatedBlocks--; 808 } 809 } 810 811 // ResizeBlock 812 BlockReference * 813 Volume::ResizeBlock(BlockReference *block, size_t size) 814 { 815 BlockReference *newBlock = NULL; 816 if (size <= fBlockSize && block) { 817 if (size == 0) { 818 fBlockAllocator->FreeBlock(block); 819 fAllocatedBlocks--; 820 } else 821 newBlock = fBlockAllocator->ResizeBlock(block, size); 822 } 823 return newBlock; 824 } 825 826 // CheckBlock 827 bool 828 Volume::CheckBlock(BlockReference *block, size_t size) 829 { 830 return fBlockAllocator->CheckBlock(block, size); 831 } 832 833 // GetAllocationInfo 834 void 835 Volume::GetAllocationInfo(AllocationInfo &info) 836 { 837 // tables 838 info.AddOtherAllocation(sizeof(NodeTable)); 839 fNodeTable->GetAllocationInfo(info); 840 info.AddOtherAllocation(sizeof(DirectoryEntryTable)); 841 fDirectoryEntryTable->GetAllocationInfo(info); 842 info.AddOtherAllocation(sizeof(NodeAttributeTable)); 843 fNodeAttributeTable->GetAllocationInfo(info); 844 // node hierarchy 845 fRootDirectory->GetAllocationInfo(info); 846 // name 847 info.AddStringAllocation(fName.GetLength()); 848 // block allocator 849 info.AddOtherAllocation(sizeof(BlockAllocator)); 850 fBlockAllocator->GetAllocationInfo(info); 851 } 852 853 // ReadLock 854 bool 855 Volume::ReadLock() 856 { 857 bool alreadyLocked = fLocker.IsLocked(); 858 if (fLocker.Lock()) { 859 if (!alreadyLocked) 860 fAccessTime = system_time(); 861 return true; 862 } 863 return false; 864 } 865 866 // ReadUnlock 867 void 868 Volume::ReadUnlock() 869 { 870 fLocker.Unlock(); 871 } 872 873 // WriteLock 874 bool 875 Volume::WriteLock() 876 { 877 bool alreadyLocked = fLocker.IsLocked(); 878 if (fLocker.Lock()) { 879 if (!alreadyLocked) 880 fAccessTime = system_time(); 881 return true; 882 } 883 return false; 884 } 885 886 // WriteUnlock 887 void 888 Volume::WriteUnlock() 889 { 890 fLocker.Unlock(); 891 } 892 893 // IteratorLock 894 bool 895 Volume::IteratorLock() 896 { 897 return fIteratorLocker.Lock(); 898 } 899 900 // IteratorUnlock 901 void 902 Volume::IteratorUnlock() 903 { 904 fIteratorLocker.Unlock(); 905 } 906 907