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