xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp (revision 072d3935c2497638e9c2502f574c133caeba9d3d)
1 /*
2  * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Volume.h"
8 
9 #include <dirent.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <sys/param.h>
14 #include <sys/stat.h>
15 
16 #include <new>
17 
18 #include <AppDefs.h>
19 #include <driver_settings.h>
20 #include <KernelExport.h>
21 #include <NodeMonitor.h>
22 #include <package/PackageInfoAttributes.h>
23 
24 #include <AutoDeleter.h>
25 #include <PackagesDirectoryDefs.h>
26 
27 #include <vfs.h>
28 
29 #include "AttributeIndex.h"
30 #include "DebugSupport.h"
31 #include "kernel_interface.h"
32 #include "LastModifiedIndex.h"
33 #include "NameIndex.h"
34 #include "OldUnpackingNodeAttributes.h"
35 #include "PackageFSRoot.h"
36 #include "PackageLinkDirectory.h"
37 #include "PackageLinksDirectory.h"
38 #include "Resolvable.h"
39 #include "SizeIndex.h"
40 #include "UnpackingLeafNode.h"
41 #include "UnpackingDirectory.h"
42 #include "Utils.h"
43 #include "Version.h"
44 
45 
46 // node ID of the root directory
47 static const ino_t kRootDirectoryID = 1;
48 
49 static const uint32 kAllStatFields = B_STAT_MODE | B_STAT_UID | B_STAT_GID
50 	| B_STAT_SIZE | B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
51 	| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME;
52 
53 // shine-through directories
54 const char* const kShineThroughDirectories[] = {
55 	"cache", "non-packaged", "packages", "settings", "var", NULL
56 };
57 
58 // sanity limit for activation change request
59 const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
60 
61 // sanity limit for activation file size
62 const size_t kMaxActivationFileSize = 10 * 1024 * 1024;
63 
64 static const char* const kAdministrativeDirectoryName
65 	= PACKAGES_DIRECTORY_ADMIN_DIRECTORY;
66 static const char* const kActivationFileName
67 	= PACKAGES_DIRECTORY_ACTIVATION_FILE;
68 static const char* const kActivationFilePath
69 	= PACKAGES_DIRECTORY_ADMIN_DIRECTORY "/"
70 		PACKAGES_DIRECTORY_ACTIVATION_FILE;
71 
72 
73 // #pragma mark - ShineThroughDirectory
74 
75 
76 struct Volume::ShineThroughDirectory : public Directory {
77 	ShineThroughDirectory(ino_t id)
78 		:
79 		Directory(id)
80 	{
81 		get_real_time(fModifiedTime);
82 	}
83 
84 	virtual timespec ModifiedTime() const
85 	{
86 		return fModifiedTime;
87 	}
88 
89 private:
90 	timespec	fModifiedTime;
91 };
92 
93 
94 // #pragma mark - ActivationChangeRequest
95 
96 
97 struct Volume::ActivationChangeRequest {
98 public:
99 	ActivationChangeRequest()
100 		:
101 		fRequest(NULL),
102 		fRequestSize(0)
103 	{
104 	}
105 
106 	~ActivationChangeRequest()
107 	{
108 		free(fRequest);
109 	}
110 
111 	status_t Init(const void* userRequest, size_t requestSize)
112 	{
113 		// copy request to kernel
114 		if (requestSize > kMaxActivationRequestSize)
115 			RETURN_ERROR(B_BAD_VALUE);
116 
117 		fRequest = (PackageFSActivationChangeRequest*)malloc(requestSize);
118 		if (fRequest == NULL)
119 			RETURN_ERROR(B_NO_MEMORY);
120 		fRequestSize = requestSize;
121 
122 		status_t error = user_memcpy(fRequest, userRequest, fRequestSize);
123 		if (error != B_OK)
124 			RETURN_ERROR(error);
125 
126 		uint32 itemCount = fRequest->itemCount;
127 		const char* requestEnd = (const char*)fRequest + requestSize;
128 		if (&fRequest->items[itemCount] > (void*)requestEnd)
129 			RETURN_ERROR(B_BAD_VALUE);
130 
131 		// adjust the item name pointers and check their validity
132 		addr_t nameDelta = (addr_t)fRequest - (addr_t)userRequest;
133 		for (uint32 i = 0; i < itemCount; i++) {
134 			PackageFSActivationChangeItem& item = fRequest->items[i];
135 			item.name += nameDelta;
136 			if (item.name < (char*)fRequest || item.name >= requestEnd)
137 				RETURN_ERROR(B_BAD_VALUE);
138 			size_t maxNameSize = requestEnd - item.name;
139 			if (strnlen(item.name, maxNameSize) == maxNameSize)
140 				RETURN_ERROR(B_BAD_VALUE);
141 		}
142 
143 		return B_OK;
144 	}
145 
146 	uint32 CountItems() const
147 	{
148 		return fRequest->itemCount;
149 	}
150 
151 	PackageFSActivationChangeItem* ItemAt(uint32 index) const
152 	{
153 		return index < CountItems() ? &fRequest->items[index] : NULL;
154 	}
155 
156 private:
157 	PackageFSActivationChangeRequest*	fRequest;
158 	size_t								fRequestSize;
159 };
160 
161 
162 // #pragma mark - Volume
163 
164 
165 Volume::Volume(fs_volume* fsVolume)
166 	:
167 	fFSVolume(fsVolume),
168 	fRootDirectory(NULL),
169 	fPackageFSRoot(NULL),
170 	fPackagesDirectory(NULL),
171 	fPackagesDirectories(),
172 	fPackagesDirectoriesByNodeRef(),
173 	fPackageSettings(),
174 	fNextNodeID(kRootDirectoryID + 1)
175 {
176 	rw_lock_init(&fLock, "packagefs volume");
177 }
178 
179 
180 Volume::~Volume()
181 {
182 	// remove the packages from the node tree
183 	{
184 		VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
185 		VolumeWriteLocker volumeLocker(this);
186 		for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
187 			Package* package = it.Next();) {
188 			_RemovePackageContent(package, NULL, false);
189 		}
190 	}
191 
192 	// delete the packages
193 	_RemoveAllPackages();
194 
195 	// delete all indices
196 	Index* index = fIndices.Clear(true);
197 	while (index != NULL) {
198 		Index* next = index->IndexHashLink();
199 		delete index;
200 		index = next;
201 	}
202 
203 	// remove all nodes from the ID hash table
204 	Node* node = fNodes.Clear(true);
205 	while (node != NULL) {
206 		Node* next = node->IDHashTableNext();
207 		node->ReleaseReference();
208 		node = next;
209 	}
210 
211 	if (fPackageFSRoot != NULL) {
212 		if (this == fPackageFSRoot->SystemVolume())
213 			_RemovePackageLinksDirectory();
214 
215 		fPackageFSRoot->UnregisterVolume(this);
216 	}
217 
218 	if (fRootDirectory != NULL)
219 		fRootDirectory->ReleaseReference();
220 
221 	while (PackagesDirectory* directory = fPackagesDirectories.RemoveHead())
222 		directory->ReleaseReference();
223 
224 	rw_lock_destroy(&fLock);
225 }
226 
227 
228 status_t
229 Volume::Mount(const char* parameterString)
230 {
231 	// init the hash tables
232 	status_t error = fPackagesDirectoriesByNodeRef.Init();
233 	if (error != B_OK)
234 		RETURN_ERROR(error);
235 
236 	error = fNodes.Init();
237 	if (error != B_OK)
238 		RETURN_ERROR(error);
239 
240 	error = fNodeListeners.Init();
241 	if (error != B_OK)
242 		RETURN_ERROR(error);
243 
244 	error = fPackages.Init();
245 	if (error != B_OK)
246 		RETURN_ERROR(error);
247 
248 	error = fIndices.Init();
249 	if (error != B_OK)
250 		RETURN_ERROR(error);
251 
252 	// create the name index
253 	{
254 		NameIndex* index = new(std::nothrow) NameIndex;
255 		if (index == NULL)
256 			RETURN_ERROR(B_NO_MEMORY);
257 
258 		error = index->Init(this);
259 		if (error != B_OK) {
260 			delete index;
261 			RETURN_ERROR(error);
262 		}
263 
264 		fIndices.Insert(index);
265 	}
266 
267 	// create the size index
268 	{
269 		SizeIndex* index = new(std::nothrow) SizeIndex;
270 		if (index == NULL)
271 			RETURN_ERROR(B_NO_MEMORY);
272 
273 		error = index->Init(this);
274 		if (error != B_OK) {
275 			delete index;
276 			RETURN_ERROR(error);
277 		}
278 
279 		fIndices.Insert(index);
280 	}
281 
282 	// create the last modified index
283 	{
284 		LastModifiedIndex* index = new(std::nothrow) LastModifiedIndex;
285 		if (index == NULL)
286 			RETURN_ERROR(B_NO_MEMORY);
287 
288 		error = index->Init(this);
289 		if (error != B_OK) {
290 			delete index;
291 			RETURN_ERROR(error);
292 		}
293 
294 		fIndices.Insert(index);
295 	}
296 
297 	// create a BEOS:APP_SIG index
298 	{
299 		AttributeIndex* index = new(std::nothrow) AttributeIndex;
300 		if (index == NULL)
301 			RETURN_ERROR(B_NO_MEMORY);
302 
303 		error = index->Init(this, "BEOS:APP_SIG", B_MIME_STRING_TYPE, 0);
304 		if (error != B_OK) {
305 			delete index;
306 			RETURN_ERROR(error);
307 		}
308 
309 		fIndices.Insert(index);
310 	}
311 
312 	// get the mount parameters
313 	const char* packages = NULL;
314 	const char* volumeName = NULL;
315 	const char* mountType = NULL;
316 	const char* shineThrough = NULL;
317 	const char* packagesState = NULL;
318 
319 	void* parameterHandle = parse_driver_settings_string(parameterString);
320 	if (parameterHandle != NULL) {
321 		packages = get_driver_parameter(parameterHandle, "packages", NULL,
322 			NULL);
323 		volumeName = get_driver_parameter(parameterHandle, "volume-name", NULL,
324 			NULL);
325 		mountType = get_driver_parameter(parameterHandle, "type", NULL, NULL);
326 		shineThrough = get_driver_parameter(parameterHandle, "shine-through",
327 			NULL, NULL);
328 		packagesState = get_driver_parameter(parameterHandle, "state", NULL,
329 			NULL);
330 	}
331 
332 	CObjectDeleter<void, status_t> parameterHandleDeleter(parameterHandle,
333 		&delete_driver_settings);
334 
335 	if (packages != NULL && packages[0] == '\0') {
336 		FATAL("invalid package folder ('packages' parameter)!\n");
337 		RETURN_ERROR(B_BAD_VALUE);
338 	}
339 
340 	error = _InitMountType(mountType);
341 	if (error != B_OK) {
342 		FATAL("invalid mount type: \"%s\"\n", mountType);
343 		RETURN_ERROR(error);
344 	}
345 
346 	// get our mount point
347 	error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,
348 		&fMountPoint.nodeID);
349 	if (error != B_OK)
350 		RETURN_ERROR(error);
351 
352 	// load package settings
353 	error = fPackageSettings.Load(fMountPoint.deviceID, fMountPoint.nodeID,
354 		fMountType);
355 	// abort only in case of serious issues (memory shortage)
356 	if (error == B_NO_MEMORY)
357 		RETURN_ERROR(error);
358 
359 	// create package domain
360 	fPackagesDirectory = new(std::nothrow) PackagesDirectory;
361 	if (fPackagesDirectory == NULL)
362 		RETURN_ERROR(B_NO_MEMORY);
363 	fPackagesDirectories.Add(fPackagesDirectory);
364 	fPackagesDirectoriesByNodeRef.Insert(fPackagesDirectory);
365 
366 	struct stat st;
367 	error = fPackagesDirectory->Init(packages, fMountPoint.deviceID,
368 		fMountPoint.nodeID, st);
369 	if (error != B_OK)
370 		RETURN_ERROR(error);
371 
372 	// If a packages state has been specified, load the needed states.
373 	if (packagesState != NULL) {
374 		error = _LoadOldPackagesStates(packagesState);
375 		if (error != B_OK)
376 			RETURN_ERROR(error);
377 	}
378 
379 	// If no volume name is given, infer it from the mount type.
380 	if (volumeName == NULL) {
381 		switch (fMountType) {
382 			case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
383 				volumeName = "system";
384 				break;
385 			case PACKAGE_FS_MOUNT_TYPE_HOME:
386 				volumeName = "config";
387 				break;
388 			case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
389 			default:
390 				volumeName = "Package FS";
391 				break;
392 		}
393 	}
394 
395 	String volumeNameString;
396 	if (!volumeNameString.SetTo(volumeName))
397 		RETURN_ERROR(B_NO_MEMORY);
398 
399 	// create the root node
400 	fRootDirectory
401 		= new(std::nothrow) ::RootDirectory(kRootDirectoryID, st.st_mtim);
402 	if (fRootDirectory == NULL)
403 		RETURN_ERROR(B_NO_MEMORY);
404 	fRootDirectory->Init(NULL, volumeNameString);
405 	fNodes.Insert(fRootDirectory);
406 	fRootDirectory->AcquireReference();
407 		// one reference for the table
408 
409 	// register with packagefs root
410 	error = ::PackageFSRoot::RegisterVolume(this);
411 	if (error != B_OK)
412 		RETURN_ERROR(error);
413 
414 	if (this == fPackageFSRoot->SystemVolume()) {
415 		error = _AddPackageLinksDirectory();
416 		if (error != B_OK)
417 			RETURN_ERROR(error);
418 	}
419 
420 	// create shine-through directories
421 	error = _CreateShineThroughDirectories(shineThrough);
422 	if (error != B_OK)
423 		RETURN_ERROR(error);
424 
425 	// add initial packages
426 	error = _AddInitialPackages();
427 	if (error != B_OK)
428 		RETURN_ERROR(error);
429 
430 	// publish the root node
431 	fRootDirectory->AcquireReference();
432 	error = PublishVNode(fRootDirectory);
433 	if (error != B_OK) {
434 		fRootDirectory->ReleaseReference();
435 		RETURN_ERROR(error);
436 	}
437 
438 	// bind and publish the shine-through directories
439 	error = _PublishShineThroughDirectories();
440 	if (error != B_OK)
441 		RETURN_ERROR(error);
442 
443 	StringPool::DumpUsageStatistics();
444 
445 	return B_OK;
446 }
447 
448 
449 void
450 Volume::Unmount()
451 {
452 }
453 
454 
455 status_t
456 Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
457 {
458 	switch (operation) {
459 		case PACKAGE_FS_OPERATION_GET_VOLUME_INFO:
460 		{
461 			if (size < sizeof(PackageFSVolumeInfo))
462 				RETURN_ERROR(B_BAD_VALUE);
463 
464 			PackageFSVolumeInfo* userVolumeInfo
465 				= (PackageFSVolumeInfo*)buffer;
466 
467 			VolumeReadLocker volumeReadLocker(this);
468 
469 			PackageFSVolumeInfo volumeInfo;
470 			volumeInfo.mountType = fMountType;
471 			volumeInfo.rootDeviceID = fPackageFSRoot->DeviceID();
472 			volumeInfo.rootDirectoryID = fPackageFSRoot->NodeID();
473 			volumeInfo.packagesDirectoryCount = fPackagesDirectories.Count();
474 
475 			status_t error = user_memcpy(userVolumeInfo, &volumeInfo,
476 				sizeof(volumeInfo));
477 			if (error != B_OK)
478 				RETURN_ERROR(error);
479 
480 			uint32 directoryIndex = 0;
481 			for (PackagesDirectoryList::Iterator it
482 					= fPackagesDirectories.GetIterator();
483 				PackagesDirectory* directory = it.Next();
484 				directoryIndex++) {
485 				PackageFSDirectoryInfo info;
486 				info.deviceID = directory->DeviceID();
487 				info.nodeID = directory->NodeID();
488 
489 				PackageFSDirectoryInfo* userInfo
490 					= userVolumeInfo->packagesDirectoryInfos + directoryIndex;
491 				if (addr_t(userInfo + 1) > (addr_t)buffer + size)
492 					break;
493 
494 				if (user_memcpy(userInfo, &info, sizeof(info)) != B_OK)
495 					return B_BAD_ADDRESS;
496 			}
497 
498 			return B_OK;
499 		}
500 
501 		case PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS:
502 		{
503 			if (size < sizeof(PackageFSGetPackageInfosRequest))
504 				RETURN_ERROR(B_BAD_VALUE);
505 
506 			PackageFSGetPackageInfosRequest* request
507 				= (PackageFSGetPackageInfosRequest*)buffer;
508 
509 			VolumeReadLocker volumeReadLocker(this);
510 
511 			addr_t bufferEnd = (addr_t)buffer + size;
512 			uint32 packageCount = fPackages.CountElements();
513 			char* nameBuffer = (char*)(request->infos + packageCount);
514 
515 			uint32 packageIndex = 0;
516 			for (PackageFileNameHashTable::Iterator it
517 					= fPackages.GetIterator(); it.HasNext();
518 				packageIndex++) {
519 				Package* package = it.Next();
520 				PackageFSPackageInfo info;
521 				info.packageDeviceID = package->DeviceID();
522 				info.packageNodeID = package->NodeID();
523 				PackagesDirectory* directory = package->Directory();
524 				info.directoryDeviceID = directory->DeviceID();
525 				info.directoryNodeID = directory->NodeID();
526 				info.name = nameBuffer;
527 
528 				PackageFSPackageInfo* userInfo = request->infos + packageIndex;
529 				if (addr_t(userInfo + 1) <= bufferEnd) {
530 					if (user_memcpy(userInfo, &info, sizeof(info)) != B_OK)
531 						return B_BAD_ADDRESS;
532 				}
533 
534 				const char* name = package->FileName();
535 				size_t nameSize = strlen(name) + 1;
536 				char* nameEnd = nameBuffer + nameSize;
537 				if ((addr_t)nameEnd <= bufferEnd) {
538 					if (user_memcpy(nameBuffer, name, nameSize) != B_OK)
539 						return B_BAD_ADDRESS;
540 				}
541 				nameBuffer = nameEnd;
542 			}
543 
544 			PackageFSGetPackageInfosRequest header;
545 			header.bufferSize = nameBuffer - (char*)request;
546 			header.packageCount = packageCount;
547 			size_t headerSize = (char*)&request->infos - (char*)request;
548 			RETURN_ERROR(user_memcpy(request, &header, headerSize));
549 		}
550 
551 		case PACKAGE_FS_OPERATION_CHANGE_ACTIVATION:
552 		{
553 			ActivationChangeRequest request;
554 			status_t error = request.Init(buffer, size);
555 			if (error != B_OK)
556 				RETURN_ERROR(B_BAD_VALUE);
557 
558 			return _ChangeActivation(request);
559 		}
560 
561 		default:
562 			return B_BAD_VALUE;
563 	}
564 }
565 
566 
567 void
568 Volume::AddNodeListener(NodeListener* listener, Node* node)
569 {
570 	ASSERT(!listener->IsListening());
571 
572 	listener->StartedListening(node);
573 
574 	if (NodeListener* list = fNodeListeners.Lookup(node))
575 		list->AddNodeListener(listener);
576 	else
577 		fNodeListeners.Insert(listener);
578 }
579 
580 
581 void
582 Volume::RemoveNodeListener(NodeListener* listener)
583 {
584 	ASSERT(listener->IsListening());
585 
586 	Node* node = listener->ListenedNode();
587 
588 	if (NodeListener* next = listener->RemoveNodeListener()) {
589 		// list not empty yet -- if we removed the head, add a new head to the
590 		// hash table
591 		NodeListener* list = fNodeListeners.Lookup(node);
592 		if (list == listener) {
593 			fNodeListeners.Remove(listener);
594 			fNodeListeners.Insert(next);
595 		}
596 	} else
597 		fNodeListeners.Remove(listener);
598 
599 	listener->StoppedListening();
600 }
601 
602 
603 void
604 Volume::AddQuery(Query* query)
605 {
606 	fQueries.Add(query);
607 }
608 
609 
610 void
611 Volume::RemoveQuery(Query* query)
612 {
613 	fQueries.Remove(query);
614 }
615 
616 
617 void
618 Volume::UpdateLiveQueries(Node* node, const char* attribute, int32 type,
619 	const void* oldKey, size_t oldLength, const void* newKey,
620 	size_t newLength)
621 {
622 	for (QueryList::Iterator it = fQueries.GetIterator();
623 			Query* query = it.Next();) {
624 		query->LiveUpdate(node, attribute, type, oldKey, oldLength, newKey,
625 			newLength);
626 	}
627 }
628 
629 
630 status_t
631 Volume::GetVNode(ino_t nodeID, Node*& _node)
632 {
633 	return get_vnode(fFSVolume, nodeID, (void**)&_node);
634 }
635 
636 
637 status_t
638 Volume::PutVNode(ino_t nodeID)
639 {
640 	return put_vnode(fFSVolume, nodeID);
641 }
642 
643 
644 status_t
645 Volume::RemoveVNode(ino_t nodeID)
646 {
647 	return remove_vnode(fFSVolume, nodeID);
648 }
649 
650 
651 status_t
652 Volume::PublishVNode(Node* node)
653 {
654 	return publish_vnode(fFSVolume, node->ID(), node, &gPackageFSVnodeOps,
655 		node->Mode() & S_IFMT, 0);
656 }
657 
658 
659 void
660 Volume::PackageLinkNodeAdded(Node* node)
661 {
662 	_AddPackageLinksNode(node);
663 
664 	notify_entry_created(ID(), node->Parent()->ID(), node->Name(), node->ID());
665 	_NotifyNodeAdded(node);
666 }
667 
668 
669 void
670 Volume::PackageLinkNodeRemoved(Node* node)
671 {
672 	_RemovePackageLinksNode(node);
673 
674 	notify_entry_removed(ID(), node->Parent()->ID(), node->Name(), node->ID());
675 	_NotifyNodeRemoved(node);
676 }
677 
678 
679 void
680 Volume::PackageLinkNodeChanged(Node* node, uint32 statFields,
681 	const OldNodeAttributes& oldAttributes)
682 {
683 	Directory* parent = node->Parent();
684 	notify_stat_changed(ID(), parent != NULL ? parent->ID() : -1, node->ID(),
685 		statFields);
686 	_NotifyNodeChanged(node, statFields, oldAttributes);
687 }
688 
689 
690 status_t
691 Volume::_LoadOldPackagesStates(const char* packagesState)
692 {
693 	// open and stat the admininistrative dir
694 	int fd = openat(fPackagesDirectory->DirectoryFD(),
695 		kAdministrativeDirectoryName, O_RDONLY);
696 	if (fd < 0) {
697 		ERROR("Failed to open administrative directory: %s\n", strerror(errno));
698 		RETURN_ERROR(errno);
699 	}
700 
701 	struct stat adminDirStat;
702 	if (fstat(fd, &adminDirStat) < 0) {
703 		ERROR("Failed to fstat() administrative directory: %s\n",
704 			strerror(errno));
705 		RETURN_ERROR(errno);
706 	}
707 
708 	// iterate through the "administrative" dir
709 	DIR* dir = fdopendir(fd);
710 	if (dir == NULL) {
711 		ERROR("Failed to open administrative directory: %s\n", strerror(errno));
712 		RETURN_ERROR(errno);
713 	}
714 	CObjectDeleter<DIR, int> dirCloser(dir, closedir);
715 
716 	while (dirent* entry = readdir(dir)) {
717 		if (strncmp(entry->d_name, "state_", 6) != 0
718 			|| strcmp(entry->d_name, packagesState) < 0) {
719 			continue;
720 		}
721 
722 		PackagesDirectory* packagesDirectory
723 			= new(std::nothrow) PackagesDirectory;
724 		status_t error = packagesDirectory->InitOldState(adminDirStat.st_dev,
725 			adminDirStat.st_ino, entry->d_name);
726 		if (error != B_OK) {
727 			delete packagesDirectory;
728 			continue;
729 		}
730 
731 		fPackagesDirectories.Add(packagesDirectory);
732 		fPackagesDirectoriesByNodeRef.Insert(packagesDirectory);
733 
734 		INFORM("added old packages dir state \"%s\"\n",
735 			packagesDirectory->StateName().Data());
736 	}
737 
738 	// sort the packages directories by state age
739 	fPackagesDirectories.Sort(&PackagesDirectory::IsNewer);
740 
741 	return B_OK;
742 }
743 
744 
745 status_t
746 Volume::_AddInitialPackages()
747 {
748 	PackagesDirectory* packagesDirectory = fPackagesDirectories.Last();
749 	INFORM("Adding packages from \"%s\"\n", packagesDirectory->Path());
750 
751 	// try reading the activation file of the oldest state
752 	status_t error = _AddInitialPackagesFromActivationFile(packagesDirectory);
753 	if (error != B_OK && packagesDirectory != fPackagesDirectory) {
754 		WARN("Loading packages from old state \"%s\" failed. Loading packages "
755 			"from latest state.\n", packagesDirectory->StateName().Data());
756 
757 		// remove all packages already added
758 		{
759 			VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
760 			VolumeWriteLocker volumeLocker(this);
761 			_RemoveAllPackages();
762 		}
763 
764 		// remove the old states
765 		while (fPackagesDirectories.Last() != fPackagesDirectory)
766 			fPackagesDirectories.RemoveTail()->ReleaseReference();
767 
768 		// try reading the activation file of the latest state
769 		packagesDirectory = fPackagesDirectory;
770 		error = _AddInitialPackagesFromActivationFile(packagesDirectory);
771 	}
772 
773 	if (error != B_OK) {
774 		INFORM("Loading packages from activation file failed. Loading all "
775 			"packages in packages directory.\n");
776 
777 		// remove all packages already added
778 		{
779 			VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
780 			VolumeWriteLocker volumeLocker(this);
781 			_RemoveAllPackages();
782 		}
783 
784 		// read the whole directory
785 		error = _AddInitialPackagesFromDirectory();
786 		if (error != B_OK)
787 			RETURN_ERROR(error);
788 	}
789 
790 	// add the packages to the node tree
791 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
792 	VolumeWriteLocker volumeLocker(this);
793 	for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
794 		Package* package = it.Next();) {
795 		error = _AddPackageContent(package, false);
796 		if (error != B_OK) {
797 			for (it.Rewind(); Package* activePackage = it.Next();) {
798 				if (activePackage == package)
799 					break;
800 				_RemovePackageContent(activePackage, NULL, false);
801 			}
802 			RETURN_ERROR(error);
803 		}
804 	}
805 
806 	return B_OK;
807 }
808 
809 
810 status_t
811 Volume::_AddInitialPackagesFromActivationFile(
812 	PackagesDirectory* packagesDirectory)
813 {
814 	// try reading the activation file
815 	int fd = openat(packagesDirectory->DirectoryFD(),
816 		packagesDirectory == fPackagesDirectory
817 			? kActivationFilePath : kActivationFileName,
818 		O_RDONLY);
819 	if (fd < 0) {
820 		INFORM("Failed to open packages activation file: %s\n",
821 			strerror(errno));
822 		RETURN_ERROR(errno);
823 	}
824 	FileDescriptorCloser fdCloser(fd);
825 
826 	// read the whole file into memory to simplify things
827 	struct stat st;
828 	if (fstat(fd, &st) != 0) {
829 		ERROR("Failed to stat packages activation file: %s\n",
830 			strerror(errno));
831 		RETURN_ERROR(errno);
832 	}
833 
834 	if (st.st_size > (off_t)kMaxActivationFileSize) {
835 		ERROR("The packages activation file is too big.\n");
836 		RETURN_ERROR(B_BAD_DATA);
837 	}
838 
839 	char* fileContent = (char*)malloc(st.st_size + 1);
840 	if (fileContent == NULL)
841 		RETURN_ERROR(B_NO_MEMORY);
842 	MemoryDeleter fileContentDeleter(fileContent);
843 
844 	ssize_t bytesRead = read(fd, fileContent, st.st_size);
845 	if (bytesRead < 0) {
846 		ERROR("Failed to read packages activation file: %s\n", strerror(errno));
847 		RETURN_ERROR(errno);
848 	}
849 
850 	if (bytesRead != st.st_size) {
851 		ERROR("Failed to read whole packages activation file\n");
852 		RETURN_ERROR(B_ERROR);
853 	}
854 
855 	// null-terminate to simplify parsing
856 	fileContent[st.st_size] = '\0';
857 
858 	// parse the file and add the respective packages
859 	const char* packageName = fileContent;
860 	char* const fileContentEnd = fileContent + st.st_size;
861 	while (packageName < fileContentEnd) {
862 		char* packageNameEnd = strchr(packageName, '\n');
863 		if (packageNameEnd == NULL)
864 			packageNameEnd = fileContentEnd;
865 
866 		// skip empty lines
867 		if (packageName == packageNameEnd) {
868 			packageName++;
869 			continue;
870 		}
871 		*packageNameEnd = '\0';
872 
873 		if (packageNameEnd - packageName >= B_FILE_NAME_LENGTH) {
874 			ERROR("Invalid packages activation file content.\n");
875 			RETURN_ERROR(B_BAD_DATA);
876 		}
877 
878 		status_t error = _LoadAndAddInitialPackage(packagesDirectory,
879 			packageName);
880 		if (error != B_OK)
881 			RETURN_ERROR(error);
882 
883 		packageName = packageNameEnd + 1;
884 	}
885 
886 	return B_OK;
887 }
888 
889 
890 status_t
891 Volume::_AddInitialPackagesFromDirectory()
892 {
893 	// iterate through the dir and create packages
894 	int fd = openat(fPackagesDirectory->DirectoryFD(), ".", O_RDONLY);
895 	if (fd < 0) {
896 		ERROR("Failed to open packages directory: %s\n", strerror(errno));
897 		RETURN_ERROR(errno);
898 	}
899 
900 	DIR* dir = fdopendir(fd);
901 	if (dir == NULL) {
902 		ERROR("Failed to open packages directory \"%s\": %s\n",
903 			fPackagesDirectory->Path(), strerror(errno));
904 		RETURN_ERROR(errno);
905 	}
906 	CObjectDeleter<DIR, int> dirCloser(dir, closedir);
907 
908 	while (dirent* entry = readdir(dir)) {
909 		// skip "." and ".."
910 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
911 			continue;
912 
913 		// also skip any entry without a ".hpkg" extension
914 		size_t nameLength = strlen(entry->d_name);
915 		if (nameLength < 5
916 			|| memcmp(entry->d_name + nameLength - 5, ".hpkg", 5) != 0) {
917 			continue;
918 		}
919 
920 		_LoadAndAddInitialPackage(fPackagesDirectory, entry->d_name);
921 	}
922 
923 	return B_OK;
924 }
925 
926 
927 status_t
928 Volume::_LoadAndAddInitialPackage(PackagesDirectory* packagesDirectory,
929 	const char* name)
930 {
931 	Package* package;
932 	status_t error = _LoadPackage(packagesDirectory, name, package);
933 	if (error != B_OK) {
934 		ERROR("Failed to load package \"%s\": %s\n", name, strerror(error));
935 		RETURN_ERROR(error);
936 	}
937 	BReference<Package> packageReference(package, true);
938 
939 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
940 	VolumeWriteLocker volumeLocker(this);
941 	_AddPackage(package);
942 
943 	return B_OK;
944 }
945 
946 
947 inline void
948 Volume::_AddPackage(Package* package)
949 {
950 	fPackages.Insert(package);
951 	package->AcquireReference();
952 }
953 
954 
955 inline void
956 Volume::_RemovePackage(Package* package)
957 {
958 	fPackages.Remove(package);
959 	package->ReleaseReference();
960 }
961 
962 
963 void
964 Volume::_RemoveAllPackages()
965 {
966 	Package* package = fPackages.Clear(true);
967 	while (package != NULL) {
968 		Package* next = package->FileNameHashTableNext();
969 		package->ReleaseReference();
970 		package = next;
971 	}
972 }
973 
974 
975 inline Package*
976 Volume::_FindPackage(const char* fileName) const
977 {
978 	return fPackages.Lookup(fileName);
979 }
980 
981 
982 status_t
983 Volume::_AddPackageContent(Package* package, bool notify)
984 {
985 	// Open the package. We don't need the FD here, but this is an optimization.
986 	// The attribute indices may want to read the package nodes' attributes and
987 	// the package file would be opened and closed for each attribute instance.
988 	// Since Package keeps and shares the FD as long as at least one party has
989 	// the package open, we prevent that.
990 	int fd = package->Open();
991 	if (fd < 0)
992 		RETURN_ERROR(fd);
993 	PackageCloser packageCloser(package);
994 
995 	status_t error = fPackageFSRoot->AddPackage(package);
996 	if (error != B_OK)
997 		RETURN_ERROR(error);
998 
999 	for (PackageNodeList::Iterator it = package->Nodes().GetIterator();
1000 			PackageNode* node = it.Next();) {
1001 		// skip over ".PackageInfo" file, it isn't part of the package content
1002 		if (strcmp(node->Name(),
1003 				BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
1004 			continue;
1005 		}
1006 		error = _AddPackageContentRootNode(package, node, notify);
1007 		if (error != B_OK) {
1008 			_RemovePackageContent(package, node, notify);
1009 			RETURN_ERROR(error);
1010 		}
1011 	}
1012 
1013 	return B_OK;
1014 }
1015 
1016 
1017 void
1018 Volume::_RemovePackageContent(Package* package, PackageNode* endNode,
1019 	bool notify)
1020 {
1021 	PackageNode* node = package->Nodes().Head();
1022 	while (node != NULL) {
1023 		if (node == endNode)
1024 			break;
1025 
1026 		PackageNode* nextNode = package->Nodes().GetNext(node);
1027 
1028 		// skip over ".PackageInfo" file, it isn't part of the package content
1029 		if (strcmp(node->Name(),
1030 				BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME) != 0) {
1031 			_RemovePackageContentRootNode(package, node, NULL, notify);
1032 		}
1033 
1034 		node = nextNode;
1035 	}
1036 
1037 	fPackageFSRoot->RemovePackage(package);;
1038 }
1039 
1040 
1041 /*!	This method recursively iterates through the descendents of the given
1042 	package root node and adds all package nodes to the node tree in
1043 	pre-order.
1044 	Due to limited kernel stack space we avoid deep recursive function calls
1045 	and rather use the package node stack implied by the tree.
1046 */
1047 status_t
1048 Volume::_AddPackageContentRootNode(Package* package,
1049 	PackageNode* rootPackageNode, bool notify)
1050 {
1051 	PackageNode* packageNode = rootPackageNode;
1052 	Directory* directory = fRootDirectory;
1053 	directory->WriteLock();
1054 
1055 	do {
1056 		Node* node;
1057 		status_t error = _AddPackageNode(directory, packageNode, notify, node);
1058 			// returns B_OK with a NULL node, when skipping the node
1059 		if (error != B_OK) {
1060 			// unlock all directories
1061 			while (directory != NULL) {
1062 				directory->WriteUnlock();
1063 				directory = directory->Parent();
1064 			}
1065 
1066 			// remove the added package nodes
1067 			_RemovePackageContentRootNode(package, rootPackageNode, packageNode,
1068 				notify);
1069 			RETURN_ERROR(error);
1070 		}
1071 
1072 		// recurse into directory, unless we're supposed to skip the node
1073 		if (node != NULL) {
1074 			if (PackageDirectory* packageDirectory
1075 					= dynamic_cast<PackageDirectory*>(packageNode)) {
1076 				if (packageDirectory->FirstChild() != NULL) {
1077 					directory = dynamic_cast<Directory*>(node);
1078 					packageNode = packageDirectory->FirstChild();
1079 					directory->WriteLock();
1080 					continue;
1081 				}
1082 			}
1083 		}
1084 
1085 		// continue with the next available (ancestors's) sibling
1086 		do {
1087 			PackageDirectory* packageDirectory = packageNode->Parent();
1088 			PackageNode* sibling = packageDirectory != NULL
1089 				? packageDirectory->NextChild(packageNode) : NULL;
1090 
1091 			if (sibling != NULL) {
1092 				packageNode = sibling;
1093 				break;
1094 			}
1095 
1096 			// no more siblings -- go back up the tree
1097 			packageNode = packageDirectory;
1098 			directory->WriteUnlock();
1099 			directory = directory->Parent();
1100 				// the parent is still locked, so this is safe
1101 		} while (packageNode != NULL);
1102 	} while (packageNode != NULL);
1103 
1104 	return B_OK;
1105 }
1106 
1107 
1108 /*!	Recursively iterates through the descendents of the given package root node
1109 	and removes all package nodes from the node tree in post-order, until
1110 	encountering \a endPackageNode (if non-null).
1111 	Due to limited kernel stack space we avoid deep recursive function calls
1112 	and rather use the package node stack implied by the tree.
1113 */
1114 void
1115 Volume::_RemovePackageContentRootNode(Package* package,
1116 	PackageNode* rootPackageNode, PackageNode* endPackageNode, bool notify)
1117 {
1118 	PackageNode* packageNode = rootPackageNode;
1119 	Directory* directory = fRootDirectory;
1120 	directory->WriteLock();
1121 
1122 	do {
1123 		if (packageNode == endPackageNode)
1124 			break;
1125 
1126 		// recurse into directory
1127 		if (PackageDirectory* packageDirectory
1128 				= dynamic_cast<PackageDirectory*>(packageNode)) {
1129 			if (packageDirectory->FirstChild() != NULL) {
1130 				if (Directory* childDirectory = dynamic_cast<Directory*>(
1131 						directory->FindChild(packageNode->Name()))) {
1132 					directory = childDirectory;
1133 					packageNode = packageDirectory->FirstChild();
1134 					directory->WriteLock();
1135 					continue;
1136 				}
1137 			}
1138 		}
1139 
1140 		// continue with the next available (ancestors's) sibling
1141 		do {
1142 			PackageDirectory* packageDirectory = packageNode->Parent();
1143 			PackageNode* sibling = packageDirectory != NULL
1144 				? packageDirectory->NextChild(packageNode) : NULL;
1145 
1146 			// we're done with the node -- remove it
1147 			_RemovePackageNode(directory, packageNode,
1148 				directory->FindChild(packageNode->Name()), notify);
1149 
1150 			if (sibling != NULL) {
1151 				packageNode = sibling;
1152 				break;
1153 			}
1154 
1155 			// no more siblings -- go back up the tree
1156 			packageNode = packageDirectory;
1157 			directory->WriteUnlock();
1158 			directory = directory->Parent();
1159 				// the parent is still locked, so this is safe
1160 		} while (packageNode != NULL/* && packageNode != rootPackageNode*/);
1161 	} while (packageNode != NULL/* && packageNode != rootPackageNode*/);
1162 }
1163 
1164 
1165 status_t
1166 Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
1167 	bool notify, Node*& _node)
1168 {
1169 	bool newNode = false;
1170 	UnpackingNode* unpackingNode;
1171 	Node* node = directory->FindChild(packageNode->Name());
1172 	PackageNode* oldPackageNode = NULL;
1173 
1174 	if (node != NULL) {
1175 		unpackingNode = dynamic_cast<UnpackingNode*>(node);
1176 		if (unpackingNode == NULL) {
1177 			_node = NULL;
1178 			return B_OK;
1179 		}
1180 		oldPackageNode = unpackingNode->GetPackageNode();
1181 	} else {
1182 		status_t error = _CreateUnpackingNode(packageNode->Mode(), directory,
1183 			packageNode->Name(), unpackingNode);
1184 		if (error != B_OK)
1185 			RETURN_ERROR(error);
1186 
1187 		node = unpackingNode->GetNode();
1188 		newNode = true;
1189 	}
1190 
1191 	BReference<Node> nodeReference(node);
1192 	NodeWriteLocker nodeWriteLocker(node);
1193 
1194 	BReference<Node> newNodeReference;
1195 	NodeWriteLocker newNodeWriteLocker;
1196 	Node* oldNode = NULL;
1197 
1198 	if (!newNode && !S_ISDIR(node->Mode()) && oldPackageNode != NULL
1199 		&& unpackingNode->WillBeFirstPackageNode(packageNode)) {
1200 		// The package node we're going to add will represent the node,
1201 		// replacing the current head package node. Since the node isn't a
1202 		// directory, we must make sure that clients having opened or mapped the
1203 		// node won't be surprised. So we create a new node and remove the
1204 		// current one.
1205 		// create a new node and transfer the package nodes to it
1206 		UnpackingNode* newUnpackingNode;
1207 		status_t error = unpackingNode->CloneTransferPackageNodes(
1208 			fNextNodeID++, newUnpackingNode);
1209 		if (error != B_OK)
1210 			RETURN_ERROR(error);
1211 
1212 		// remove the old node
1213 		_NotifyNodeRemoved(node);
1214 		_RemoveNodeAndVNode(node);
1215 		oldNode = node;
1216 
1217 		// add the new node
1218 		unpackingNode = newUnpackingNode;
1219 		node = unpackingNode->GetNode();
1220 		newNodeReference.SetTo(node);
1221 		newNodeWriteLocker.SetTo(node, false);
1222 
1223 		directory->AddChild(node);
1224 		fNodes.Insert(node);
1225 		newNode = true;
1226 	}
1227 
1228 	status_t error = unpackingNode->AddPackageNode(packageNode, ID());
1229 	if (error != B_OK) {
1230 		// Remove the node, if created before. If the node was created to
1231 		// replace the previous node, send out notifications instead.
1232 		if (newNode) {
1233 			if (oldNode != NULL) {
1234 				_NotifyNodeAdded(node);
1235 				if (notify) {
1236 					notify_entry_removed(ID(), directory->ID(), oldNode->Name(),
1237 						oldNode->ID());
1238 					notify_entry_created(ID(), directory->ID(), node->Name(),
1239 						node->ID());
1240 				}
1241 			} else
1242 				_RemoveNode(node);
1243 		}
1244 		RETURN_ERROR(error);
1245 	}
1246 
1247 	if (newNode) {
1248 		_NotifyNodeAdded(node);
1249 	} else if (packageNode == unpackingNode->GetPackageNode()) {
1250 		_NotifyNodeChanged(node, kAllStatFields,
1251 			OldUnpackingNodeAttributes(oldPackageNode));
1252 	}
1253 
1254 	if (notify) {
1255 		if (newNode) {
1256 			if (oldNode != NULL) {
1257 				notify_entry_removed(ID(), directory->ID(), oldNode->Name(),
1258 					oldNode->ID());
1259 			}
1260 			notify_entry_created(ID(), directory->ID(), node->Name(),
1261 				node->ID());
1262 		} else if (packageNode == unpackingNode->GetPackageNode()) {
1263 			// The new package node has become the one representing the node.
1264 			// Send stat changed notification for directories and entry
1265 			// removed + created notifications for files and symlinks.
1266 			notify_stat_changed(ID(), directory->ID(), node->ID(),
1267 				kAllStatFields);
1268 			// TODO: Actually the attributes might change, too!
1269 		}
1270 	}
1271 
1272 	_node = node;
1273 	return B_OK;
1274 }
1275 
1276 
1277 void
1278 Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
1279 	Node* node, bool notify)
1280 {
1281 	UnpackingNode* unpackingNode = dynamic_cast<UnpackingNode*>(node);
1282 	if (unpackingNode == NULL)
1283 		return;
1284 
1285 	BReference<Node> nodeReference(node);
1286 	NodeWriteLocker nodeWriteLocker(node);
1287 
1288 	PackageNode* headPackageNode = unpackingNode->GetPackageNode();
1289 	bool nodeRemoved = false;
1290 	Node* newNode = NULL;
1291 
1292 	BReference<Node> newNodeReference;
1293 	NodeWriteLocker newNodeWriteLocker;
1294 
1295 	// If this is the last package node of the node, remove it completely.
1296 	if (unpackingNode->IsOnlyPackageNode(packageNode)) {
1297 		// Notify before removing the node. Otherwise the indices might not
1298 		// find the node anymore.
1299 		_NotifyNodeRemoved(node);
1300 
1301 		unpackingNode->PrepareForRemoval();
1302 
1303 		_RemoveNodeAndVNode(node);
1304 		nodeRemoved = true;
1305 	} else if (packageNode == headPackageNode) {
1306 		// The node does at least have one more package node, but the one to be
1307 		// removed is the head. Unless it's a directory, we replace the node
1308 		// with a completely new one and let the old one die. This is necessary
1309 		// to avoid surprises for clients that have opened/mapped the node.
1310 		if (S_ISDIR(packageNode->Mode())) {
1311 			unpackingNode->RemovePackageNode(packageNode, ID());
1312 			_NotifyNodeChanged(node, kAllStatFields,
1313 				OldUnpackingNodeAttributes(headPackageNode));
1314 		} else {
1315 			// create a new node and transfer the package nodes to it
1316 			UnpackingNode* newUnpackingNode;
1317 			status_t error = unpackingNode->CloneTransferPackageNodes(
1318 				fNextNodeID++, newUnpackingNode);
1319 			if (error == B_OK) {
1320 				// remove the package node
1321 				newUnpackingNode->RemovePackageNode(packageNode, ID());
1322 
1323 				// remove the old node
1324 				_NotifyNodeRemoved(node);
1325 				_RemoveNodeAndVNode(node);
1326 
1327 				// add the new node
1328 				newNode = newUnpackingNode->GetNode();
1329 				newNodeReference.SetTo(newNode);
1330 				newNodeWriteLocker.SetTo(newNode, false);
1331 
1332 				directory->AddChild(newNode);
1333 				fNodes.Insert(newNode);
1334 				_NotifyNodeAdded(newNode);
1335 			} else {
1336 				// There's nothing we can do. Remove the node completely.
1337 				_NotifyNodeRemoved(node);
1338 
1339 				unpackingNode->PrepareForRemoval();
1340 
1341 				_RemoveNodeAndVNode(node);
1342 				nodeRemoved = true;
1343 			}
1344 		}
1345 	} else {
1346 		// The package node to remove is not the head of the node. This change
1347 		// doesn't have any visible effect.
1348 		unpackingNode->RemovePackageNode(packageNode, ID());
1349 	}
1350 
1351 	if (!notify)
1352 		return;
1353 
1354 	// send notifications
1355 	if (nodeRemoved) {
1356 		notify_entry_removed(ID(), directory->ID(), node->Name(), node->ID());
1357 	} else if (packageNode == headPackageNode) {
1358 		// The removed package node was the one representing the node.
1359 		// Send stat changed notification for directories and entry
1360 		// removed + created notifications for files and symlinks.
1361 		if (S_ISDIR(packageNode->Mode())) {
1362 			notify_stat_changed(ID(), directory->ID(), node->ID(),
1363 				kAllStatFields);
1364 			// TODO: Actually the attributes might change, too!
1365 		} else {
1366 			notify_entry_removed(ID(), directory->ID(), node->Name(),
1367 				node->ID());
1368 			notify_entry_created(ID(), directory->ID(), newNode->Name(),
1369 				newNode->ID());
1370 		}
1371 	}
1372 }
1373 
1374 
1375 status_t
1376 Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const String& name,
1377 	UnpackingNode*& _node)
1378 {
1379 	UnpackingNode* unpackingNode;
1380 	if (S_ISREG(mode) || S_ISLNK(mode))
1381 		unpackingNode = new(std::nothrow) UnpackingLeafNode(fNextNodeID++);
1382 	else if (S_ISDIR(mode))
1383 		unpackingNode = new(std::nothrow) UnpackingDirectory(fNextNodeID++);
1384 	else
1385 		RETURN_ERROR(B_UNSUPPORTED);
1386 
1387 	if (unpackingNode == NULL)
1388 		RETURN_ERROR(B_NO_MEMORY);
1389 
1390 	Node* node = unpackingNode->GetNode();
1391 	BReference<Node> nodeReference(node, true);
1392 
1393 	status_t error = node->Init(parent, name);
1394 	if (error != B_OK)
1395 		RETURN_ERROR(error);
1396 
1397 	parent->AddChild(node);
1398 
1399 	fNodes.Insert(node);
1400 	nodeReference.Detach();
1401 		// we keep the initial node reference for the table
1402 
1403 	_node = unpackingNode;
1404 	return B_OK;
1405 }
1406 
1407 
1408 void
1409 Volume::_RemoveNode(Node* node)
1410 {
1411 	// remove from parent
1412 	Directory* parent = node->Parent();
1413 	parent->RemoveChild(node);
1414 
1415 	// remove from node table
1416 	fNodes.Remove(node);
1417 	node->ReleaseReference();
1418 }
1419 
1420 
1421 void
1422 Volume::_RemoveNodeAndVNode(Node* node)
1423 {
1424 	// If the node is known to the VFS, we get the vnode, remove it, and put it,
1425 	// so that the VFS will discard it as soon as possible (i.e. now, if no one
1426 	// else is using it).
1427 	NodeWriteLocker nodeWriteLocker(node);
1428 
1429 	// Remove the node from its parent and the volume. This makes the node
1430 	// inaccessible via the get_vnode() and lookup() hooks.
1431 	_RemoveNode(node);
1432 
1433 	bool getVNode = node->IsKnownToVFS();
1434 
1435 	nodeWriteLocker.Unlock();
1436 
1437 	// Get a vnode reference, if the node is already known to the VFS.
1438 	Node* dummyNode;
1439 	if (getVNode && GetVNode(node->ID(), dummyNode) == B_OK) {
1440 		// TODO: There still is a race condition here which we can't avoid
1441 		// without more help from the VFS. Right after we drop the write
1442 		// lock a vnode for the node could be discarded by the VFS. At that
1443 		// point another thread trying to get the vnode by ID would create
1444 		// a vnode, mark it busy and call our get_vnode() hook. It would
1445 		// block since we (i.e. the package loader thread executing this
1446 		// method) still have the volume write lock. Our get_vnode() call
1447 		// would block, since it finds the vnode marked busy. It times out
1448 		// eventually, but until then a good deal of FS operations might
1449 		// block as well due to us holding the volume lock and probably
1450 		// several node locks as well. A get_vnode*() variant (e.g.
1451 		// get_vnode_etc() with flags parameter) that wouldn't block and
1452 		// only get the vnode, if already loaded and non-busy, would be
1453 		// perfect here.
1454 		RemoveVNode(node->ID());
1455 		PutVNode(node->ID());
1456 	}
1457 }
1458 
1459 
1460 status_t
1461 Volume::_LoadPackage(PackagesDirectory* packagesDirectory, const char* name,
1462 	Package*& _package)
1463 {
1464 	// Find the package -- check the specified packages directory and iterate
1465 	// toward the newer states.
1466 	struct stat st;
1467 	for (;;) {
1468 		if (packagesDirectory == NULL)
1469 			return B_ENTRY_NOT_FOUND;
1470 
1471 		if (fstatat(packagesDirectory->DirectoryFD(), name, &st, 0) == 0) {
1472 			// check whether the entry is a file
1473 			if (!S_ISREG(st.st_mode))
1474 				return B_BAD_VALUE;
1475 			break;
1476 		}
1477 
1478 		packagesDirectory = fPackagesDirectories.GetPrevious(packagesDirectory);
1479 	}
1480 
1481 	// create a package
1482 	Package* package = new(std::nothrow) Package(this, packagesDirectory,
1483 		st.st_dev, st.st_ino);
1484 	if (package == NULL)
1485 		RETURN_ERROR(B_NO_MEMORY);
1486 	BReference<Package> packageReference(package, true);
1487 
1488 	status_t error = package->Init(name);
1489 	if (error != B_OK)
1490 		return error;
1491 
1492 	error = package->Load(fPackageSettings);
1493 	if (error != B_OK)
1494 		return error;
1495 
1496 	_package = packageReference.Detach();
1497 	return B_OK;
1498 }
1499 
1500 
1501 status_t
1502 Volume::_ChangeActivation(ActivationChangeRequest& request)
1503 {
1504 	uint32 itemCount = request.CountItems();
1505 	if (itemCount == 0)
1506 		return B_OK;
1507 
1508 	// first check the request
1509 	int32 newPackageCount = 0;
1510 	int32 oldPackageCount = 0;
1511 	{
1512 		VolumeReadLocker volumeLocker(this);
1513 
1514 		for (uint32 i = 0; i < itemCount; i++) {
1515 			PackageFSActivationChangeItem* item = request.ItemAt(i);
1516 			if (item->parentDeviceID != fPackagesDirectory->DeviceID()
1517 				|| item->parentDirectoryID != fPackagesDirectory->NodeID()) {
1518 				ERROR("Volume::_ChangeActivation(): mismatching packages "
1519 					"directory\n");
1520 				RETURN_ERROR(B_MISMATCHED_VALUES);
1521 			}
1522 
1523 			Package* package = _FindPackage(item->name);
1524 // TODO: We should better look up the package by node_ref!
1525 			if (item->type == PACKAGE_FS_ACTIVATE_PACKAGE) {
1526 				if (package != NULL) {
1527 					ERROR("Volume::_ChangeActivation(): package to activate "
1528 						"already activated: \"%s\"\n", item->name);
1529 					RETURN_ERROR(B_NAME_IN_USE);
1530 				}
1531 				newPackageCount++;
1532 			} else if (item->type == PACKAGE_FS_DEACTIVATE_PACKAGE) {
1533 				if (package == NULL) {
1534 					ERROR("Volume::_ChangeActivation(): package to deactivate "
1535 						"not found: \"%s\"\n", item->name);
1536 					RETURN_ERROR(B_NAME_NOT_FOUND);
1537 				}
1538 				oldPackageCount++;
1539 			} else if (item->type == PACKAGE_FS_REACTIVATE_PACKAGE) {
1540 				if (package == NULL) {
1541 					ERROR("Volume::_ChangeActivation(): package to reactivate "
1542 						"not found: \"%s\"\n", item->name);
1543 					RETURN_ERROR(B_NAME_NOT_FOUND);
1544 				}
1545 				oldPackageCount++;
1546 				newPackageCount++;
1547 			} else
1548 				RETURN_ERROR(B_BAD_VALUE);
1549 		}
1550 	}
1551 
1552 	INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32
1553 		" old packages\n", newPackageCount, oldPackageCount);
1554 
1555 	// Things look good so far -- allocate reference arrays for the packages to
1556 	// add and remove.
1557 	BReference<Package>* newPackageReferences
1558 		= new(std::nothrow) BReference<Package>[newPackageCount];
1559 	if (newPackageReferences == NULL)
1560 		RETURN_ERROR(B_NO_MEMORY);
1561 	ArrayDeleter<BReference<Package> > newPackageReferencesDeleter(
1562 			newPackageReferences);
1563 
1564 	BReference<Package>* oldPackageReferences
1565 		= new(std::nothrow) BReference<Package>[oldPackageCount];
1566 	if (oldPackageReferences == NULL)
1567 		RETURN_ERROR(B_NO_MEMORY);
1568 	ArrayDeleter<BReference<Package> > oldPackageReferencesDeleter(
1569 			oldPackageReferences);
1570 
1571 	// load all new packages
1572 	int32 newPackageIndex = 0;
1573 	for (uint32 i = 0; i < itemCount; i++) {
1574 		PackageFSActivationChangeItem* item = request.ItemAt(i);
1575 
1576 		if (item->type != PACKAGE_FS_ACTIVATE_PACKAGE
1577 			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
1578 			continue;
1579 		}
1580 
1581 		Package* package;
1582 		status_t error = _LoadPackage(fPackagesDirectory, item->name, package);
1583 		if (error != B_OK) {
1584 			ERROR("Volume::_ChangeActivation(): failed to load package "
1585 				"\"%s\"\n", item->name);
1586 			RETURN_ERROR(error);
1587 		}
1588 
1589 		newPackageReferences[newPackageIndex++].SetTo(package, true);
1590 	}
1591 
1592 	// apply the changes
1593 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
1594 	VolumeWriteLocker volumeLocker(this);
1595 // TODO: Add a change counter to Volume, so we can easily check whether
1596 // everything is still the same.
1597 
1598 	// remove the old packages
1599 	int32 oldPackageIndex = 0;
1600 	for (uint32 i = 0; i < itemCount; i++) {
1601 		PackageFSActivationChangeItem* item = request.ItemAt(i);
1602 
1603 		if (item->type != PACKAGE_FS_DEACTIVATE_PACKAGE
1604 			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
1605 			continue;
1606 		}
1607 
1608 		Package* package = _FindPackage(item->name);
1609 // TODO: We should better look up the package by node_ref!
1610 		oldPackageReferences[oldPackageIndex++].SetTo(package);
1611 		_RemovePackageContent(package, NULL, true);
1612 		_RemovePackage(package);
1613 
1614 		INFORM("package \"%s\" deactivated\n", package->FileName().Data());
1615 	}
1616 // TODO: Since package removal cannot fail, consider adding the new packages
1617 // first. The reactivation case may make that problematic, since two packages
1618 // with the same name would be active after activating the new one. Check!
1619 
1620 	// add the new packages
1621 	status_t error = B_OK;
1622 	for (newPackageIndex = 0; newPackageIndex < newPackageCount;
1623 		newPackageIndex++) {
1624 		Package* package = newPackageReferences[newPackageIndex];
1625 		_AddPackage(package);
1626 
1627 		// add the package to the node tree
1628 		error = _AddPackageContent(package, true);
1629 		if (error != B_OK) {
1630 			_RemovePackage(package);
1631 			break;
1632 		}
1633 		INFORM("package \"%s\" activated\n", package->FileName().Data());
1634 	}
1635 
1636 	// Try to roll back the changes, if an error occurred.
1637 	if (error != B_OK) {
1638 		for (int32 i = newPackageIndex - 1; i >= 0; i--) {
1639 			Package* package = newPackageReferences[i];
1640 			_RemovePackageContent(package, NULL, true);
1641 			_RemovePackage(package);
1642 		}
1643 
1644 		for (int32 i = oldPackageCount - 1; i >= 0; i--) {
1645 			Package* package = oldPackageReferences[i];
1646 			_AddPackage(package);
1647 
1648 			if (_AddPackageContent(package, true) != B_OK) {
1649 				// nothing we can do here
1650 				ERROR("Volume::_ChangeActivation(): failed to roll back "
1651 					"deactivation of package \"%s\" after error\n",
1652 		  			package->FileName().Data());
1653 				_RemovePackage(package);
1654 			}
1655 		}
1656 	}
1657 
1658 	return error;
1659 }
1660 
1661 
1662 status_t
1663 Volume::_InitMountType(const char* mountType)
1664 {
1665 	if (mountType == NULL)
1666 		fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM;
1667 	else if (strcmp(mountType, "system") == 0)
1668 		fMountType = PACKAGE_FS_MOUNT_TYPE_SYSTEM;
1669 	else if (strcmp(mountType, "home") == 0)
1670 		fMountType = PACKAGE_FS_MOUNT_TYPE_HOME;
1671 	else if (strcmp(mountType, "custom") == 0)
1672 		fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM;
1673 	else
1674 		RETURN_ERROR(B_BAD_VALUE);
1675 
1676 	return B_OK;
1677 }
1678 
1679 
1680 status_t
1681 Volume::_CreateShineThroughDirectory(Directory* parent, const char* name,
1682 	Directory*& _directory)
1683 {
1684 	ShineThroughDirectory* directory = new(std::nothrow) ShineThroughDirectory(
1685 		fNextNodeID++);
1686 	if (directory == NULL)
1687 		RETURN_ERROR(B_NO_MEMORY);
1688 	BReference<ShineThroughDirectory> directoryReference(directory, true);
1689 
1690 	String nameString;
1691 	if (!nameString.SetTo(name))
1692 		RETURN_ERROR(B_NO_MEMORY);
1693 
1694 	status_t error = directory->Init(parent, nameString);
1695 	if (error != B_OK)
1696 		RETURN_ERROR(error);
1697 
1698 	parent->AddChild(directory);
1699 
1700 	fNodes.Insert(directory);
1701 	directoryReference.Detach();
1702 		// we keep the initial node reference for the table
1703 
1704 	_directory = directory;
1705 	return B_OK;
1706 }
1707 
1708 
1709 status_t
1710 Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
1711 {
1712 	// get the directories to map
1713 	const char* const* directories = NULL;
1714 
1715 	if (shineThroughSetting == NULL) {
1716 		// nothing specified -- derive from mount type
1717 		switch (fMountType) {
1718 			case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
1719 			case PACKAGE_FS_MOUNT_TYPE_HOME:
1720 				directories = kShineThroughDirectories;
1721 				break;
1722 			case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
1723 				return B_OK;
1724 			case PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT:
1725 				return B_BAD_VALUE;
1726 		}
1727 	} else if (strcmp(shineThroughSetting, "system") == 0)
1728 		directories = kShineThroughDirectories;
1729 	else if (strcmp(shineThroughSetting, "home") == 0)
1730 		directories = kShineThroughDirectories;
1731 	else if (strcmp(shineThroughSetting, "none") == 0)
1732 		directories = NULL;
1733 	else
1734 		RETURN_ERROR(B_BAD_VALUE);
1735 
1736 	if (directories == NULL)
1737 		return B_OK;
1738 
1739 	// iterate through the directory list and create the directories
1740 	while (const char* directoryName = *(directories++)) {
1741 		// create the directory
1742 		Directory* directory;
1743 		status_t error = _CreateShineThroughDirectory(fRootDirectory,
1744 			directoryName, directory);
1745 		if (error != B_OK)
1746 			RETURN_ERROR(error);
1747 	}
1748 
1749 	return B_OK;
1750 }
1751 
1752 
1753 status_t
1754 Volume::_PublishShineThroughDirectories()
1755 {
1756 	// Iterate through the root directory children and bind the shine-through
1757 	// directories to the respective mount point subdirectories.
1758 	Node* nextNode;
1759 	for (Node* node = fRootDirectory->FirstChild(); node != NULL;
1760 			node = nextNode) {
1761 		nextNode = fRootDirectory->NextChild(node);
1762 
1763 		// skip anything but shine-through directories
1764 		ShineThroughDirectory* directory
1765 			= dynamic_cast<ShineThroughDirectory*>(node);
1766 		if (directory == NULL)
1767 			continue;
1768 
1769 		const char* directoryName = directory->Name();
1770 
1771 		// look up the mount point subdirectory
1772 		struct vnode* vnode;
1773 		status_t error = vfs_entry_ref_to_vnode(fMountPoint.deviceID,
1774 			fMountPoint.nodeID, directoryName, &vnode);
1775 		if (error != B_OK) {
1776 			dprintf("packagefs: Failed to get shine-through directory \"%s\": "
1777 				"%s\n", directoryName, strerror(error));
1778 			_RemoveNode(directory);
1779 			continue;
1780 		}
1781 		CObjectDeleter<struct vnode> vnodePutter(vnode, &vfs_put_vnode);
1782 
1783 		// stat it
1784 		struct stat st;
1785 		error = vfs_stat_vnode(vnode, &st);
1786 		if (error != B_OK) {
1787 			dprintf("packagefs: Failed to stat shine-through directory \"%s\": "
1788 				"%s\n", directoryName, strerror(error));
1789 			_RemoveNode(directory);
1790 			continue;
1791 		}
1792 
1793 		if (!S_ISDIR(st.st_mode)) {
1794 			dprintf("packagefs: Shine-through entry \"%s\" is not a "
1795 				"directory\n", directoryName);
1796 			_RemoveNode(directory);
1797 			continue;
1798 		}
1799 
1800 		// publish the vnode, so the VFS will find it without asking us
1801 		directory->AcquireReference();
1802 		error = PublishVNode(directory);
1803 		if (error != B_OK) {
1804 			directory->ReleaseReference();
1805 			_RemoveNode(directory);
1806 			RETURN_ERROR(error);
1807 		}
1808 
1809 		// bind the directory
1810 		error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id,
1811 			directory->ID());
1812 
1813 		PutVNode(directory->ID());
1814 			// release our reference again -- on success
1815 			// vfs_bind_mount_directory() got one
1816 
1817 		if (error != B_OK)
1818 			RETURN_ERROR(error);
1819 	}
1820 
1821 	return B_OK;
1822 }
1823 
1824 
1825 status_t
1826 Volume::_AddPackageLinksDirectory()
1827 {
1828 	// called when mounting, so we don't need to lock the volume
1829 
1830 	PackageLinksDirectory* packageLinksDirectory
1831 		= fPackageFSRoot->GetPackageLinksDirectory();
1832 
1833 	NodeWriteLocker rootDirectoryWriteLocker(fRootDirectory);
1834 	NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory);
1835 
1836 	packageLinksDirectory->SetParent(fRootDirectory);
1837 	fRootDirectory->AddChild(packageLinksDirectory);
1838 
1839 	_AddPackageLinksNode(packageLinksDirectory);
1840 
1841 	packageLinksDirectory->SetListener(this);
1842 
1843 	return B_OK;
1844 }
1845 
1846 
1847 void
1848 Volume::_RemovePackageLinksDirectory()
1849 {
1850 	PackageLinksDirectory* packageLinksDirectory
1851 		= fPackageFSRoot->GetPackageLinksDirectory();
1852 
1853 	VolumeWriteLocker volumeLocker(this);
1854 	NodeWriteLocker rootDirectoryWriteLocker(fRootDirectory);
1855 	NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory);
1856 
1857 	if (packageLinksDirectory->Parent() == fRootDirectory) {
1858 		packageLinksDirectory->SetListener(NULL);
1859 		fRootDirectory->RemoveChild(packageLinksDirectory);
1860 		packageLinksDirectory->SetParent(NULL);
1861 	}
1862 }
1863 
1864 
1865 void
1866 Volume::_AddPackageLinksNode(Node* node)
1867 {
1868 	node->SetID(fNextNodeID++);
1869 
1870 	fNodes.Insert(node);
1871 	node->AcquireReference();
1872 
1873 	// If this is a directory, recursively add descendants. The directory tree
1874 	// for the package links isn't deep, so we can do recursion.
1875 	if (Directory* directory = dynamic_cast<Directory*>(node)) {
1876 		for (Node* child = directory->FirstChild(); child != NULL;
1877 				child = directory->NextChild(child)) {
1878 			NodeWriteLocker childWriteLocker(child);
1879 			_AddPackageLinksNode(child);
1880 		}
1881 	}
1882 }
1883 
1884 
1885 void
1886 Volume::_RemovePackageLinksNode(Node* node)
1887 {
1888 	// If this is a directory, recursively remove descendants. The directory
1889 	// tree for the package links isn't deep, so we can do recursion.
1890 	if (Directory* directory = dynamic_cast<Directory*>(node)) {
1891 		for (Node* child = directory->FirstChild(); child != NULL;
1892 				child = directory->NextChild(child)) {
1893 			NodeWriteLocker childWriteLocker(child);
1894 			_RemovePackageLinksNode(child);
1895 		}
1896 	}
1897 
1898 	fNodes.Remove(node);
1899 	node->ReleaseReference();
1900 }
1901 
1902 
1903 inline Volume*
1904 Volume::_SystemVolumeIfNotSelf() const
1905 {
1906 	if (Volume* systemVolume = fPackageFSRoot->SystemVolume())
1907 		return systemVolume == this ? NULL : systemVolume;
1908 	return NULL;
1909 }
1910 
1911 
1912 void
1913 Volume::_NotifyNodeAdded(Node* node)
1914 {
1915 	Node* key = node;
1916 
1917 	for (int i = 0; i < 2; i++) {
1918 		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
1919 			NodeListener* last = listener->PreviousNodeListener();
1920 
1921 			while (true) {
1922 				NodeListener* next = listener->NextNodeListener();
1923 
1924 				listener->NodeAdded(node);
1925 
1926 				if (listener == last)
1927 					break;
1928 
1929 				listener = next;
1930 			}
1931 		}
1932 
1933 		key = NULL;
1934 	}
1935 }
1936 
1937 
1938 void
1939 Volume::_NotifyNodeRemoved(Node* node)
1940 {
1941 	Node* key = node;
1942 
1943 	for (int i = 0; i < 2; i++) {
1944 		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
1945 			NodeListener* last = listener->PreviousNodeListener();
1946 
1947 			while (true) {
1948 				NodeListener* next = listener->NextNodeListener();
1949 
1950 				listener->NodeRemoved(node);
1951 
1952 				if (listener == last)
1953 					break;
1954 
1955 				listener = next;
1956 			}
1957 		}
1958 
1959 		key = NULL;
1960 	}
1961 }
1962 
1963 
1964 void
1965 Volume::_NotifyNodeChanged(Node* node, uint32 statFields,
1966 	const OldNodeAttributes& oldAttributes)
1967 {
1968 	Node* key = node;
1969 
1970 	for (int i = 0; i < 2; i++) {
1971 		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
1972 			NodeListener* last = listener->PreviousNodeListener();
1973 
1974 			while (true) {
1975 				NodeListener* next = listener->NextNodeListener();
1976 
1977 				listener->NodeChanged(node, statFields, oldAttributes);
1978 
1979 				if (listener == last)
1980 					break;
1981 
1982 				listener = next;
1983 			}
1984 		}
1985 
1986 		key = NULL;
1987 	}
1988 }
1989