xref: /haiku/src/kits/tracker/VirtualDirectoryManager.cpp (revision 4e3137c085bae361922078f123dceb92da700640)
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;
228 		fileTime *= 1000000;
229 		fileTime += st.st_mtim.tv_nsec / 1000;
230 		if (fileTime == fFileTime) {
231 			if (_changed != NULL)
232 				*_changed = false;
233 
234 			return B_OK;
235 		}
236 
237 		if (node_ref(st.st_dev, st.st_ino) != fInfo->DefinitionFileNodeRef())
238 			return B_ENTRY_NOT_FOUND;
239 
240 		// read the contents
241 		off_t fileSize = st.st_size;
242 		if (fileSize > (off_t)kMaxVirtualDirectoryFileSize)
243 			return B_BAD_VALUE;
244 
245 		char* buffer = new(std::nothrow) char[fileSize + 1];
246 		if (buffer == NULL)
247 			return B_NO_MEMORY;
248 		ArrayDeleter<char> bufferDeleter(buffer);
249 
250 		ssize_t bytesRead = file.ReadAt(0, buffer, fileSize);
251 		if (bytesRead < 0)
252 			return bytesRead;
253 
254 		buffer[bytesRead] = '\0';
255 
256 		// parse it
257 		BStringList oldDirectoryPaths(fDirectoryPaths);
258 		fDirectoryPaths.MakeEmpty();
259 
260 		BDriverSettings driverSettings;
261 		error = driverSettings.SetToString(buffer);
262 		if (error != B_OK)
263 			return error;
264 
265 		BDriverParameterIterator it
266 			= driverSettings.ParameterIterator("directory");
267 		while (it.HasNext()) {
268 			BDriverParameter parameter = it.Next();
269 			for (int32 i = 0; i < parameter.CountValues(); i++)
270 				fDirectoryPaths.Add(parameter.ValueAt(i));
271 		}
272 
273 		// update file time and check whether something has changed
274 		fFileTime = fileTime;
275 
276 		bool changed = fDirectoryPaths != oldDirectoryPaths;
277 		if (changed || fLastChangeTime < 0)
278 			fLastChangeTime = fFileTime;
279 
280 		if (_changed != NULL)
281 			*_changed = changed;
282 
283 		return B_OK;
284 	}
285 
286 	VirtualDirectoryManager::Info* Info() const
287 	{
288 		return fInfo;
289 	}
290 
291 private:
292 	typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap;
293 
294 private:
295 	BStringList						fDirectoryPaths;
296 	VirtualDirectoryManager::Info*	fInfo;
297 	bigtime_t						fFileTime;
298 										// actual file modified time
299 	bigtime_t						fLastChangeTime;
300 										// last time something actually changed
301 };
302 
303 
304 // #pragma mark - VirtualDirectoryManager
305 
306 
307 VirtualDirectoryManager::VirtualDirectoryManager()
308 	:
309 	fLock("virtual directory manager")
310 {
311 }
312 
313 
314 /*static*/ VirtualDirectoryManager*
315 VirtualDirectoryManager::Instance()
316 {
317 	static VirtualDirectoryManager* manager
318 		= new(std::nothrow) VirtualDirectoryManager;
319 	return manager;
320 }
321 
322 
323 status_t
324 VirtualDirectoryManager::ResolveDirectoryPaths(
325 	const node_ref& definitionFileNodeRef,
326 	const entry_ref& definitionFileEntryRef, BStringList& _directoryPaths,
327 	node_ref* _definitionFileNodeRef, entry_ref* _definitionFileEntryRef)
328 {
329 	Info* info = _InfoForNodeRef(definitionFileNodeRef);
330 	if (info == NULL) {
331 		status_t error = _ResolveUnknownDefinitionFile(definitionFileNodeRef,
332 			definitionFileEntryRef, info);
333 		if (error != B_OK)
334 			return error;
335 	}
336 
337 	const BString& subDirectory = info->Path();
338 	const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
339 	if (subDirectory.IsEmpty()) {
340 		_directoryPaths = rootDirectoryPaths;
341 	} else {
342 		_directoryPaths.MakeEmpty();
343 		int32 count = rootDirectoryPaths.CountStrings();
344 		for (int32 i = 0; i < count; i++) {
345 			BString path = rootDirectoryPaths.StringAt(i);
346 			_directoryPaths.Add(path << '/' << subDirectory);
347 		}
348 	}
349 
350 	if (_definitionFileEntryRef != NULL) {
351 		*_definitionFileEntryRef = info->DefinitionFileEntryRef();
352 		if (_definitionFileEntryRef->name == NULL)
353 			return B_NO_MEMORY;
354 	}
355 
356 	if (_definitionFileNodeRef != NULL)
357 		*_definitionFileNodeRef = info->DefinitionFileNodeRef();
358 
359 	return B_OK;
360 }
361 
362 
363 bool
364 VirtualDirectoryManager::GetDefinitionFileChangeTime(
365 	const node_ref& definitionFileRef, bigtime_t& _time) const
366 {
367 	Info* info = _InfoForNodeRef(definitionFileRef);
368 	if (info == NULL)
369 		return false;
370 
371 	_time = info->Root()->LastChangeTime();
372 	return true;
373 }
374 
375 
376 bool
377 VirtualDirectoryManager::GetRootDefinitionFile(
378 	const node_ref& definitionFileRef, node_ref& _rootDefinitionFileRef)
379 {
380 	Info* info = _InfoForNodeRef(definitionFileRef);
381 	if (info == NULL)
382 		return false;
383 
384 	_rootDefinitionFileRef = info->Root()->Info()->DefinitionFileNodeRef();
385 	return true;
386 }
387 
388 
389 bool
390 VirtualDirectoryManager::GetSubDirectoryDefinitionFile(
391 	const node_ref& baseDefinitionRef, const char* subDirName,
392 	entry_ref& _entryRef, node_ref& _nodeRef)
393 {
394 	Info* parentInfo = _InfoForNodeRef(baseDefinitionRef);
395 	if (parentInfo == NULL)
396 		return false;
397 
398 	Info* info = parentInfo->GetChild(subDirName);
399 	if (info == NULL)
400 		return false;
401 
402 	_entryRef = info->DefinitionFileEntryRef();
403 	_nodeRef = info->DefinitionFileNodeRef();
404 	return _entryRef.name != NULL;
405 }
406 
407 
408 bool
409 VirtualDirectoryManager::GetParentDirectoryDefinitionFile(
410 	const node_ref& subDirDefinitionRef, entry_ref& _entryRef,
411 	node_ref& _nodeRef)
412 {
413 	Info* info = _InfoForNodeRef(subDirDefinitionRef);
414 	if (info == NULL)
415 		return false;
416 
417 	Info* parentInfo = info->Parent();
418 	if (parentInfo == NULL)
419 		return false;
420 
421 	_entryRef = parentInfo->DefinitionFileEntryRef();
422 	_nodeRef = parentInfo->DefinitionFileNodeRef();
423 	return _entryRef.name != NULL;
424 }
425 
426 
427 status_t
428 VirtualDirectoryManager::TranslateDirectoryEntry(
429 	const node_ref& definitionFileRef, dirent* buffer)
430 {
431 	NotOwningEntryRef entryRef(buffer->d_pdev, buffer->d_pino, buffer->d_name);
432 	node_ref nodeRef(buffer->d_dev, buffer->d_ino);
433 
434 	status_t result = TranslateDirectoryEntry(definitionFileRef, entryRef,
435 		nodeRef);
436 	if (result != B_OK)
437 		return result;
438 
439 	buffer->d_pdev = entryRef.device;
440 	buffer->d_pino = entryRef.directory;
441 	buffer->d_dev = nodeRef.device;
442 	buffer->d_ino = nodeRef.node;
443 
444 	return B_OK;
445 }
446 
447 
448 status_t
449 VirtualDirectoryManager::TranslateDirectoryEntry(
450 	const node_ref& definitionFileRef, entry_ref& _entryRef, node_ref& _nodeRef)
451 {
452 	Info* parentInfo = _InfoForNodeRef(definitionFileRef);
453 	if (parentInfo == NULL)
454 		return B_BAD_VALUE;
455 
456 	// get the info for the entry
457 	Info* info = parentInfo->GetChild(_entryRef.name);
458 	if (info == NULL) {
459 		// If not done yet, create a directory for the parent, where we can
460 		// place the new definition file.
461 		if (parentInfo->Id().IsEmpty()) {
462 			BString id = BUuid().SetToRandom().ToString();
463 			if (id.IsEmpty())
464 				return B_NO_MEMORY;
465 
466 			BPath path(kTemporaryDefinitionFileBaseDirectoryPath, id);
467 			status_t error = path.InitCheck();
468 			if (error != B_OK)
469 				return error;
470 
471 			error = create_directory(path.Path(),
472 				S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
473 			if (error != B_OK)
474 				return error;
475 
476 			struct stat st;
477 			if (lstat(path.Path(), &st) != 0)
478 				return errno;
479 
480 			parentInfo->SetId(id);
481 			parentInfo->SetChildDefinitionsDirectoryRef(
482 				node_ref(st.st_dev, st.st_ino));
483 		}
484 
485 		// create the definition file
486 		const node_ref& directoryRef
487 			= parentInfo->ChildDefinitionsDirectoryRef();
488 		NotOwningEntryRef entryRef(directoryRef, _entryRef.name);
489 
490 		BFile definitionFile;
491 		status_t error = definitionFile.SetTo(&entryRef,
492 			B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
493 		if (error != B_OK)
494 			return error;
495 
496 		node_ref nodeRef;
497 		error = definitionFile.GetNodeRef(&nodeRef);
498 		if (error != B_OK)
499 			return error;
500 
501 		BNodeInfo nodeInfo(&definitionFile);
502 		error = nodeInfo.SetType(kVirtualDirectoryMimeType);
503 		if (error != B_OK)
504 			return error;
505 
506 		// create the info
507 		info = parentInfo->CreateChild(nodeRef, entryRef);
508 		if (info == NULL || !_AddInfo(info))
509 			return B_NO_MEMORY;
510 
511 		// Write some info into the definition file that helps us to find the
512 		// root definition file. This is only necessary when definition file
513 		// entry refs are transferred between applications. Then the receiving
514 		// application may need to find the root definition file and resolve
515 		// the subdirectories.
516 		const entry_ref& rootEntryRef
517 			= parentInfo->Root()->Info()->DefinitionFileEntryRef();
518 		BString definitionFileContent;
519 		definitionFileContent.SetToFormat(
520 			"root {\n"
521 			"  device %" B_PRIdDEV "\n"
522 			"  directory %" B_PRIdINO "\n"
523 			"  name \"%s\"\n"
524 			"}\n"
525 			"subdir \"%s\"\n",
526 			rootEntryRef.device, rootEntryRef.directory, rootEntryRef.name,
527 			info->Path().String());
528 		// failure is not nice, but not mission critical for this application
529 		if (!definitionFileContent.IsEmpty()) {
530 			definitionFile.WriteAt(0,
531 				definitionFileContent.String(), definitionFileContent.Length());
532 		}
533 	}
534 
535 	const entry_ref& entryRef = info->DefinitionFileEntryRef();
536 	_nodeRef = info->DefinitionFileNodeRef();
537 	_entryRef.device = entryRef.device;
538 	_entryRef.directory = entryRef.directory;
539 
540 	return B_OK;
541 }
542 
543 
544 bool
545 VirtualDirectoryManager::DefinitionFileChanged(
546 	const node_ref& definitionFileRef)
547 {
548 	Info* info = _InfoForNodeRef(definitionFileRef);
549 	if (info == NULL)
550 		return false;
551 
552 	_UpdateTree(info->Root());
553 
554 	return _InfoForNodeRef(definitionFileRef) != NULL;
555 }
556 
557 
558 status_t
559 VirtualDirectoryManager::DirectoryRemoved(const node_ref& definitionFileRef)
560 {
561 	Info* info = _InfoForNodeRef(definitionFileRef);
562 	if (info == NULL)
563 		return B_ENTRY_NOT_FOUND;
564 
565 	_RemoveDirectory(info);
566 
567 	// delete the info
568 	if (info->Parent() == NULL)
569 		delete info->Root();
570 	else
571 		info->Parent()->DeleteChild(info);
572 
573 	return B_OK;
574 }
575 
576 
577 /*static*/ bool
578 VirtualDirectoryManager::GetEntry(const BStringList& directoryPaths,
579 	const char* name, entry_ref* _ref, struct stat* _st)
580 {
581 	int32 count = directoryPaths.CountStrings();
582 	for (int32 i = 0; i < count; i++) {
583 		BPath path;
584 		if (path.SetTo(directoryPaths.StringAt(i), name) != B_OK)
585 			continue;
586 
587 		struct stat st;
588 		if (lstat(path.Path(), &st) == 0) {
589 			if (_ref != NULL) {
590 				if (get_ref_for_path(path.Path(), _ref) != B_OK)
591 					return false;
592 			}
593 			if (_st != NULL)
594 				*_st = st;
595 			return true;
596 		}
597 	}
598 
599 	return false;
600 }
601 
602 
603 VirtualDirectoryManager::Info*
604 VirtualDirectoryManager::_InfoForNodeRef(const node_ref& nodeRef) const
605 {
606 	NodeRefInfoMap::const_iterator it = fInfos.find(nodeRef);
607 	return it != fInfos.end() ? it->second : NULL;
608 }
609 
610 
611 bool
612 VirtualDirectoryManager::_AddInfo(Info* info)
613 {
614 	try {
615 		fInfos[info->DefinitionFileNodeRef()] = info;
616 		return true;
617 	} catch (...) {
618 		return false;
619 	}
620 }
621 
622 
623 void
624 VirtualDirectoryManager::_RemoveInfo(Info* info)
625 {
626 	NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef());
627 	if (it != fInfos.end())
628 		fInfos.erase(it);
629 }
630 
631 
632 void
633 VirtualDirectoryManager::_UpdateTree(RootInfo* root)
634 {
635 	bool changed = false;
636 	status_t result = root->ReadDefinition(&changed);
637 	if (result != B_OK) {
638 		DirectoryRemoved(root->Info()->DefinitionFileNodeRef());
639 		return;
640 	}
641 
642 	if (!changed)
643 		return;
644 
645 	_UpdateTree(root->Info());
646 }
647 
648 
649 void
650 VirtualDirectoryManager::_UpdateTree(Info* info)
651 {
652 	const BStringList& directoryPaths = info->Root()->DirectoryPaths();
653 
654 	int32 childCount = info->Children().CountItems();
655 	for (int32 i = childCount -1; i >= 0; i--) {
656 		Info* childInfo = info->Children().ItemAt(i);
657 		struct stat st;
658 		if (GetEntry(directoryPaths, childInfo->Path(), NULL, &st)
659 			&& S_ISDIR(st.st_mode)) {
660 			_UpdateTree(childInfo);
661 		} else {
662 			_RemoveDirectory(childInfo);
663 			info->DeleteChildAt(i);
664 		}
665 	}
666 }
667 
668 
669 void
670 VirtualDirectoryManager::_RemoveDirectory(Info* info)
671 {
672 	// recursively remove the subdirectories
673 	for (int32 i = 0; Info* child = info->Children().ItemAt(i); i++)
674 		_RemoveDirectory(child);
675 
676 	// remove the directory for the child definition file
677 	if (!info->Id().IsEmpty()) {
678 		BPath path(kTemporaryDefinitionFileBaseDirectoryPath, info->Id());
679 		if (path.InitCheck() == B_OK)
680 			rmdir(path.Path());
681 	}
682 
683 	// unless this is the root directory, remove the definition file
684 	if (info != info->Root()->Info())
685 		BEntry(&info->DefinitionFileEntryRef()).Remove();
686 
687 	_RemoveInfo(info);
688 }
689 
690 
691 status_t
692 VirtualDirectoryManager::_ResolveUnknownDefinitionFile(
693 	const node_ref& definitionFileNodeRef,
694 	const entry_ref& definitionFileEntryRef, Info*& _info)
695 {
696 	// This is either a root definition file or a subdir definition file
697 	// created by another application. We'll just try to read the info from the
698 	// file that a subdir definition file would contain. If that fails, we
699 	// assume a root definition file.
700 	entry_ref entryRef;
701 	BString subDirPath;
702 	if (_ReadSubDirectoryDefinitionFileInfo(definitionFileEntryRef, entryRef,
703 			subDirPath) != B_OK) {
704 		return _CreateRootInfo(definitionFileNodeRef, definitionFileEntryRef,
705 			_info);
706 	}
707 
708 	if (subDirPath.IsEmpty())
709 		return B_BAD_VALUE;
710 
711 	// get the root definition file node ref
712 	node_ref nodeRef;
713 	status_t error = BEntry(&entryRef).GetNodeRef(&nodeRef);
714 	if (error != B_OK)
715 		return error;
716 
717 	// resolve/create the root info
718 	Info* info = _InfoForNodeRef(nodeRef);
719 	if (info == NULL) {
720 		error = _CreateRootInfo(nodeRef, entryRef, info);
721 		if (error != B_OK)
722 			return error;
723 	} else if (info->Root()->Info() != info)
724 		return B_BAD_VALUE;
725 
726 	const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
727 
728 	// now we can traverse the subdir path and resolve all infos along the way
729 	int32 nextComponentOffset = 0;
730 	while (nextComponentOffset < subDirPath.Length()) {
731 		int32 componentEnd = subDirPath.FindFirst('/', nextComponentOffset);
732 		if (componentEnd >= 0) {
733 			// skip duplicate '/'s
734 			if (componentEnd == nextComponentOffset + 1) {
735 				nextComponentOffset = componentEnd;
736 				continue;
737 			}
738 			nextComponentOffset = componentEnd + 1;
739 		} else {
740 			componentEnd = subDirPath.Length();
741 			nextComponentOffset = componentEnd;
742 		}
743 
744 		BString entryPath(subDirPath, componentEnd);
745 		if (entryPath.IsEmpty())
746 			return B_NO_MEMORY;
747 
748 		struct stat st;
749 		if (!GetEntry(rootDirectoryPaths, entryPath, &entryRef, &st))
750 			return B_ENTRY_NOT_FOUND;
751 
752 		if (!S_ISDIR(st.st_mode))
753 			return B_BAD_VALUE;
754 
755 		error = TranslateDirectoryEntry(info->DefinitionFileNodeRef(), entryRef,
756 			nodeRef);
757 		if (error != B_OK)
758 			return error;
759 
760 		info = _InfoForNodeRef(nodeRef);
761 	}
762 
763 	_info = info;
764 
765 	return B_OK;
766 }
767 
768 
769 status_t
770 VirtualDirectoryManager::_CreateRootInfo(const node_ref& definitionFileNodeRef,
771 	const entry_ref& definitionFileEntryRef, Info*& _info)
772 {
773 	RootInfo* root = new(std::nothrow) RootInfo(definitionFileNodeRef,
774 		definitionFileEntryRef);
775 	if (root == NULL || root->InitCheck() != B_OK) {
776 		delete root;
777 		return B_NO_MEMORY;
778 	}
779 	ObjectDeleter<RootInfo> rootDeleter(root);
780 
781 	status_t error = root->ReadDefinition();
782 	if (error != B_OK)
783 		return error;
784 
785 	if (!_AddInfo(root->Info()))
786 		return B_NO_MEMORY;
787 
788 	rootDeleter.Detach();
789 	_info = root->Info();
790 
791 	return B_OK;
792 }
793 
794 
795 status_t
796 VirtualDirectoryManager::_ReadSubDirectoryDefinitionFileInfo(
797 	const entry_ref& entryRef, entry_ref& _rootDefinitionFileEntryRef,
798 	BString& _subDirPath)
799 {
800 	BDriverSettings driverSettings;
801 	status_t error = driverSettings.Load(entryRef);
802 	if (error != B_OK)
803 		return error;
804 
805 	const char* subDirPath = driverSettings.GetParameterValue("subdir");
806 	if (subDirPath == NULL || subDirPath[0] == '\0')
807 		return B_BAD_DATA;
808 
809 	BDriverParameter rootParameter;
810 	if (!driverSettings.FindParameter("root", &rootParameter))
811 		return B_BAD_DATA;
812 
813 	const char* name = rootParameter.GetParameterValue("name");
814 	dev_t device = rootParameter.GetInt32ParameterValue("device", -1, -1);
815 	ino_t directory = rootParameter.GetInt64ParameterValue("directory");
816 	if (name == NULL || name[0] == '\0' || device < 0)
817 		return B_BAD_DATA;
818 
819 	_rootDefinitionFileEntryRef = entry_ref(device, directory, name);
820 	_subDirPath = subDirPath;
821 
822 	return !_subDirPath.IsEmpty() && _rootDefinitionFileEntryRef.name != NULL
823 		? B_OK : B_NO_MEMORY;
824 }
825 
826 } // namespace BPrivate
827