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