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