xref: /haiku/src/add-ons/kernel/file_systems/ramfs/Volume.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
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