xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package_links/PackageLinkDirectory.cpp (revision 0059775c1d6454bba41a9f0defebc4b6151838fa)
11e7416d9SIngo Weinhold /*
21e7416d9SIngo Weinhold  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
31e7416d9SIngo Weinhold  * Distributed under the terms of the MIT License.
41e7416d9SIngo Weinhold  */
51e7416d9SIngo Weinhold 
61e7416d9SIngo Weinhold 
71e7416d9SIngo Weinhold #include "PackageLinkDirectory.h"
81e7416d9SIngo Weinhold 
91e7416d9SIngo Weinhold #include <new>
101e7416d9SIngo Weinhold 
111e7416d9SIngo Weinhold #include <NodeMonitor.h>
121e7416d9SIngo Weinhold 
131e7416d9SIngo Weinhold #include <AutoDeleter.h>
141e7416d9SIngo Weinhold 
15d0126238SIngo Weinhold #include "AutoPackageAttributeDirectoryCookie.h"
161e7416d9SIngo Weinhold #include "DebugSupport.h"
171e7416d9SIngo Weinhold #include "PackageLinksListener.h"
18d07c930cSIngo Weinhold #include "StringConstants.h"
191e7416d9SIngo Weinhold #include "Utils.h"
201e7416d9SIngo Weinhold #include "Version.h"
211e7416d9SIngo Weinhold #include "Volume.h"
221e7416d9SIngo Weinhold 
231e7416d9SIngo Weinhold 
PackageLinkDirectory()241e7416d9SIngo Weinhold PackageLinkDirectory::PackageLinkDirectory()
251e7416d9SIngo Weinhold 	:
261e7416d9SIngo Weinhold 	Directory(0),
271e7416d9SIngo Weinhold 		// the ID needs to be assigned later, when added to a volume
281e7416d9SIngo Weinhold 	fSelfLink(NULL),
291e7416d9SIngo Weinhold 	fSettingsLink(NULL)
301e7416d9SIngo Weinhold {
311e7416d9SIngo Weinhold 	get_real_time(fModifiedTime);
321e7416d9SIngo Weinhold }
331e7416d9SIngo Weinhold 
341e7416d9SIngo Weinhold 
~PackageLinkDirectory()351e7416d9SIngo Weinhold PackageLinkDirectory::~PackageLinkDirectory()
361e7416d9SIngo Weinhold {
371e7416d9SIngo Weinhold 	if (fSelfLink != NULL)
381e7416d9SIngo Weinhold 		fSelfLink->ReleaseReference();
391e7416d9SIngo Weinhold 	if (fSettingsLink != NULL)
401e7416d9SIngo Weinhold 		fSettingsLink->ReleaseReference();
411e7416d9SIngo Weinhold 
421e7416d9SIngo Weinhold 	while (DependencyLink* link = fDependencyLinks.RemoveHead())
431e7416d9SIngo Weinhold 		link->ReleaseReference();
441e7416d9SIngo Weinhold }
451e7416d9SIngo Weinhold 
461e7416d9SIngo Weinhold 
471e7416d9SIngo Weinhold status_t
Init(Package * package)48dfb09e12SAugustin Cavalier PackageLinkDirectory::Init(Package* package)
491e7416d9SIngo Weinhold {
501e7416d9SIngo Weinhold 	// init the directory/node
51dfb09e12SAugustin Cavalier 	status_t error = Init(package->VersionedName());
521e7416d9SIngo Weinhold 	if (error != B_OK)
531e7416d9SIngo Weinhold 		RETURN_ERROR(error);
541e7416d9SIngo Weinhold 
551e7416d9SIngo Weinhold 	// add the package
561e7416d9SIngo Weinhold 	AddPackage(package, NULL);
571e7416d9SIngo Weinhold 
581e7416d9SIngo Weinhold 	return B_OK;
591e7416d9SIngo Weinhold }
601e7416d9SIngo Weinhold 
611e7416d9SIngo Weinhold 
621e7416d9SIngo Weinhold status_t
Init(const String & name)63dfb09e12SAugustin Cavalier PackageLinkDirectory::Init(const String& name)
641e7416d9SIngo Weinhold {
65dfb09e12SAugustin Cavalier 	return Directory::Init(name);
661e7416d9SIngo Weinhold }
671e7416d9SIngo Weinhold 
681e7416d9SIngo Weinhold 
691e7416d9SIngo Weinhold timespec
ModifiedTime() const701e7416d9SIngo Weinhold PackageLinkDirectory::ModifiedTime() const
711e7416d9SIngo Weinhold {
721e7416d9SIngo Weinhold 	return fModifiedTime;
731e7416d9SIngo Weinhold }
741e7416d9SIngo Weinhold 
75d0126238SIngo Weinhold 
76d0126238SIngo Weinhold status_t
OpenAttributeDirectory(AttributeDirectoryCookie * & _cookie)77d0126238SIngo Weinhold PackageLinkDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
78d0126238SIngo Weinhold {
79d0126238SIngo Weinhold 	Package* package = fPackages.Head();
80d0126238SIngo Weinhold 	if (package == NULL)
81d0126238SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
82d0126238SIngo Weinhold 
83d0126238SIngo Weinhold 	AutoPackageAttributeDirectoryCookie* cookie = new(std::nothrow)
84d0126238SIngo Weinhold 		AutoPackageAttributeDirectoryCookie();
85d0126238SIngo Weinhold 	if (cookie == NULL)
86d0126238SIngo Weinhold 		return B_NO_MEMORY;
87d0126238SIngo Weinhold 
88d0126238SIngo Weinhold 	_cookie = cookie;
89d0126238SIngo Weinhold 	return B_OK;
90d0126238SIngo Weinhold }
91d0126238SIngo Weinhold 
92d0126238SIngo Weinhold 
93d0126238SIngo Weinhold status_t
OpenAttribute(const StringKey & name,int openMode,AttributeCookie * & _cookie)94d0126238SIngo Weinhold PackageLinkDirectory::OpenAttribute(const StringKey& name, int openMode,
95d0126238SIngo Weinhold 	AttributeCookie*& _cookie)
96d0126238SIngo Weinhold {
97d0126238SIngo Weinhold 	Package* package = fPackages.Head();
98d0126238SIngo Weinhold 	if (package == NULL)
99d0126238SIngo Weinhold 		return B_ENTRY_NOT_FOUND;
100d0126238SIngo Weinhold 
101d0126238SIngo Weinhold 	return AutoPackageAttributes::OpenCookie(package, name, openMode, _cookie);
102d0126238SIngo Weinhold }
103d0126238SIngo Weinhold 
104d0126238SIngo Weinhold 
1051e7416d9SIngo Weinhold void
AddPackage(Package * package,PackageLinksListener * listener)1061e7416d9SIngo Weinhold PackageLinkDirectory::AddPackage(Package* package,
1071e7416d9SIngo Weinhold 	PackageLinksListener* listener)
1081e7416d9SIngo Weinhold {
109*0059775cSAugustin Cavalier 	DirectoryWriteLocker writeLocker(this);
1101e7416d9SIngo Weinhold 
1111e7416d9SIngo Weinhold 	// Find the insertion point in the list. We sort by mount type -- the more
1121e7416d9SIngo Weinhold 	// specific the higher the priority.
1131e7416d9SIngo Weinhold 	MountType mountType = package->Volume()->MountType();
1141e7416d9SIngo Weinhold 	Package* otherPackage = NULL;
1151e7416d9SIngo Weinhold 	for (PackageList::Iterator it = fPackages.GetIterator();
1161e7416d9SIngo Weinhold 			(otherPackage = it.Next()) != NULL;) {
1171e7416d9SIngo Weinhold 		if (otherPackage->Volume()->MountType() <= mountType)
1181e7416d9SIngo Weinhold 			break;
1191e7416d9SIngo Weinhold 	}
1201e7416d9SIngo Weinhold 
1211e7416d9SIngo Weinhold 	fPackages.InsertBefore(otherPackage, package);
1221e7416d9SIngo Weinhold 	package->SetLinkDirectory(this);
1231e7416d9SIngo Weinhold 
1241e7416d9SIngo Weinhold 	if (package == fPackages.Head())
1251e7416d9SIngo Weinhold 		_Update(listener);
1261e7416d9SIngo Weinhold }
1271e7416d9SIngo Weinhold 
1281e7416d9SIngo Weinhold 
1291e7416d9SIngo Weinhold void
RemovePackage(Package * package,PackageLinksListener * listener)1301e7416d9SIngo Weinhold PackageLinkDirectory::RemovePackage(Package* package,
1311e7416d9SIngo Weinhold 	PackageLinksListener* listener)
1321e7416d9SIngo Weinhold {
1331e7416d9SIngo Weinhold 	ASSERT(package->LinkDirectory() == this);
1341e7416d9SIngo Weinhold 
135*0059775cSAugustin Cavalier 	DirectoryWriteLocker writeLocker(this);
1361e7416d9SIngo Weinhold 
1371e7416d9SIngo Weinhold 	bool firstPackage = package == fPackages.Head();
1381e7416d9SIngo Weinhold 
1391e7416d9SIngo Weinhold 	package->SetLinkDirectory(NULL);
1401e7416d9SIngo Weinhold 	fPackages.Remove(package);
1411e7416d9SIngo Weinhold 
1421e7416d9SIngo Weinhold 	if (firstPackage)
1431e7416d9SIngo Weinhold 		_Update(listener);
1441e7416d9SIngo Weinhold }
1451e7416d9SIngo Weinhold 
1461e7416d9SIngo Weinhold 
1471e7416d9SIngo Weinhold void
UpdatePackageDependencies(Package * package,PackageLinksListener * listener)1481e7416d9SIngo Weinhold PackageLinkDirectory::UpdatePackageDependencies(Package* package,
1491e7416d9SIngo Weinhold 	PackageLinksListener* listener)
1501e7416d9SIngo Weinhold {
1511e7416d9SIngo Weinhold 	ASSERT(package->LinkDirectory() == this);
1521e7416d9SIngo Weinhold 
153*0059775cSAugustin Cavalier 	DirectoryWriteLocker writeLocker(this);
1541e7416d9SIngo Weinhold 
1551e7416d9SIngo Weinhold 	// We only need to update, if that head package is affected.
1561e7416d9SIngo Weinhold 	if (package != fPackages.Head())
1571e7416d9SIngo Weinhold 		return;
1581e7416d9SIngo Weinhold 
1591e7416d9SIngo Weinhold 	_UpdateDependencies(listener);
1601e7416d9SIngo Weinhold }
1611e7416d9SIngo Weinhold 
1621e7416d9SIngo Weinhold 
1631e7416d9SIngo Weinhold status_t
_Update(PackageLinksListener * listener)1641e7416d9SIngo Weinhold PackageLinkDirectory::_Update(PackageLinksListener* listener)
1651e7416d9SIngo Weinhold {
1661e7416d9SIngo Weinhold 	// Always remove all dependency links -- if there's still a package, they
1671e7416d9SIngo Weinhold 	// will be re-created below.
1681e7416d9SIngo Weinhold 	while (DependencyLink* link = fDependencyLinks.RemoveHead())
1691e7416d9SIngo Weinhold 		_RemoveLink(link, listener);
1701e7416d9SIngo Weinhold 
1711e7416d9SIngo Weinhold 	// check, if empty
1721e7416d9SIngo Weinhold 	Package* package = fPackages.Head();
1731e7416d9SIngo Weinhold 	if (package == NULL) {
1741e7416d9SIngo Weinhold 		// remove self and settings link
1751e7416d9SIngo Weinhold 		_RemoveLink(fSelfLink, listener);
1761e7416d9SIngo Weinhold 		fSelfLink = NULL;
1771e7416d9SIngo Weinhold 
1781e7416d9SIngo Weinhold 		_RemoveLink(fSettingsLink, listener);
1791e7416d9SIngo Weinhold 		fSettingsLink = NULL;
1801e7416d9SIngo Weinhold 
1811e7416d9SIngo Weinhold 		return B_OK;
1821e7416d9SIngo Weinhold 	}
1831e7416d9SIngo Weinhold 
1841e7416d9SIngo Weinhold 	// create/update self and settings link
1851e7416d9SIngo Weinhold 	status_t error = _CreateOrUpdateLink(fSelfLink, package,
186d07c930cSIngo Weinhold 		Link::TYPE_INSTALLATION_LOCATION, StringConstants::Get().kSelfLinkName,
187d07c930cSIngo Weinhold 		listener);
1881e7416d9SIngo Weinhold 	if (error != B_OK)
1891e7416d9SIngo Weinhold 		RETURN_ERROR(error);
1901e7416d9SIngo Weinhold 
1911e7416d9SIngo Weinhold 	error = _CreateOrUpdateLink(fSettingsLink, package, Link::TYPE_SETTINGS,
192d07c930cSIngo Weinhold 		StringConstants::Get().kSettingsLinkName, listener);
1931e7416d9SIngo Weinhold 	if (error != B_OK)
1941e7416d9SIngo Weinhold 		RETURN_ERROR(error);
1951e7416d9SIngo Weinhold 
1961e7416d9SIngo Weinhold 	// update the dependency links
1971e7416d9SIngo Weinhold 	return _UpdateDependencies(listener);
1981e7416d9SIngo Weinhold }
1991e7416d9SIngo Weinhold 
2001e7416d9SIngo Weinhold 
2011e7416d9SIngo Weinhold status_t
_UpdateDependencies(PackageLinksListener * listener)2021e7416d9SIngo Weinhold PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener)
2031e7416d9SIngo Weinhold {
204*0059775cSAugustin Cavalier 	ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
205*0059775cSAugustin Cavalier 
2061e7416d9SIngo Weinhold 	Package* package = fPackages.Head();
2071e7416d9SIngo Weinhold 	if (package == NULL)
2081e7416d9SIngo Weinhold 		return B_OK;
2091e7416d9SIngo Weinhold 
2101e7416d9SIngo Weinhold 	// Iterate through the package's dependencies
2111e7416d9SIngo Weinhold 	for (DependencyList::ConstIterator it
2121e7416d9SIngo Weinhold 				= package->Dependencies().GetIterator();
2131e7416d9SIngo Weinhold 			Dependency* dependency = it.Next();) {
2141e7416d9SIngo Weinhold 		Resolvable* resolvable = dependency->Resolvable();
2151e7416d9SIngo Weinhold 		Package* resolvablePackage = resolvable != NULL
2161e7416d9SIngo Weinhold 			? resolvable->Package() : NULL;
2171e7416d9SIngo Weinhold 
218b8ab901eSIngo Weinhold 		Node* node = FindChild(dependency->FileName());
2191e7416d9SIngo Weinhold 		if (node != NULL) {
2201e7416d9SIngo Weinhold 			// link already exists -- update
2211e7416d9SIngo Weinhold 			DependencyLink* link = static_cast<DependencyLink*>(node);
2221e7416d9SIngo Weinhold 			link->Update(resolvablePackage, listener);
2231e7416d9SIngo Weinhold 		} else {
2241e7416d9SIngo Weinhold 			// no link for the dependency yet -- create one
2251e7416d9SIngo Weinhold 			DependencyLink* link = new(std::nothrow) DependencyLink(
2261e7416d9SIngo Weinhold 				resolvablePackage);
2271e7416d9SIngo Weinhold 			if (link == NULL)
2281e7416d9SIngo Weinhold 				return B_NO_MEMORY;
2291e7416d9SIngo Weinhold 
230dfb09e12SAugustin Cavalier 			status_t error = link->Init(dependency->FileName());
2311e7416d9SIngo Weinhold 			if (error != B_OK) {
2321e7416d9SIngo Weinhold 				delete link;
2331e7416d9SIngo Weinhold 				RETURN_ERROR(error);
2341e7416d9SIngo Weinhold 			}
2351e7416d9SIngo Weinhold 
2361e7416d9SIngo Weinhold 			AddChild(link);
2371e7416d9SIngo Weinhold 			fDependencyLinks.Add(link);
2381e7416d9SIngo Weinhold 
239*0059775cSAugustin Cavalier 			if (listener != NULL)
2401e7416d9SIngo Weinhold 				listener->PackageLinkNodeAdded(link);
2411e7416d9SIngo Weinhold 		}
2421e7416d9SIngo Weinhold 	}
2431e7416d9SIngo Weinhold 
2441e7416d9SIngo Weinhold 	return B_OK;
2451e7416d9SIngo Weinhold }
2461e7416d9SIngo Weinhold 
2471e7416d9SIngo Weinhold 
2481e7416d9SIngo Weinhold void
_RemoveLink(Link * link,PackageLinksListener * listener)2491e7416d9SIngo Weinhold PackageLinkDirectory::_RemoveLink(Link* link, PackageLinksListener* listener)
2501e7416d9SIngo Weinhold {
251*0059775cSAugustin Cavalier 	ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
252*0059775cSAugustin Cavalier 
2531e7416d9SIngo Weinhold 	if (link != NULL) {
2541e7416d9SIngo Weinhold 		if (listener != NULL)
2551e7416d9SIngo Weinhold 			listener->PackageLinkNodeRemoved(link);
2561e7416d9SIngo Weinhold 
2571e7416d9SIngo Weinhold 		RemoveChild(link);
2581e7416d9SIngo Weinhold 		link->ReleaseReference();
2591e7416d9SIngo Weinhold 	}
2601e7416d9SIngo Weinhold }
2611e7416d9SIngo Weinhold 
2621e7416d9SIngo Weinhold 
2631e7416d9SIngo Weinhold status_t
_CreateOrUpdateLink(Link * & link,Package * package,Link::Type type,const String & name,PackageLinksListener * listener)2641e7416d9SIngo Weinhold PackageLinkDirectory::_CreateOrUpdateLink(Link*& link, Package* package,
265d07c930cSIngo Weinhold 	Link::Type type, const String& name, PackageLinksListener* listener)
2661e7416d9SIngo Weinhold {
267*0059775cSAugustin Cavalier 	ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
268*0059775cSAugustin Cavalier 
2691e7416d9SIngo Weinhold 	if (link == NULL) {
2701e7416d9SIngo Weinhold 		link = new(std::nothrow) Link(package, type);
2711e7416d9SIngo Weinhold 		if (link == NULL)
2721e7416d9SIngo Weinhold 			return B_NO_MEMORY;
2731e7416d9SIngo Weinhold 
274dfb09e12SAugustin Cavalier 		status_t error = link->Init(name);
2751e7416d9SIngo Weinhold 		if (error != B_OK)
2761e7416d9SIngo Weinhold 			RETURN_ERROR(error);
2771e7416d9SIngo Weinhold 
2781e7416d9SIngo Weinhold 		AddChild(link);
2791e7416d9SIngo Weinhold 
280*0059775cSAugustin Cavalier 		if (listener != NULL)
2811e7416d9SIngo Weinhold 			listener->PackageLinkNodeAdded(link);
2821e7416d9SIngo Weinhold 	} else {
2831e7416d9SIngo Weinhold 		link->Update(package, listener);
2841e7416d9SIngo Weinhold 	}
2851e7416d9SIngo Weinhold 
2861e7416d9SIngo Weinhold 	return B_OK;
2871e7416d9SIngo Weinhold }
288