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