xref: /haiku/src/system/boot/loader/file_systems/packagefs/packagefs.cpp (revision 3af8011358bd4c624a0979336d48dabb466171ed)
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/PathBlocklist.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 		char buffer[256];
291 		vsnprintf(buffer, sizeof(buffer), format, args);
292 		dprintf("%s", buffer);
293 	}
294 };
295 
296 
297 // #pragma mark - PackageVolume
298 
299 
300 struct PackageVolume : BReferenceable, private PackageLoaderErrorOutput {
301 	PackageVolume()
302 		:
303 		fNextNodeID(1),
304 		fRootDirectory(this, S_IFDIR),
305 		fHeapReader(NULL),
306 		fFile(NULL)
307 	{
308 	}
309 
310 	~PackageVolume()
311 	{
312 		delete fHeapReader;
313 		delete fFile;
314 	}
315 
316 	status_t Init(int fd, const PackageFileHeapReader* heapReader)
317 	{
318 		status_t error = fRootDirectory.Init(&fRootDirectory, ".",
319 			NextNodeID());
320 		if (error != B_OK)
321 			return error;
322 
323 		fd = dup(fd);
324 		if (fd < 0)
325 			return errno;
326 
327 		fFile = new(std::nothrow) BFdIO(fd, true);
328 		if (fFile == NULL) {
329 			close(fd);
330 			return B_NO_MEMORY;
331 		}
332 
333 		// clone a heap reader and adjust it for our use
334 		fHeapReader = heapReader->Clone();
335 		if (fHeapReader == NULL)
336 			return B_NO_MEMORY;
337 
338 		fHeapReader->SetErrorOutput(this);
339 		fHeapReader->SetFile(fFile);
340 
341 		return B_OK;
342 	}
343 
344 	PackageDirectory* RootDirectory()
345 	{
346 		return &fRootDirectory;
347 	}
348 
349 	ino_t NextNodeID()
350 	{
351 		return fNextNodeID++;
352 	}
353 
354 	status_t CreateFileDataReader(const BPackageData& data,
355 		BAbstractBufferedDataReader*& _reader)
356 	{
357 		return BPackageDataReaderFactory().CreatePackageDataReader(fHeapReader,
358 			data, _reader);
359 	}
360 
361 private:
362 	ino_t						fNextNodeID;
363 	PackageDirectory			fRootDirectory;
364 	PackageFileHeapReader*		fHeapReader;
365 	BPositionIO*				fFile;
366 };
367 
368 
369 // #pragma mark - PackageLoaderContentHandler
370 
371 
372 struct PackageLoaderContentHandler : BPackageContentHandler {
373 	PackageLoaderContentHandler(PackageVolume* volume,
374 		PackageSettingsItem* settingsItem)
375 		:
376 		fVolume(volume),
377 		fSettingsItem(settingsItem),
378 		fLastSettingsEntry(NULL),
379 		fLastSettingsEntryEntry(NULL),
380 		fErrorOccurred(false)
381 	{
382 	}
383 
384 	status_t Init()
385 	{
386 		return B_OK;
387 	}
388 
389 	virtual status_t HandleEntry(BPackageEntry* entry)
390 	{
391 		if (fErrorOccurred
392 			|| (fLastSettingsEntry != NULL
393 				&& fLastSettingsEntry->IsBlocked())) {
394 			return B_OK;
395 		}
396 
397 		PackageDirectory* parentDir = NULL;
398 		if (const BPackageEntry* parentEntry = entry->Parent()) {
399 			if (!S_ISDIR(parentEntry->Mode()))
400 				RETURN_ERROR(B_BAD_DATA);
401 
402 			parentDir = static_cast<PackageDirectory*>(
403 				(PackageNode*)parentEntry->UserToken());
404 		}
405 
406 		if (fSettingsItem != NULL
407 			&& (parentDir == NULL
408 				|| entry->Parent() == fLastSettingsEntryEntry)) {
409 			PackageSettingsItem::Entry* settingsEntry
410 				= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
411 			if (settingsEntry != NULL) {
412 				fLastSettingsEntry = settingsEntry;
413 				fLastSettingsEntryEntry = entry;
414 				if (fLastSettingsEntry->IsBlocked())
415 					return B_OK;
416 			}
417 		}
418 
419 		if (parentDir == NULL)
420 			parentDir = fVolume->RootDirectory();
421 
422 		status_t error;
423 
424 		// get the file mode -- filter out write permissions
425 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
426 
427 		// create the package node
428 		PackageNode* node;
429 		if (S_ISREG(mode)) {
430 			// file
431 			node = new(std::nothrow) PackageFile(fVolume, mode, entry->Data());
432 		} else if (S_ISLNK(mode)) {
433 			// symlink
434 			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
435 				fVolume, mode);
436 			if (symlink == NULL)
437 				RETURN_ERROR(B_NO_MEMORY);
438 
439 			error = symlink->SetSymlinkPath(entry->SymlinkPath());
440 			if (error != B_OK) {
441 				delete symlink;
442 				return error;
443 			}
444 
445 			node = symlink;
446 		} else if (S_ISDIR(mode)) {
447 			// directory
448 			node = new(std::nothrow) PackageDirectory(fVolume, mode);
449 		} else
450 			RETURN_ERROR(B_BAD_DATA);
451 
452 		if (node == NULL)
453 			RETURN_ERROR(B_NO_MEMORY);
454 
455 		error = node->Init(parentDir, entry->Name(), fVolume->NextNodeID());
456 		if (error != B_OK) {
457 			delete node;
458 			RETURN_ERROR(error);
459 		}
460 
461 		node->SetModifiedTime(entry->ModifiedTime());
462 
463 		// add it to the parent directory
464 		parentDir->AddChild(node);
465 
466 		entry->SetUserToken(node);
467 
468 		return B_OK;
469 	}
470 
471 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
472 		BPackageEntryAttribute* attribute)
473 	{
474 		// attributes aren't needed in the boot loader
475 		return B_OK;
476 	}
477 
478 	virtual status_t HandleEntryDone(BPackageEntry* entry)
479 	{
480 		if (entry == fLastSettingsEntryEntry) {
481 			fLastSettingsEntryEntry = entry->Parent();
482 			fLastSettingsEntry = fLastSettingsEntry->Parent();
483 		}
484 
485 		return B_OK;
486 	}
487 
488 	virtual status_t HandlePackageAttribute(
489 		const BPackageInfoAttributeValue& value)
490 	{
491 		// TODO?
492 		return B_OK;
493 	}
494 
495 	virtual void HandleErrorOccurred()
496 	{
497 		fErrorOccurred = true;
498 	}
499 
500 private:
501 	PackageVolume*				fVolume;
502 	const PackageSettingsItem*	fSettingsItem;
503 	PackageSettingsItem::Entry*	fLastSettingsEntry;
504 	const BPackageEntry*		fLastSettingsEntryEntry;
505 	bool						fErrorOccurred;
506 };
507 
508 
509 // #pragma mark - File
510 
511 
512 struct File : ::Node {
513 	File(PackageFile* file)
514 		:
515 		fFile(file)
516 	{
517 		fFile->Volume()->AcquireReference();
518 	}
519 
520 	~File()
521 	{
522 		fFile->Volume()->ReleaseReference();
523 	}
524 
525 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
526 		size_t bufferSize)
527 	{
528 		off_t size = fFile->Size();
529 		if (pos < 0 || pos > size)
530 			return B_BAD_VALUE;
531 		if (pos + (off_t)bufferSize > size)
532 			bufferSize = size - pos;
533 
534 		if (bufferSize > 0) {
535 			BAbstractBufferedDataReader* dataReader
536 				= (BAbstractBufferedDataReader*)cookie;
537 			status_t error = dataReader->ReadData(pos, buffer, bufferSize);
538 			if (error != B_OK)
539 				return error;
540 		}
541 
542 		return bufferSize;
543 	}
544 
545 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
546 		size_t bufferSize)
547 	{
548 		return B_READ_ONLY_DEVICE;
549 	}
550 
551 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
552 	{
553 		strlcpy(nameBuffer, fFile->Name(), bufferSize);
554 		return B_OK;
555 	}
556 
557 	virtual status_t Open(void** _cookie, int mode)
558 	{
559 		if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
560 			return B_NOT_ALLOWED;
561 
562 		BAbstractBufferedDataReader* dataReader;
563 		status_t error = fFile->Volume()->CreateFileDataReader(fFile->Data(),
564 			dataReader);
565 		if (error != B_OK)
566 			return error;
567 
568 		*_cookie = dataReader;
569 		Acquire();
570 		return B_OK;
571 	}
572 
573 	virtual status_t Close(void* cookie)
574 	{
575 		BAbstractBufferedDataReader* dataReader
576 			= (BAbstractBufferedDataReader*)cookie;
577 		delete dataReader;
578 		Release();
579 		return B_OK;
580 	}
581 
582 
583 	virtual int32 Type() const
584 	{
585 		return fFile->Mode() & S_IFMT;
586 	}
587 
588 	virtual off_t Size() const
589 	{
590 		return fFile->Size();
591 	}
592 
593 	virtual ino_t Inode() const
594 	{
595 		return fFile->NodeID();
596 	}
597 
598 private:
599 	PackageFile*	fFile;
600 };
601 
602 
603 // #pragma mark - Symlink
604 
605 
606 struct Symlink : ::Node {
607 	Symlink(PackageSymlink* symlink)
608 		:
609 		fSymlink(symlink)
610 	{
611 		fSymlink->Volume()->AcquireReference();
612 	}
613 
614 	~Symlink()
615 	{
616 		fSymlink->Volume()->ReleaseReference();
617 	}
618 
619 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
620 		size_t bufferSize)
621 	{
622 		return B_BAD_VALUE;
623 	}
624 
625 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
626 		size_t bufferSize)
627 	{
628 		return B_READ_ONLY_DEVICE;
629 	}
630 
631 	virtual status_t ReadLink(char* buffer, size_t bufferSize)
632 	{
633 		const char* path = fSymlink->SymlinkPath();
634 		size_t size = strlen(path) + 1;
635 
636 		if (size > bufferSize)
637 			return B_BUFFER_OVERFLOW;
638 
639 		memcpy(buffer, path, size);
640 		return B_OK;
641 	}
642 
643 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
644 	{
645 		strlcpy(nameBuffer, fSymlink->Name(), bufferSize);
646 		return B_OK;
647 	}
648 
649 	virtual int32 Type() const
650 	{
651 		return fSymlink->Mode() & S_IFMT;
652 	}
653 
654 	virtual off_t Size() const
655 	{
656 		return strlen(fSymlink->SymlinkPath()) + 1;
657 	}
658 
659 	virtual ino_t Inode() const
660 	{
661 		return fSymlink->NodeID();
662 	}
663 
664 private:
665 	PackageSymlink*	fSymlink;
666 };
667 
668 
669 // #pragma mark - Directory
670 
671 
672 struct Directory : ::Directory {
673 	Directory(PackageDirectory* symlink)
674 		:
675 		fDirectory(symlink)
676 	{
677 		fDirectory->Volume()->AcquireReference();
678 	}
679 
680 	~Directory()
681 	{
682 		fDirectory->Volume()->ReleaseReference();
683 	}
684 
685 	void RemoveEntry(const char* path)
686 	{
687 		fDirectory->RemoveEntry(path);
688 	}
689 
690 	virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
691 		size_t bufferSize)
692 	{
693 		return B_IS_A_DIRECTORY;
694 	}
695 
696 	virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
697 		size_t bufferSize)
698 	{
699 		return B_IS_A_DIRECTORY;
700 	}
701 
702 	virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
703 	{
704 		strlcpy(nameBuffer, fDirectory->Name(), bufferSize);
705 		return B_OK;
706 	}
707 
708 	virtual int32 Type() const
709 	{
710 		return fDirectory->Mode() & S_IFMT;
711 	}
712 
713 	virtual ino_t Inode() const
714 	{
715 		return fDirectory->NodeID();
716 	}
717 
718 	virtual status_t Open(void** _cookie, int mode)
719 	{
720 		if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
721 			return B_NOT_ALLOWED;
722 
723 		Cookie* cookie = new(std::nothrow) Cookie;
724 		if (cookie == NULL)
725 			return B_NO_MEMORY;
726 
727 		cookie->nextChild = fDirectory->FirstChild();
728 
729 		Acquire();
730 		*_cookie = cookie;
731 		return B_OK;
732 	}
733 
734 	virtual status_t Close(void* _cookie)
735 	{
736 		Cookie* cookie = (Cookie*)_cookie;
737 		delete cookie;
738 		Release();
739 		return B_OK;
740 	}
741 
742 	virtual Node* LookupDontTraverse(const char* name)
743 	{
744 		// look up the child
745 		PackageNode* child = fDirectory->Lookup(name);
746 		if (child == NULL)
747 			return NULL;
748 
749 		// create the node
750 		::Node* node;
751 		return create_node(child, node) == B_OK ? node : NULL;
752 	}
753 
754 	virtual status_t GetNextEntry(void* _cookie, char* nameBuffer,
755 		size_t bufferSize)
756 	{
757 		Cookie* cookie = (Cookie*)_cookie;
758 		PackageNode* child = cookie->nextChild;
759 		if (child == NULL)
760 			return B_ENTRY_NOT_FOUND;
761 
762 		cookie->nextChild = fDirectory->NextChild(child);
763 
764 		strlcpy(nameBuffer, child->Name(), bufferSize);
765 		return B_OK;
766 	}
767 
768 	virtual status_t GetNextNode(void* _cookie, Node** _node)
769 	{
770 		Cookie* cookie = (Cookie*)_cookie;
771 		PackageNode* child = cookie->nextChild;
772 		if (child == NULL)
773 			return B_ENTRY_NOT_FOUND;
774 
775 		cookie->nextChild = fDirectory->NextChild(child);
776 
777 		return create_node(child, *_node);
778 	}
779 
780 	virtual status_t Rewind(void* _cookie)
781 	{
782 		Cookie* cookie = (Cookie*)_cookie;
783 		cookie->nextChild = NULL;
784 		return B_OK;
785 	}
786 
787 	virtual bool IsEmpty()
788 	{
789 		return fDirectory->FirstChild() == NULL;
790 	}
791 
792 private:
793 	struct Cookie {
794 		PackageNode*	nextChild;
795 	};
796 
797 
798 private:
799 	PackageDirectory*	fDirectory;
800 };
801 
802 
803 // #pragma mark -
804 
805 
806 static status_t
807 create_node(PackageNode* packageNode, ::Node*& _node)
808 {
809 	if (packageNode == NULL)
810 		return B_BAD_VALUE;
811 
812 	::Node* node;
813 	switch (packageNode->Mode() & S_IFMT) {
814 		case S_IFREG:
815 			node = new(std::nothrow) File(
816 				static_cast<PackageFile*>(packageNode));
817 			break;
818 		case S_IFLNK:
819 			node = new(std::nothrow) Symlink(
820 				static_cast<PackageSymlink*>(packageNode));
821 			break;
822 		case S_IFDIR:
823 			node = new(std::nothrow) Directory(
824 				static_cast<PackageDirectory*>(packageNode));
825 			break;
826 		default:
827 			return B_BAD_VALUE;
828 	}
829 
830 	if (node == NULL)
831 		return B_NO_MEMORY;
832 
833 	_node = node;
834 	return B_OK;
835 }
836 
837 
838 }	// namespace PackageFS
839 
840 
841 status_t
842 packagefs_mount_file(int fd, ::Directory* systemDirectory,
843 	::Directory*& _mountedDirectory)
844 {
845 	PackageLoaderErrorOutput errorOutput;
846  	PackageReaderImpl packageReader(&errorOutput);
847 	status_t error = packageReader.Init(fd, false, 0);
848  	if (error != B_OK)
849  		RETURN_ERROR(error);
850 
851 	// create the volume
852 	PackageVolume* volume = new(std::nothrow) PackageVolume;
853 	if (volume == NULL)
854 		return B_NO_MEMORY;
855 	BReference<PackageVolume> volumeReference(volume, true);
856 
857 	error = volume->Init(fd, packageReader.RawHeapReader());
858 	if (error != B_OK)
859 		RETURN_ERROR(error);
860 
861 	// load settings for the package
862 	PackageSettingsItem* settings = PackageSettingsItem::Load(systemDirectory,
863 		"haiku");
864 	ObjectDeleter<PackageSettingsItem> settingsDeleter(settings);
865 
866 	// parse content -- this constructs the entry/node tree
867 	PackageLoaderContentHandler handler(volume, settings);
868 	error = handler.Init();
869 	if (error != B_OK)
870 		RETURN_ERROR(error);
871 
872 	error = packageReader.ParseContent(&handler);
873 	if (error != B_OK)
874 		RETURN_ERROR(error);
875 
876 	// create a VFS node for the root node
877 	::Node* rootNode;
878 	error = create_node(volume->RootDirectory(), rootNode);
879 	if (error != B_OK)
880 		RETURN_ERROR(error);
881 
882 	_mountedDirectory = static_cast< ::Directory*>(rootNode);
883 	return B_OK;
884 }
885 
886 
887 void
888 packagefs_apply_path_blocklist(::Directory* systemDirectory,
889 	const PathBlocklist& pathBlocklist)
890 {
891 	PackageFS::Directory* directory
892 		= static_cast<PackageFS::Directory*>(systemDirectory);
893 
894 	for (PathBlocklist::Iterator it = pathBlocklist.GetIterator();
895 		BlockedPath* path = it.Next();) {
896 		directory->RemoveEntry(path->Path());
897 	}
898 }
899 
900