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