xref: /haiku/src/kits/tracker/VirtualDirectoryManager.cpp (revision 32832cbe47f991cc6d2b29824903181d8baaaa63)
1 /*
2  * Copyright 2013 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, ingo_weinhold@gmx.de
7  */
8 
9 
10 #include "VirtualDirectoryManager.h"
11 
12 #include <errno.h>
13 
14 #include <new>
15 
16 #include <Directory.h>
17 #include <File.h>
18 #include <StringList.h>
19 
20 #include <AutoDeleter.h>
21 #include <AutoLocker.h>
22 #include <DriverSettings.h>
23 #include <NotOwningEntryRef.h>
24 #include <Uuid.h>
25 
26 #include "MimeTypes.h"
27 #include "Model.h"
28 
29 
30 namespace BPrivate {
31 
32 static const size_t kMaxVirtualDirectoryFileSize = 10 * 1024;
33 static const char* const kTemporaryDefinitionFileBaseDirectoryPath
34 	= "/tmp/tracker/virtual-directories";
35 
36 
37 // #pragma mark - VirtualDirectoryManager::Info
38 
39 
40 class VirtualDirectoryManager::Info {
41 private:
42 	typedef BObjectList<Info> InfoList;
43 
44 public:
45 	Info(RootInfo* root, Info* parent, const BString& path,
46 		const node_ref& definitionFileNodeRef,
47 		const entry_ref& definitionFileEntryRef)
48 		:
49 		fRoot(root),
50 		fParent(parent),
51 		fPath(path),
52 		fDefinitionFileNodeRef(definitionFileNodeRef),
53 		fDefinitionFileEntryRef(definitionFileEntryRef),
54 		fId(),
55 		fChildDefinitionsDirectoryRef(-1, -1),
56 		fChildren(10, true)
57 	{
58 	}
59 
60 	~Info()
61 	{
62 	}
63 
64 	RootInfo* Root() const
65 	{
66 		return fRoot;
67 	}
68 
69 	Info* Parent() const
70 	{
71 		return fParent;
72 	}
73 
74 	const char* Name() const
75 	{
76 		return fDefinitionFileEntryRef.name;
77 	}
78 
79 	const BString& Path() const
80 	{
81 		return fPath;
82 	}
83 
84 	const node_ref& DefinitionFileNodeRef() const
85 	{
86 		return fDefinitionFileNodeRef;
87 	}
88 
89 	const entry_ref& DefinitionFileEntryRef() const
90 	{
91 		return fDefinitionFileEntryRef;
92 	}
93 
94 	const InfoList& Children() const
95 	{
96 		return fChildren;
97 	}
98 
99 	const BString& Id() const
100 	{
101 		return fId;
102 	}
103 
104 	void SetId(const BString& id)
105 	{
106 		fId = id;
107 	}
108 
109 	const node_ref& ChildDefinitionsDirectoryRef() const
110 	{
111 		return fChildDefinitionsDirectoryRef;
112 	}
113 
114 	void SetChildDefinitionsDirectoryRef(const node_ref& ref)
115 	{
116 		fChildDefinitionsDirectoryRef = ref;
117 	}
118 
119 	Info* GetChild(const char* name) const
120 	{
121 		for (int32 i = 0; Info* child = fChildren.ItemAt(i); i++) {
122 			if (strcmp(name, child->Name()) == 0)
123 				return child;
124 		}
125 		return NULL;
126 	}
127 
128 	Info* CreateChild(const node_ref& definitionFileNodeRef,
129 		const entry_ref& definitionFileEntryRef)
130 	{
131 		BString path;
132 		if (fPath.IsEmpty()) {
133 			path = definitionFileEntryRef.name;
134 		} else {
135 			path.SetToFormat("%s/%s", fPath.String(),
136 				definitionFileEntryRef.name);
137 		}
138 		if (path.IsEmpty())
139 			return NULL;
140 
141 		Info* info = new(std::nothrow) Info(fRoot, this, path,
142 			definitionFileNodeRef, definitionFileEntryRef);
143 		if (info == NULL || !fChildren.AddItem(info)) {
144 			delete info;
145 			return NULL;
146 		}
147 		return info;
148 	}
149 
150 	bool DeleteChild(Info* info)
151 	{
152 		return fChildren.RemoveItem(info, true);
153 	}
154 
155 	void DeleteChildAt(int32 index)
156 	{
157 		delete fChildren.RemoveItemAt(index);
158 	}
159 
160 private:
161 	RootInfo*	fRoot;
162 	Info*		fParent;
163 	BString		fPath;
164 	node_ref	fDefinitionFileNodeRef;
165 	entry_ref	fDefinitionFileEntryRef;
166 	BString		fId;
167 	node_ref	fChildDefinitionsDirectoryRef;
168 	InfoList	fChildren;
169 };
170 
171 
172 // #pragma mark - VirtualDirectoryManager::RootInfo
173 
174 
175 class VirtualDirectoryManager::RootInfo {
176 public:
177 	RootInfo(const node_ref& definitionFileNodeRef,
178 		const entry_ref& definitionFileEntryRef)
179 		:
180 		fDirectoryPaths(),
181 		fInfo(new(std::nothrow) VirtualDirectoryManager::Info(this, NULL,
182 				BString(), definitionFileNodeRef, definitionFileEntryRef)),
183 		fFileTime(-1),
184 		fLastChangeTime(-1)
185 	{
186 	}
187 
188 	~RootInfo()
189 	{
190 		delete fInfo;
191 	}
192 
193 	status_t InitCheck() const
194 	{
195 		return fInfo != NULL ? B_OK : B_NO_MEMORY;
196 	}
197 
198 	bigtime_t FileTime() const
199 	{
200 		return fFileTime;
201 	}
202 
203 	bigtime_t LastChangeTime() const
204 	{
205 		return fLastChangeTime;
206 	}
207 
208 	const BStringList& DirectoryPaths() const
209 	{
210 		return fDirectoryPaths;
211 	}
212 
213 	status_t ReadDefinition(bool* _changed = NULL)
214 	{
215 		// open the definition file
216 		BFile file;
217 		status_t error = file.SetTo(&fInfo->DefinitionFileEntryRef(),
218 			B_READ_ONLY);
219 		if (error != B_OK)
220 			return error;
221 
222 		struct stat st;
223 		error = file.GetStat(&st);
224 		if (error != B_OK)
225 			return error;
226 
227 		bigtime_t fileTime = st.st_mtim.tv_sec * 1000000
228 			+ st.st_mtim.tv_nsec / 1000;
229 		if (fileTime == fFileTime) {
230 			if (_changed != NULL)
231 				*_changed = false;
232 			return B_OK;
233 		}
234 
235 		if (node_ref(st.st_dev, st.st_ino) != fInfo->DefinitionFileNodeRef())
236 			return B_ENTRY_NOT_FOUND;
237 
238 		// read the contents
239 		off_t fileSize = st.st_size;
240 		if (fileSize > (off_t)kMaxVirtualDirectoryFileSize)
241 			return B_BAD_VALUE;
242 
243 		char* buffer = new(std::nothrow) char[fileSize + 1];
244 		if (buffer == NULL)
245 			return B_NO_MEMORY;
246 		ArrayDeleter<char> bufferDeleter(buffer);
247 
248 		ssize_t bytesRead = file.ReadAt(0, buffer, fileSize);
249 		if (bytesRead < 0)
250 			return bytesRead;
251 
252 		buffer[bytesRead] = '\0';
253 
254 		// parse it
255 		BStringList oldDirectoryPaths(fDirectoryPaths);
256 		fDirectoryPaths.MakeEmpty();
257 
258 		BDriverSettings driverSettings;
259 		error = driverSettings.SetToString(buffer);
260 		if (error != B_OK)
261 			return error;
262 
263 		BDriverParameterIterator it
264 			= driverSettings.ParameterIterator("directory");
265 		while (it.HasNext()) {
266 			BDriverParameter parameter = it.Next();
267 			for (int32 i = 0; i < parameter.CountValues(); i++)
268 				fDirectoryPaths.Add(parameter.ValueAt(i));
269 		}
270 
271 		// update file time and check whether something has changed
272 		fFileTime = fileTime;
273 
274 		bool changed = fDirectoryPaths != oldDirectoryPaths;
275 		if (changed || fLastChangeTime < 0)
276 			fLastChangeTime = fFileTime;
277 
278 		if (_changed != NULL)
279 			*_changed = changed;
280 
281 		return B_OK;
282 	}
283 
284 	VirtualDirectoryManager::Info* Info() const
285 	{
286 		return fInfo;
287 	}
288 
289 private:
290 	typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap;
291 
292 private:
293 	BStringList						fDirectoryPaths;
294 	VirtualDirectoryManager::Info*	fInfo;
295 	bigtime_t						fFileTime;
296 										// actual file modified time
297 	bigtime_t						fLastChangeTime;
298 										// last time something actually changed
299 };
300 
301 
302 // #pragma mark - VirtualDirectoryManager
303 
304 
305 VirtualDirectoryManager::VirtualDirectoryManager()
306 	:
307 	fLock("virtual directory manager")
308 {
309 }
310 
311 
312 /*static*/ VirtualDirectoryManager*
313 VirtualDirectoryManager::Instance()
314 {
315 	static VirtualDirectoryManager* manager
316 		= new(std::nothrow) VirtualDirectoryManager;
317 	return manager;
318 }
319 
320 
321 status_t
322 VirtualDirectoryManager::ResolveDirectoryPaths(
323 	const node_ref& definitionFileNodeRef,
324 	const entry_ref& definitionFileEntryRef, BStringList& _directoryPaths,
325 	node_ref* _definitionFileNodeRef, entry_ref* _definitionFileEntryRef)
326 {
327 	Info* info = _InfoForNodeRef(definitionFileNodeRef);
328 	if (info == NULL) {
329 		status_t error = _ResolveUnknownDefinitionFile(definitionFileNodeRef,
330 			definitionFileEntryRef, info);
331 		if (error != B_OK)
332 			return error;
333 	}
334 
335 	const BString& subDirectory = info->Path();
336 	const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
337 	if (subDirectory.IsEmpty()) {
338 		_directoryPaths = rootDirectoryPaths;
339 	} else {
340 		_directoryPaths.MakeEmpty();
341 		int32 count = rootDirectoryPaths.CountStrings();
342 		for (int32 i = 0; i < count; i++) {
343 			BString path = rootDirectoryPaths.StringAt(i);
344 			_directoryPaths.Add(path << '/' << subDirectory);
345 		}
346 	}
347 
348 	if (_definitionFileEntryRef != NULL) {
349 		*_definitionFileEntryRef = info->DefinitionFileEntryRef();
350 		if (_definitionFileEntryRef->name == NULL)
351 			return B_NO_MEMORY;
352 	}
353 
354 	if (_definitionFileNodeRef != NULL)
355 		*_definitionFileNodeRef = info->DefinitionFileNodeRef();
356 
357 	return B_OK;
358 }
359 
360 
361 bool
362 VirtualDirectoryManager::GetDefinitionFileChangeTime(
363 	const node_ref& definitionFileRef, bigtime_t& _time) const
364 {
365 	Info* info = _InfoForNodeRef(definitionFileRef);
366 	if (info == NULL)
367 		return false;
368 
369 	_time = info->Root()->LastChangeTime();
370 	return true;
371 }
372 
373 
374 bool
375 VirtualDirectoryManager::GetRootDefinitionFile(
376 	const node_ref& definitionFileRef, node_ref& _rootDefinitionFileRef)
377 {
378 	Info* info = _InfoForNodeRef(definitionFileRef);
379 	if (info == NULL)
380 		return false;
381 
382 	_rootDefinitionFileRef = info->Root()->Info()->DefinitionFileNodeRef();
383 	return true;
384 }
385 
386 
387 bool
388 VirtualDirectoryManager::GetSubDirectoryDefinitionFile(
389 	const node_ref& baseDefinitionRef, const char* subDirName,
390 	entry_ref& _entryRef, node_ref& _nodeRef)
391 {
392 	Info* parentInfo = _InfoForNodeRef(baseDefinitionRef);
393 	if (parentInfo == NULL)
394 		return false;
395 
396 	Info* info = parentInfo->GetChild(subDirName);
397 	if (info == NULL)
398 		return false;
399 
400 	_entryRef = info->DefinitionFileEntryRef();
401 	_nodeRef = info->DefinitionFileNodeRef();
402 	return _entryRef.name != NULL;
403 }
404 
405 
406 bool
407 VirtualDirectoryManager::GetParentDirectoryDefinitionFile(
408 	const node_ref& subDirDefinitionRef, entry_ref& _entryRef,
409 	node_ref& _nodeRef)
410 {
411 	Info* info = _InfoForNodeRef(subDirDefinitionRef);
412 	if (info == NULL)
413 		return false;
414 
415 	Info* parentInfo = info->Parent();
416 	if (parentInfo == NULL)
417 		return false;
418 
419 	_entryRef = parentInfo->DefinitionFileEntryRef();
420 	_nodeRef = parentInfo->DefinitionFileNodeRef();
421 	return _entryRef.name != NULL;
422 }
423 
424 
425 status_t
426 VirtualDirectoryManager::TranslateDirectoryEntry(
427 	const node_ref& definitionFileRef, dirent* buffer)
428 {
429 	NotOwningEntryRef entryRef(buffer->d_pdev, buffer->d_pino, buffer->d_name);
430 	node_ref nodeRef(buffer->d_dev, buffer->d_ino);
431 
432 	status_t result = TranslateDirectoryEntry(definitionFileRef, entryRef,
433 		nodeRef);
434 	if (result != B_OK)
435 		return result;
436 
437 	buffer->d_pdev = entryRef.device;
438 	buffer->d_pino = entryRef.directory;
439 	buffer->d_dev = nodeRef.device;
440 	buffer->d_ino = nodeRef.node;
441 
442 	return B_OK;
443 }
444 
445 
446 status_t
447 VirtualDirectoryManager::TranslateDirectoryEntry(
448 	const node_ref& definitionFileRef, entry_ref& _entryRef, node_ref& _nodeRef)
449 {
450 	Info* parentInfo = _InfoForNodeRef(definitionFileRef);
451 	if (parentInfo == NULL)
452 		return B_BAD_VALUE;
453 
454 	// get the info for the entry
455 	Info* info = parentInfo->GetChild(_entryRef.name);
456 	if (info == NULL) {
457 		// If not done yet, create a directory for the parent, where we can
458 		// place the new definition file.
459 		if (parentInfo->Id().IsEmpty()) {
460 			BString id = BUuid().SetToRandom().ToString();
461 			if (id.IsEmpty())
462 				return B_NO_MEMORY;
463 
464 			BPath path(kTemporaryDefinitionFileBaseDirectoryPath, id);
465 			status_t error = path.InitCheck();
466 			if (error != B_OK)
467 				return error;
468 
469 			error = create_directory(path.Path(),
470 				S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
471 			if (error != B_OK)
472 				return error;
473 
474 			struct stat st;
475 			if (lstat(path.Path(), &st) != 0)
476 				return errno;
477 
478 			parentInfo->SetId(id);
479 			parentInfo->SetChildDefinitionsDirectoryRef(
480 				node_ref(st.st_dev, st.st_ino));
481 		}
482 
483 		// create the definition file
484 		const node_ref& directoryRef
485 			= parentInfo->ChildDefinitionsDirectoryRef();
486 		NotOwningEntryRef entryRef(directoryRef, _entryRef.name);
487 
488 		BFile definitionFile;
489 		status_t error = definitionFile.SetTo(&entryRef,
490 			B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
491 		if (error != B_OK)
492 			return error;
493 
494 		node_ref nodeRef;
495 		error = definitionFile.GetNodeRef(&nodeRef);
496 		if (error != B_OK)
497 			return error;
498 
499 		BNodeInfo nodeInfo(&definitionFile);
500 		error = nodeInfo.SetType(kVirtualDirectoryMimeType);
501 		if (error != B_OK)
502 			return error;
503 
504 		// create the info
505 		info = parentInfo->CreateChild(nodeRef, entryRef);
506 		if (info == NULL || !_AddInfo(info))
507 			return B_NO_MEMORY;
508 
509 		// Write some info into the definition file that helps us to find the
510 		// root definition file. This is only necessary when definition file
511 		// entry refs are transferred between applications. Then the receiving
512 		// application may need to find the root definition file and resolve
513 		// the subdirectories.
514 		const entry_ref& rootEntryRef
515 			= parentInfo->Root()->Info()->DefinitionFileEntryRef();
516 		BString definitionFileContent;
517 		definitionFileContent.SetToFormat(
518 			"root {\n"
519 			"  device %" B_PRIdDEV "\n"
520 			"  directory %" B_PRIdINO "\n"
521 			"  name \"%s\"\n"
522 			"}\n"
523 			"subdir \"%s\"\n",
524 			rootEntryRef.device, rootEntryRef.directory, rootEntryRef.name,
525 			info->Path().String());
526 		// failure is not nice, but not mission critical for this application
527 		if (!definitionFileContent.IsEmpty()) {
528 			definitionFile.WriteAt(0,
529 				definitionFileContent.String(), definitionFileContent.Length());
530 		}
531 	}
532 
533 	const entry_ref& entryRef = info->DefinitionFileEntryRef();
534 	_nodeRef = info->DefinitionFileNodeRef();
535 	_entryRef.device = entryRef.device;
536 	_entryRef.directory = entryRef.directory;
537 
538 	return B_OK;
539 }
540 
541 
542 bool
543 VirtualDirectoryManager::DefinitionFileChanged(
544 	const node_ref& definitionFileRef)
545 {
546 	Info* info = _InfoForNodeRef(definitionFileRef);
547 	if (info == NULL)
548 		return false;
549 
550 	_UpdateTree(info->Root());
551 
552 	return _InfoForNodeRef(definitionFileRef) != NULL;
553 }
554 
555 
556 status_t
557 VirtualDirectoryManager::DirectoryRemoved(const node_ref& definitionFileRef)
558 {
559 	Info* info = _InfoForNodeRef(definitionFileRef);
560 	if (info == NULL)
561 		return B_ENTRY_NOT_FOUND;
562 
563 	_RemoveDirectory(info);
564 
565 	// delete the info
566 	if (info->Parent() == NULL)
567 		delete info->Root();
568 	else
569 		info->Parent()->DeleteChild(info);
570 
571 	return B_OK;
572 }
573 
574 
575 /*static*/ bool
576 VirtualDirectoryManager::GetEntry(const BStringList& directoryPaths,
577 	const char* name, entry_ref* _ref, struct stat* _st)
578 {
579 	int32 count = directoryPaths.CountStrings();
580 	for (int32 i = 0; i < count; i++) {
581 		BPath path;
582 		if (path.SetTo(directoryPaths.StringAt(i), name) != B_OK)
583 			continue;
584 
585 		struct stat st;
586 		if (lstat(path.Path(), &st) == 0) {
587 			if (_ref != NULL) {
588 				if (get_ref_for_path(path.Path(), _ref) != B_OK)
589 					return false;
590 			}
591 			if (_st != NULL)
592 				*_st = st;
593 			return true;
594 		}
595 	}
596 
597 	return false;
598 }
599 
600 
601 VirtualDirectoryManager::Info*
602 VirtualDirectoryManager::_InfoForNodeRef(const node_ref& nodeRef) const
603 {
604 	NodeRefInfoMap::const_iterator it = fInfos.find(nodeRef);
605 	return it != fInfos.end() ? it->second : NULL;
606 }
607 
608 
609 bool
610 VirtualDirectoryManager::_AddInfo(Info* info)
611 {
612 	try {
613 		fInfos[info->DefinitionFileNodeRef()] = info;
614 		return true;
615 	} catch (...) {
616 		return false;
617 	}
618 }
619 
620 
621 void
622 VirtualDirectoryManager::_RemoveInfo(Info* info)
623 {
624 	NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef());
625 	if (it != fInfos.end())
626 		fInfos.erase(it);
627 }
628 
629 
630 void
631 VirtualDirectoryManager::_UpdateTree(RootInfo* root)
632 {
633 	bool changed = false;
634 	status_t result = root->ReadDefinition(&changed);
635 	if (result != B_OK) {
636 		DirectoryRemoved(root->Info()->DefinitionFileNodeRef());
637 		return;
638 	}
639 
640 	if (!changed)
641 		return;
642 
643 	_UpdateTree(root->Info());
644 }
645 
646 
647 void
648 VirtualDirectoryManager::_UpdateTree(Info* info)
649 {
650 	const BStringList& directoryPaths = info->Root()->DirectoryPaths();
651 
652 	int32 childCount = info->Children().CountItems();
653 	for (int32 i = childCount -1; i >= 0; i--) {
654 		Info* childInfo = info->Children().ItemAt(i);
655 		struct stat st;
656 		if (GetEntry(directoryPaths, childInfo->Path(), NULL, &st)
657 			&& S_ISDIR(st.st_mode)) {
658 			_UpdateTree(childInfo);
659 		} else {
660 			_RemoveDirectory(childInfo);
661 			info->DeleteChildAt(i);
662 		}
663 	}
664 }
665 
666 
667 void
668 VirtualDirectoryManager::_RemoveDirectory(Info* info)
669 {
670 	// recursively remove the subdirectories
671 	for (int32 i = 0; Info* child = info->Children().ItemAt(i); i++)
672 		_RemoveDirectory(child);
673 
674 	// remove the directory for the child definition file
675 	if (!info->Id().IsEmpty()) {
676 		BPath path(kTemporaryDefinitionFileBaseDirectoryPath, info->Id());
677 		if (path.InitCheck() == B_OK)
678 			rmdir(path.Path());
679 	}
680 
681 	// unless this is the root directory, remove the definition file
682 	if (info != info->Root()->Info())
683 		BEntry(&info->DefinitionFileEntryRef()).Remove();
684 
685 	_RemoveInfo(info);
686 }
687 
688 
689 status_t
690 VirtualDirectoryManager::_ResolveUnknownDefinitionFile(
691 	const node_ref& definitionFileNodeRef,
692 	const entry_ref& definitionFileEntryRef, Info*& _info)
693 {
694 	// This is either a root definition file or a subdir definition file
695 	// created by another application. We'll just try to read the info from the
696 	// file that a subdir definition file would contain. If that fails, we
697 	// assume a root definition file.
698 	entry_ref entryRef;
699 	BString subDirPath;
700 	if (_ReadSubDirectoryDefinitionFileInfo(definitionFileEntryRef, entryRef,
701 			subDirPath) != B_OK) {
702 		return _CreateRootInfo(definitionFileNodeRef, definitionFileEntryRef,
703 			_info);
704 	}
705 
706 	if (subDirPath.IsEmpty())
707 		return B_BAD_VALUE;
708 
709 	// get the root definition file node ref
710 	node_ref nodeRef;
711 	status_t error = BEntry(&entryRef).GetNodeRef(&nodeRef);
712 	if (error != B_OK)
713 		return error;
714 
715 	// resolve/create the root info
716 	Info* info = _InfoForNodeRef(nodeRef);
717 	if (info == NULL) {
718 		error = _CreateRootInfo(nodeRef, entryRef, info);
719 		if (error != B_OK)
720 			return error;
721 	} else if (info->Root()->Info() != info)
722 		return B_BAD_VALUE;
723 
724 	const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
725 
726 	// now we can traverse the subdir path and resolve all infos along the way
727 	int32 nextComponentOffset = 0;
728 	while (nextComponentOffset < subDirPath.Length()) {
729 		int32 componentEnd = subDirPath.FindFirst('/', nextComponentOffset);
730 		if (componentEnd >= 0) {
731 			// skip duplicate '/'s
732 			if (componentEnd == nextComponentOffset + 1) {
733 				nextComponentOffset = componentEnd;
734 				continue;
735 			}
736 			nextComponentOffset = componentEnd + 1;
737 		} else {
738 			componentEnd = subDirPath.Length();
739 			nextComponentOffset = componentEnd;
740 		}
741 
742 		BString entryPath(subDirPath, componentEnd);
743 		if (entryPath.IsEmpty())
744 			return B_NO_MEMORY;
745 
746 		struct stat st;
747 		if (!GetEntry(rootDirectoryPaths, entryPath, &entryRef, &st))
748 			return B_ENTRY_NOT_FOUND;
749 
750 		if (!S_ISDIR(st.st_mode))
751 			return B_BAD_VALUE;
752 
753 		error = TranslateDirectoryEntry(info->DefinitionFileNodeRef(), entryRef,
754 			nodeRef);
755 		if (error != B_OK)
756 			return error;
757 
758 		info = _InfoForNodeRef(nodeRef);
759 	}
760 
761 	_info = info;
762 
763 	return B_OK;
764 }
765 
766 
767 status_t
768 VirtualDirectoryManager::_CreateRootInfo(const node_ref& definitionFileNodeRef,
769 	const entry_ref& definitionFileEntryRef, Info*& _info)
770 {
771 	RootInfo* root = new(std::nothrow) RootInfo(definitionFileNodeRef,
772 		definitionFileEntryRef);
773 	if (root == NULL || root->InitCheck() != B_OK) {
774 		delete root;
775 		return B_NO_MEMORY;
776 	}
777 	ObjectDeleter<RootInfo> rootDeleter(root);
778 
779 	status_t error = root->ReadDefinition();
780 	if (error != B_OK)
781 		return error;
782 
783 	if (!_AddInfo(root->Info()))
784 		return B_NO_MEMORY;
785 
786 	rootDeleter.Detach();
787 	_info = root->Info();
788 
789 	return B_OK;
790 }
791 
792 
793 status_t
794 VirtualDirectoryManager::_ReadSubDirectoryDefinitionFileInfo(
795 	const entry_ref& entryRef, entry_ref& _rootDefinitionFileEntryRef,
796 	BString& _subDirPath)
797 {
798 	BDriverSettings driverSettings;
799 	status_t error = driverSettings.Load(entryRef);
800 	if (error != B_OK)
801 		return error;
802 
803 	const char* subDirPath = driverSettings.GetParameterValue("subdir");
804 	if (subDirPath == NULL || subDirPath[0] == '\0')
805 		return B_BAD_DATA;
806 
807 	BDriverParameter rootParameter;
808 	if (!driverSettings.FindParameter("root", &rootParameter))
809 		return B_BAD_DATA;
810 
811 	const char* name = rootParameter.GetParameterValue("name");
812 	dev_t device = rootParameter.GetInt32ParameterValue("device", -1, -1);
813 	ino_t directory = rootParameter.GetInt64ParameterValue("directory");
814 	if (name == NULL || name[0] == '\0' || device < 0)
815 		return B_BAD_DATA;
816 
817 	_rootDefinitionFileEntryRef = entry_ref(device, directory, name);
818 	_subDirPath = subDirPath;
819 
820 	return !_subDirPath.IsEmpty() && _rootDefinitionFileEntryRef.name != NULL
821 		? B_OK : B_NO_MEMORY;
822 }
823 
824 } // namespace BPrivate
825