xref: /haiku/src/system/boot/loader/file_systems/packagefs/packagefs.cpp (revision 991dadd6324f7b7a68e94743a39ebae789823228)
1 /*
2  * Copyright 2011-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "packagefs.h"
8 
9 #include <errno.h>
10 #include <unistd.h>
11 
12 #include <package/hpkg/DataReader.h>
13 #include <package/hpkg/ErrorOutput.h>
14 #include <package/hpkg/PackageDataReader.h>
15 #include <package/hpkg/PackageEntry.h>
16 #include <package/hpkg/PackageEntryAttribute.h>
17 #include <package/hpkg/PackageFileHeapReader.h>
18 #include <package/hpkg/PackageReaderImpl.h>
19 
20 #include <AutoDeleter.h>
21 
22 #include <util/DoublyLinkedList.h>
23 
24 #include <Referenceable.h>
25 
26 #include <boot/PathBlacklist.h>
27 #include <boot/platform.h>
28 
29 #include "PackageSettingsItem.h"
30 
31 
32 #if 0
33 #	define RETURN_ERROR(error) return (error);
34 #else
35 #	define RETURN_ERROR(err)												\
36 	{																		\
37 		status_t _status = err;												\
38 		if (_status < B_OK)													\
39 			dprintf("%s:%d: %s\n", __FILE__, __LINE__, strerror(_status));	\
40 		return _status;														\
41 	}
42 #endif
43 
44 
45 using namespace BPackageKit;
46 using namespace BPackageKit::BHPKG;
47 using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
48 using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
49 
50 using namespace PackageFS;
51 
52 
53 namespace PackageFS {
54 
55 
56 struct PackageDirectory;
57 struct PackageNode;
58 struct PackageVolume;
59 
60 
61 static status_t create_node(PackageNode* packageNode, ::Node*& _node);
62 
63 
64 // #pragma mark - PackageNode
65 
66 
67 struct PackageNode : DoublyLinkedListLinkImpl<PackageNode> {
68 	PackageNode(PackageVolume* volume, mode_t mode)
69 		:
70 		fVolume(volume),
71 		fParentDirectory(NULL),
72 		fName(NULL),
73 		fNodeID(0),
74 		fMode(mode)
75 	{
76 		fModifiedTime.tv_sec = 0;
77 		fModifiedTime.tv_nsec = 0;
78 	}
79 
80 	virtual ~PackageNode()
81 	{
82 		free(fName);
83 	}
84 
85 	status_t Init(PackageDirectory* parentDir, const char* name, ino_t nodeID)
86 	{
87 		fParentDirectory = parentDir;
88 		fName = strdup(name);
89 		fNodeID = nodeID;
90 
91 		return fName != NULL ? B_OK : B_NO_MEMORY;
92 	}
93 
94 	PackageVolume* Volume() const
95 	{
96 		return fVolume;
97 	}
98 
99 	const char* Name() const
100 	{
101 		return fName;
102 	}
103 
104 	ino_t NodeID() const
105 	{
106 		return fNodeID;
107 	}
108 
109 	mode_t Mode() const
110 	{
111 		return fMode;
112 	}
113 
114 	void SetModifiedTime(const timespec& time)
115 	{
116 		fModifiedTime = time;
117 	}
118 
119 	const timespec& ModifiedTime() const
120 	{
121 		return fModifiedTime;
122 	}
123 
124 	virtual void RemoveEntry(const char* path)
125 	{
126 	}
127 
128 protected:
129 	PackageVolume*		fVolume;
130 	PackageDirectory*	fParentDirectory;
131 	char*				fName;
132 	ino_t				fNodeID;
133 	mode_t				fMode;
134 	timespec			fModifiedTime;
135 };
136 
137 
138 // #pragma mark - PackageFile
139 
140 
141 struct PackageFile : PackageNode {
142 	PackageFile(PackageVolume* volume, mode_t mode, const BPackageData& data)
143 		:
144 		PackageNode(volume, mode),
145 		fData(data)
146 	{
147 	}
148 
149 	const BPackageData& Data() const
150 	{
151 		return fData;
152 	}
153 
154 	off_t Size() const
155 	{
156 		return fData.Size();
157 	}
158 
159 private:
160 	BPackageData	fData;
161 };
162 
163 
164 // #pragma mark - PackageSymlink
165 
166 
167 struct PackageSymlink : PackageNode {
168 	PackageSymlink(PackageVolume* volume, mode_t mode)
169 		:
170 		PackageNode(volume, mode),
171 		fPath(NULL)
172 	{
173 	}
174 
175 	~PackageSymlink()
176 	{
177 		free(fPath);
178 	}
179 
180 	status_t SetSymlinkPath(const char* path)
181 	{
182 		fPath = strdup(path);
183 		return fPath != NULL ? B_OK : B_NO_MEMORY;
184 	}
185 
186 	const char* SymlinkPath() const
187 	{
188 		return fPath;
189 	}
190 
191 private:
192 	char*	fPath;
193 };
194 
195 
196 // #pragma mark - PackageDirectory
197 
198 
199 struct PackageDirectory : PackageNode {
200 	PackageDirectory(PackageVolume* volume, mode_t mode)
201 		:
202 		PackageNode(volume, mode)
203 	{
204 	}
205 
206 	~PackageDirectory()
207 	{
208 		while (PackageNode* node = fEntries.RemoveHead())
209 			delete node;
210 	}
211 
212 	void AddChild(PackageNode* node)
213 	{
214 		fEntries.Add(node);
215 	}
216 
217 	PackageNode* FirstChild() const
218 	{
219 		return fEntries.Head();
220 	}
221 
222 	PackageNode* NextChild(PackageNode* child) const
223 	{
224 		return fEntries.GetNext(child);
225 	}
226 
227 	PackageNode* Lookup(const char* name)
228 	{
229 		if (strcmp(name, ".") == 0)
230 			return this;
231 		if (strcmp(name, "..") == 0)
232 			return fParentDirectory;
233 
234 		return _LookupChild(name, strlen(name));
235 	}
236 
237 	virtual void RemoveEntry(const char* path)
238 	{
239 		const char* componentEnd = strchr(path, '/');
240 		if (componentEnd == NULL)
241 			componentEnd = path + strlen(path);
242 
243 		PackageNode* child = _LookupChild(path, componentEnd - path);
244 		if (child == NULL)
245 			return;
246 
247 		if (*componentEnd == '\0') {
248 			// last path component -- delete the child
249 			fEntries.Remove(child);
250 			delete child;
251 		} else {
252 			// must be a directory component -- continue resolving the path
253 			child->RemoveEntry(componentEnd + 1);
254 		}
255 	}
256 
257 private:
258 	typedef DoublyLinkedList<PackageNode>	NodeList;
259 
260 private:
261 	PackageNode* _LookupChild(const char* name, size_t nameLength)
262 	{
263 		for (NodeList::Iterator it = fEntries.GetIterator();
264 				PackageNode* child = it.Next();) {
265 			if (strncmp(child->Name(), name, nameLength) == 0
266 				&& child->Name()[nameLength] == '\0') {
267 				return child;
268 			}
269 		}
270 
271 		return NULL;
272 	}
273 
274 private:
275 	NodeList	fEntries;
276 };
277 
278 
279 // #pragma mark - PackageLoaderErrorOutput
280 
281 
282 struct PackageLoaderErrorOutput : BErrorOutput {
283 	PackageLoaderErrorOutput()
284 	{
285 	}
286 
287 	virtual void PrintErrorVarArgs(const char* format, va_list args)
288 	{
289 	}
290 };
291 
292 
293 // #pragma mark - PackageVolume
294 
295 
296 struct PackageVolume : BReferenceable, private PackageLoaderErrorOutput {
297 	PackageVolume()
298 		:
299 		fNextNodeID(1),
300 		fRootDirectory(this, S_IFDIR),
301 		fHeapReader(NULL),
302 		fFD(-1)
303 	{
304 	}
305 
306 	~PackageVolume()
307 	{
308 		delete fHeapReader;
309 
310 		if (fFD >= 0)
311 			close(fFD);
312 	}
313 
314 	status_t Init(int fd, const PackageFileHeapReader* heapReader)
315 	{
316 		status_t error = fRootDirectory.Init(&fRootDirectory, ".",
317 			NextNodeID());
318 		if (error != B_OK)
319 			return error;
320 
321 		fFD = dup(fd);
322 		if (fFD < 0)
323 			return errno;
324 
325 		// clone a heap reader and adjust it for our use
326 		fHeapReader = heapReader->Clone();
327 		if (fHeapReader == NULL)
328 			return B_NO_MEMORY;
329 
330 		fHeapReader->SetErrorOutput(this);
331 		fHeapReader->SetFD(fFD);
332 
333 		return B_OK;
334 	}
335 
336 	PackageDirectory* RootDirectory()
337 	{
338 		return &fRootDirectory;
339 	}
340 
341 	ino_t NextNodeID()
342 	{
343 		return fNextNodeID++;
344 	}
345 
346 	status_t CreateFileDataReader(const BPackageData& data,
347 		BAbstractBufferedDataReader*& _reader)
348 	{
349 		return BPackageDataReaderFactory().CreatePackageDataReader(fHeapReader,
350 			data, _reader);
351 	}
352 
353 private:
354 	ino_t						fNextNodeID;
355 	PackageDirectory			fRootDirectory;
356 	PackageFileHeapReader*		fHeapReader;
357 	int							fFD;
358 };
359 
360 
361 // #pragma mark - PackageLoaderContentHandler
362 
363 
364 struct PackageLoaderContentHandler : BPackageContentHandler {
365 	PackageLoaderContentHandler(PackageVolume* volume,
366 		PackageSettingsItem* settingsItem)
367 		:
368 		fVolume(volume),
369 		fSettingsItem(settingsItem),
370 		fLastSettingsEntry(NULL),
371 		fLastSettingsEntryEntry(NULL),
372 		fErrorOccurred(false)
373 	{
374 	}
375 
376 	status_t Init()
377 	{
378 		return B_OK;
379 	}
380 
381 	virtual status_t HandleEntry(BPackageEntry* entry)
382 	{
383 		if (fErrorOccurred
384 			|| (fLastSettingsEntry != NULL
385 				&& fLastSettingsEntry->IsBlackListed())) {
386 			return B_OK;
387 		}
388 
389 		PackageDirectory* parentDir = NULL;
390 		if (const BPackageEntry* parentEntry = entry->Parent()) {
391 			if (!S_ISDIR(parentEntry->Mode()))
392 				RETURN_ERROR(B_BAD_DATA);
393 
394 			parentDir = static_cast<PackageDirectory*>(
395 				(PackageNode*)parentEntry->UserToken());
396 		}
397 
398 		if (fSettingsItem != NULL
399 			&& (parentDir == NULL
400 				|| entry->Parent() == fLastSettingsEntryEntry)) {
401 			PackageSettingsItem::Entry* settingsEntry
402 				= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
403 			if (settingsEntry != NULL) {
404 				fLastSettingsEntry = settingsEntry;
405 				fLastSettingsEntryEntry = entry;
406 				if (fLastSettingsEntry->IsBlackListed())
407 					return B_OK;
408 			}
409 		}
410 
411 		if (parentDir == NULL)
412 			parentDir = fVolume->RootDirectory();
413 
414 		status_t error;
415 
416 		// get the file mode -- filter out write permissions
417 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
418 
419 		// create the package node
420 		PackageNode* node;
421 		if (S_ISREG(mode)) {
422 			// file
423 			node = new(std::nothrow) PackageFile(fVolume, mode, entry->Data());
424 		} else if (S_ISLNK(mode)) {
425 			// symlink
426 			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
427 				fVolume, mode);
428 			if (symlink == NULL)
429 				RETURN_ERROR(B_NO_MEMORY);
430 
431 			error = symlink->SetSymlinkPath(entry->SymlinkPath());
432 			if (error != B_OK) {
433 				delete symlink;
434 				return error;
435 			}
436 
437 			node = symlink;
438 		} else if (S_ISDIR(mode)) {
439 			// directory
440 			node = new(std::nothrow) PackageDirectory(fVolume, mode);
441 		} else
442 			RETURN_ERROR(B_BAD_DATA);
443 
444 		if (node == NULL)
445 			RETURN_ERROR(B_NO_MEMORY);
446 
447 		error = node->Init(parentDir, entry->Name(), fVolume->NextNodeID());
448 		if (error != B_OK) {
449 			delete node;
450 			RETURN_ERROR(error);
451 		}
452 
453 		node->SetModifiedTime(entry->ModifiedTime());
454 
455 		// add it to the parent directory
456 		parentDir->AddChild(node);
457 
458 		entry->SetUserToken(node);
459 
460 		return B_OK;
461 	}
462 
463 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
464 		BPackageEntryAttribute* attribute)
465 	{
466 		// attributes aren't needed in the boot loader
467 		return B_OK;
468 	}
469 
470 	virtual status_t HandleEntryDone(BPackageEntry* entry)
471 	{
472 		if (entry == fLastSettingsEntryEntry) {
473 			fLastSettingsEntryEntry = entry->Parent();
474 			fLastSettingsEntry = fLastSettingsEntry->Parent();
475 		}
476 
477 		return B_OK;
478 	}
479 
480 	virtual status_t HandlePackageAttribute(
481 		const BPackageInfoAttributeValue& value)
482 	{
483 		// TODO?
484 		return B_OK;
485 	}
486 
487 	virtual void HandleErrorOccurred()
488 	{
489 		fErrorOccurred = true;
490 	}
491 
492 private:
493 	PackageVolume*				fVolume;
494 	const PackageSettingsItem*	fSettingsItem;
495 	PackageSettingsItem::Entry*	fLastSettingsEntry;
496 	const BPackageEntry*		fLastSettingsEntryEntry;
497 	bool						fErrorOccurred;
498 };
499 
500 
501 // #pragma mark - File
502 
503 
504 struct File : ::Node {
505 	File(PackageFile* file)
506 		:
507 		fFile(file)
508 	{
509 		fFile->Volume()->AcquireReference();
510 	}
511 
512 	~File()
513 	{
514 		fFile->Volume()->ReleaseReference();
515 	}
516 
517 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
518 		size_t bufferSize)
519 	{
520 		off_t size = fFile->Size();
521 		if (pos < 0 || pos > size)
522 			return B_BAD_VALUE;
523 		if (pos + bufferSize > size)
524 			bufferSize = size - pos;
525 
526 		if (bufferSize > 0) {
527 			BAbstractBufferedDataReader* dataReader
528 				= (BAbstractBufferedDataReader*)cookie;
529 			status_t error = dataReader->ReadData(pos, buffer, bufferSize);
530 			if (error != B_OK)
531 				return error;
532 		}
533 
534 		return bufferSize;
535 	}
536 
537 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
538 		size_t bufferSize)
539 	{
540 		return B_READ_ONLY_DEVICE;
541 	}
542 
543 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
544 	{
545 		strlcpy(nameBuffer, fFile->Name(), bufferSize);
546 		return B_OK;
547 	}
548 
549 	virtual status_t Open(void** _cookie, int mode)
550 	{
551 		if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
552 			return B_NOT_ALLOWED;
553 
554 		BAbstractBufferedDataReader* dataReader;
555 		status_t error = fFile->Volume()->CreateFileDataReader(fFile->Data(),
556 			dataReader);
557 		if (error != B_OK)
558 			return error;
559 
560 		*_cookie = dataReader;
561 		Acquire();
562 		return B_OK;
563 	}
564 
565 	virtual status_t Close(void* cookie)
566 	{
567 		BAbstractBufferedDataReader* dataReader
568 			= (BAbstractBufferedDataReader*)cookie;
569 		delete dataReader;
570 		Release();
571 		return B_OK;
572 	}
573 
574 
575 	virtual int32 Type() const
576 	{
577 		return fFile->Mode() & S_IFMT;
578 	}
579 
580 	virtual off_t Size() const
581 	{
582 		return fFile->Size();
583 	}
584 
585 	virtual ino_t Inode() const
586 	{
587 		return fFile->NodeID();
588 	}
589 
590 private:
591 	PackageFile*	fFile;
592 };
593 
594 
595 // #pragma mark - Symlink
596 
597 
598 struct Symlink : ::Node {
599 	Symlink(PackageSymlink* symlink)
600 		:
601 		fSymlink(symlink)
602 	{
603 		fSymlink->Volume()->AcquireReference();
604 	}
605 
606 	~Symlink()
607 	{
608 		fSymlink->Volume()->ReleaseReference();
609 	}
610 
611 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
612 		size_t bufferSize)
613 	{
614 		return B_BAD_VALUE;
615 	}
616 
617 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
618 		size_t bufferSize)
619 	{
620 		return B_READ_ONLY_DEVICE;
621 	}
622 
623 	virtual status_t ReadLink(char* buffer, size_t bufferSize)
624 	{
625 		const char* path = fSymlink->SymlinkPath();
626 		size_t size = strlen(path) + 1;
627 
628 		if (size > bufferSize)
629 			return B_BUFFER_OVERFLOW;
630 
631 		memcpy(buffer, path, size);
632 		return B_OK;
633 	}
634 
635 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
636 	{
637 		strlcpy(nameBuffer, fSymlink->Name(), bufferSize);
638 		return B_OK;
639 	}
640 
641 	virtual int32 Type() const
642 	{
643 		return fSymlink->Mode() & S_IFMT;
644 	}
645 
646 	virtual off_t Size() const
647 	{
648 		return strlen(fSymlink->SymlinkPath()) + 1;
649 	}
650 
651 	virtual ino_t Inode() const
652 	{
653 		return fSymlink->NodeID();
654 	}
655 
656 private:
657 	PackageSymlink*	fSymlink;
658 };
659 
660 
661 // #pragma mark - Directory
662 
663 
664 struct Directory : ::Directory {
665 	Directory(PackageDirectory* symlink)
666 		:
667 		fDirectory(symlink)
668 	{
669 		fDirectory->Volume()->AcquireReference();
670 	}
671 
672 	~Directory()
673 	{
674 		fDirectory->Volume()->ReleaseReference();
675 	}
676 
677 	void RemoveEntry(const char* path)
678 	{
679 		fDirectory->RemoveEntry(path);
680 	}
681 
682 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
683 		size_t bufferSize)
684 	{
685 		return B_IS_A_DIRECTORY;
686 	}
687 
688 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
689 		size_t bufferSize)
690 	{
691 		return B_IS_A_DIRECTORY;
692 	}
693 
694 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
695 	{
696 		strlcpy(nameBuffer, fDirectory->Name(), bufferSize);
697 		return B_OK;
698 	}
699 
700 	virtual int32 Type() const
701 	{
702 		return fDirectory->Mode() & S_IFMT;
703 	}
704 
705 	virtual ino_t Inode() const
706 	{
707 		return fDirectory->NodeID();
708 	}
709 
710 	virtual status_t Open(void** _cookie, int mode)
711 	{
712 		if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
713 			return B_NOT_ALLOWED;
714 
715 		Cookie* cookie = new(std::nothrow) Cookie;
716 		if (cookie == NULL)
717 			return B_NO_MEMORY;
718 
719 		cookie->nextChild = fDirectory->FirstChild();
720 
721 		Acquire();
722 		*_cookie = cookie;
723 		return B_OK;
724 	}
725 
726 	virtual status_t Close(void* _cookie)
727 	{
728 		Cookie* cookie = (Cookie*)_cookie;
729 		delete cookie;
730 		Release();
731 		return B_OK;
732 	}
733 
734 	virtual Node* LookupDontTraverse(const char* name)
735 	{
736 		// look up the child
737 		PackageNode* child = fDirectory->Lookup(name);
738 		if (child == NULL)
739 			return NULL;
740 
741 		// create the node
742 		::Node* node;
743 		return create_node(child, node) == B_OK ? node : NULL;
744 	}
745 
746 	virtual status_t GetNextEntry(void* _cookie, char* nameBuffer,
747 		size_t bufferSize)
748 	{
749 		Cookie* cookie = (Cookie*)_cookie;
750 		PackageNode* child = cookie->nextChild;
751 		if (child == NULL)
752 			return B_ENTRY_NOT_FOUND;
753 
754 		cookie->nextChild = fDirectory->NextChild(child);
755 
756 		strlcpy(nameBuffer, child->Name(), bufferSize);
757 		return B_OK;
758 	}
759 
760 	virtual status_t GetNextNode(void* _cookie, Node** _node)
761 	{
762 		Cookie* cookie = (Cookie*)_cookie;
763 		PackageNode* child = cookie->nextChild;
764 		if (child == NULL)
765 			return B_ENTRY_NOT_FOUND;
766 
767 		cookie->nextChild = fDirectory->NextChild(child);
768 
769 		return create_node(child, *_node);
770 	}
771 
772 	virtual status_t Rewind(void* _cookie)
773 	{
774 		Cookie* cookie = (Cookie*)_cookie;
775 		cookie->nextChild = NULL;
776 		return B_OK;
777 	}
778 
779 	virtual bool IsEmpty()
780 	{
781 		return fDirectory->FirstChild() == NULL;
782 	}
783 
784 private:
785 	struct Cookie {
786 		PackageNode*	nextChild;
787 	};
788 
789 
790 private:
791 	PackageDirectory*	fDirectory;
792 };
793 
794 
795 // #pragma mark -
796 
797 
798 static status_t
799 create_node(PackageNode* packageNode, ::Node*& _node)
800 {
801 	if (packageNode == NULL)
802 		return B_BAD_VALUE;
803 
804 	::Node* node;
805 	switch (packageNode->Mode() & S_IFMT) {
806 		case S_IFREG:
807 			node = new(std::nothrow) File(
808 				static_cast<PackageFile*>(packageNode));
809 			break;
810 		case S_IFLNK:
811 			node = new(std::nothrow) Symlink(
812 				static_cast<PackageSymlink*>(packageNode));
813 			break;
814 		case S_IFDIR:
815 			node = new(std::nothrow) Directory(
816 				static_cast<PackageDirectory*>(packageNode));
817 			break;
818 		default:
819 			return B_BAD_VALUE;
820 	}
821 
822 	if (node == NULL)
823 		return B_NO_MEMORY;
824 
825 	_node = node;
826 	return B_OK;
827 }
828 
829 
830 }	// namespace PackageFS
831 
832 
833 status_t
834 packagefs_mount_file(int fd, ::Directory* systemDirectory,
835 	::Directory*& _mountedDirectory)
836 {
837 	PackageLoaderErrorOutput errorOutput;
838  	PackageReaderImpl packageReader(&errorOutput);
839 	status_t error = packageReader.Init(fd, false, 0);
840  	if (error != B_OK)
841  		RETURN_ERROR(error);
842 
843 	// create the volume
844 	PackageVolume* volume = new(std::nothrow) PackageVolume;
845 	if (volume == NULL)
846 		return B_NO_MEMORY;
847 	BReference<PackageVolume> volumeReference(volume, true);
848 
849 	error = volume->Init(fd, packageReader.RawHeapReader());
850 	if (error != B_OK)
851 		RETURN_ERROR(error);
852 
853 	// load settings for the package
854 	PackageSettingsItem* settings = PackageSettingsItem::Load(systemDirectory,
855 		"haiku");
856 	ObjectDeleter<PackageSettingsItem> settingsDeleter(settings);
857 
858 	// parse content -- this constructs the entry/node tree
859 	PackageLoaderContentHandler handler(volume, settings);
860 	error = handler.Init();
861 	if (error != B_OK)
862 		RETURN_ERROR(error);
863 
864 	error = packageReader.ParseContent(&handler);
865 	if (error != B_OK)
866 		RETURN_ERROR(error);
867 
868 	// create a VFS node for the root node
869 	::Node* rootNode;
870 	error = create_node(volume->RootDirectory(), rootNode);
871 	if (error != B_OK)
872 		RETURN_ERROR(error);
873 
874 	_mountedDirectory = static_cast< ::Directory*>(rootNode);
875 	return B_OK;
876 }
877 
878 
879 void
880 packagefs_apply_path_blacklist(::Directory* systemDirectory,
881 	const PathBlacklist& pathBlacklist)
882 {
883 	PackageFS::Directory* directory
884 		= static_cast<PackageFS::Directory*>(systemDirectory);
885 
886 	for (PathBlacklist::Iterator it = pathBlacklist.GetIterator();
887 		BlacklistedPath* path = it.Next();) {
888 		directory->RemoveEntry(path->Path());
889 	}
890 }
891 
892