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