* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageLinkDirectory.h"
#include <new>
#include <NodeMonitor.h>
#include <AutoDeleter.h>
#include "AutoPackageAttributeDirectoryCookie.h"
#include "DebugSupport.h"
#include "PackageLinksListener.h"
#include "StringConstants.h"
#include "Utils.h"
#include "Version.h"
#include "Volume.h"
PackageLinkDirectory::PackageLinkDirectory()
:
Directory(0),
fSelfLink(NULL),
fSettingsLink(NULL)
{
get_real_time(fModifiedTime);
}
PackageLinkDirectory::~PackageLinkDirectory()
{
if (fSelfLink != NULL)
fSelfLink->ReleaseReference();
if (fSettingsLink != NULL)
fSettingsLink->ReleaseReference();
while (DependencyLink* link = fDependencyLinks.RemoveHead())
link->ReleaseReference();
}
status_t
PackageLinkDirectory::Init(Package* package)
{
status_t error = Init(package->VersionedName());
if (error != B_OK)
RETURN_ERROR(error);
AddPackage(package, NULL);
return B_OK;
}
status_t
PackageLinkDirectory::Init(const String& name)
{
return Directory::Init(name);
}
timespec
PackageLinkDirectory::ModifiedTime() const
{
return fModifiedTime;
}
status_t
PackageLinkDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
{
Package* package = fPackages.Head();
if (package == NULL)
return B_ENTRY_NOT_FOUND;
AutoPackageAttributeDirectoryCookie* cookie = new(std::nothrow)
AutoPackageAttributeDirectoryCookie();
if (cookie == NULL)
return B_NO_MEMORY;
_cookie = cookie;
return B_OK;
}
status_t
PackageLinkDirectory::OpenAttribute(const StringKey& name, int openMode,
AttributeCookie*& _cookie)
{
Package* package = fPackages.Head();
if (package == NULL)
return B_ENTRY_NOT_FOUND;
return AutoPackageAttributes::OpenCookie(package, name, openMode, _cookie);
}
void
PackageLinkDirectory::AddPackage(Package* package,
PackageLinksListener* listener)
{
DirectoryWriteLocker writeLocker(this);
MountType mountType = package->Volume()->MountType();
Package* otherPackage = NULL;
for (PackageList::Iterator it = fPackages.GetIterator();
(otherPackage = it.Next()) != NULL;) {
if (otherPackage->Volume()->MountType() <= mountType)
break;
}
fPackages.InsertBefore(otherPackage, package);
package->SetLinkDirectory(this);
if (package == fPackages.Head())
_Update(listener);
}
void
PackageLinkDirectory::RemovePackage(Package* package,
PackageLinksListener* listener)
{
ASSERT(package->LinkDirectory() == this);
DirectoryWriteLocker writeLocker(this);
bool firstPackage = package == fPackages.Head();
package->SetLinkDirectory(NULL);
fPackages.Remove(package);
if (firstPackage)
_Update(listener);
}
void
PackageLinkDirectory::UpdatePackageDependencies(Package* package,
PackageLinksListener* listener)
{
ASSERT(package->LinkDirectory() == this);
DirectoryWriteLocker writeLocker(this);
if (package != fPackages.Head())
return;
_UpdateDependencies(listener);
}
status_t
PackageLinkDirectory::_Update(PackageLinksListener* listener)
{
while (DependencyLink* link = fDependencyLinks.RemoveHead())
_RemoveLink(link, listener);
Package* package = fPackages.Head();
if (package == NULL) {
_RemoveLink(fSelfLink, listener);
fSelfLink = NULL;
_RemoveLink(fSettingsLink, listener);
fSettingsLink = NULL;
return B_OK;
}
status_t error = _CreateOrUpdateLink(fSelfLink, package,
Link::TYPE_INSTALLATION_LOCATION, StringConstants::Get().kSelfLinkName,
listener);
if (error != B_OK)
RETURN_ERROR(error);
error = _CreateOrUpdateLink(fSettingsLink, package, Link::TYPE_SETTINGS,
StringConstants::Get().kSettingsLinkName, listener);
if (error != B_OK)
RETURN_ERROR(error);
return _UpdateDependencies(listener);
}
status_t
PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener)
{
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
Package* package = fPackages.Head();
if (package == NULL)
return B_OK;
for (DependencyList::ConstIterator it
= package->Dependencies().GetIterator();
Dependency* dependency = it.Next();) {
Resolvable* resolvable = dependency->Resolvable();
Package* resolvablePackage = resolvable != NULL
? resolvable->Package() : NULL;
Node* node = FindChild(dependency->FileName());
if (node != NULL) {
DependencyLink* link = static_cast<DependencyLink*>(node);
link->Update(resolvablePackage, listener);
} else {
DependencyLink* link = new(std::nothrow) DependencyLink(
resolvablePackage);
if (link == NULL)
return B_NO_MEMORY;
status_t error = link->Init(dependency->FileName());
if (error != B_OK) {
delete link;
RETURN_ERROR(error);
}
AddChild(link);
fDependencyLinks.Add(link);
if (listener != NULL)
listener->PackageLinkNodeAdded(link);
}
}
return B_OK;
}
void
PackageLinkDirectory::_RemoveLink(Link* link, PackageLinksListener* listener)
{
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
if (link != NULL) {
if (listener != NULL)
listener->PackageLinkNodeRemoved(link);
RemoveChild(link);
link->ReleaseReference();
}
}
status_t
PackageLinkDirectory::_CreateOrUpdateLink(Link*& link, Package* package,
Link::Type type, const String& name, PackageLinksListener* listener)
{
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
if (link == NULL) {
link = new(std::nothrow) Link(package, type);
if (link == NULL)
return B_NO_MEMORY;
status_t error = link->Init(name);
if (error != B_OK)
RETURN_ERROR(error);
AddChild(link);
if (listener != NULL)
listener->PackageLinkNodeAdded(link);
} else {
link->Update(package, listener);
}
return B_OK;
}