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
30namespace BPrivate {
31
32static const size_t kMaxVirtualDirectoryFileSize = 10 * 1024;
33static const char* const kTemporaryDefinitionFileBaseDirectoryPath
34	= "/tmp/tracker/virtual-directories";
35
36
37// #pragma mark - VirtualDirectoryManager::Info
38
39
40class VirtualDirectoryManager::Info {
41private:
42	typedef BObjectList<Info> InfoList;
43
44public:
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
160private:
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
175class VirtualDirectoryManager::RootInfo {
176public:
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
291private:
292	typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap;
293
294private:
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
307VirtualDirectoryManager::VirtualDirectoryManager()
308	:
309	fLock("virtual directory manager")
310{
311}
312
313
314/*static*/ VirtualDirectoryManager*
315VirtualDirectoryManager::Instance()
316{
317	static VirtualDirectoryManager* manager
318		= new(std::nothrow) VirtualDirectoryManager;
319	return manager;
320}
321
322
323status_t
324VirtualDirectoryManager::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
363bool
364VirtualDirectoryManager::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
376bool
377VirtualDirectoryManager::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
389bool
390VirtualDirectoryManager::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
408bool
409VirtualDirectoryManager::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
427status_t
428VirtualDirectoryManager::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
448status_t
449VirtualDirectoryManager::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
544bool
545VirtualDirectoryManager::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
558status_t
559VirtualDirectoryManager::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
578VirtualDirectoryManager::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
603VirtualDirectoryManager::Info*
604VirtualDirectoryManager::_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
611bool
612VirtualDirectoryManager::_AddInfo(Info* info)
613{
614	try {
615		fInfos[info->DefinitionFileNodeRef()] = info;
616		return true;
617	} catch (...) {
618		return false;
619	}
620}
621
622
623void
624VirtualDirectoryManager::_RemoveInfo(Info* info)
625{
626	NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef());
627	if (it != fInfos.end())
628		fInfos.erase(it);
629}
630
631
632void
633VirtualDirectoryManager::_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
649void
650VirtualDirectoryManager::_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
669void
670VirtualDirectoryManager::_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
691status_t
692VirtualDirectoryManager::_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
769status_t
770VirtualDirectoryManager::_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
795status_t
796VirtualDirectoryManager::_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