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