diff --git a/headers/os/package/PackageRoster.h b/headers/os/package/PackageRoster.h index d407da7e38..15487c23c1 100644 --- a/headers/os/package/PackageRoster.h +++ b/headers/os/package/PackageRoster.h @@ -28,6 +28,7 @@ struct BRepositoryConfigVisitor { }; +class BInstallationLocationInfo; class BPackageInfoSet; class BRepositoryCache; class BRepositoryConfig; @@ -60,6 +61,9 @@ public: status_t GetRepositoryConfig(const BString& name, BRepositoryConfig* repositoryConfig); + status_t GetInstallationLocationInfo( + BPackageInstallationLocation location, + BInstallationLocationInfo& _info); status_t GetActivePackages( BPackageInstallationLocation location, BPackageInfoSet& packageInfos); diff --git a/headers/private/package/DaemonClient.h b/headers/private/package/DaemonClient.h new file mode 100644 index 0000000000..e16b3e3499 --- /dev/null +++ b/headers/private/package/DaemonClient.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef _PACKAGE__PRIVATE__DAEMON_CLIENT_H_ +#define _PACKAGE__PRIVATE__DAEMON_CLIENT_H_ + + +#include +#include + + +namespace BPackageKit { + + +class BInstallationLocationInfo; +class BPackageInfoSet; + + +namespace BPrivate { + + +class BDaemonClient { +public: + BDaemonClient(); + ~BDaemonClient(); + + status_t GetInstallationLocationInfo( + BPackageInstallationLocation location, + BInstallationLocationInfo& _info); + +private: + status_t _InitMessenger(); + status_t _ExtractPackageInfoSet(const BMessage& message, + const char* field, BPackageInfoSet& _infos); + +private: + BMessenger fDaemonMessenger; +}; + + +} // namespace BPrivate +} // namespace BPackageKit + + +#endif // _PACKAGE__PRIVATE__DAEMON_CLIENT_H_ diff --git a/headers/private/package/DaemonDefs.h b/headers/private/package/DaemonDefs.h new file mode 100644 index 0000000000..3bde3b742b --- /dev/null +++ b/headers/private/package/DaemonDefs.h @@ -0,0 +1,46 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef _PACKAGE__PRIVATE__DAEMON_DEFS_H_ +#define _PACKAGE__PRIVATE__DAEMON_DEFS_H_ + + +namespace BPackageKit { +namespace BPrivate { + + +#define B_PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon" + + +enum BDaemonError { + B_DAEMON_OK +}; + + +// message codes for requests to and replies from the daemon +enum { + B_MESSAGE_GET_INSTALLATION_LOCATION_INFO = 'PKLI', + // "location": int32 + // the respective installation location constant + B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY = 'PKLR', + // "base directory device": int32 + // "base directory node": int64 + // "packages directory device": int32 + // "packages directory node": int64 + // "change count": int64 + // "active packages": message[] + // archived BPackageInfos of the active packages + // "inactive packages": message[] + // archived BPackageInfos of the inactive packages +}; + + +#endif // _PACKAGE__PRIVATE__DAEMON_DEFS_H_ + + +} // namespace BPrivate +} // namespace BPackageKit diff --git a/headers/private/package/PackageDaemonDefs.h b/headers/private/package/PackageDaemonDefs.h deleted file mode 100644 index ccb74b7df6..0000000000 --- a/headers/private/package/PackageDaemonDefs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Ingo Weinhold - */ -#ifndef _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_ -#define _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_ - - -namespace BPackageKit { -namespace BPrivate { - - -#define PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon" - - -// message codes for requests to and replies from the daemon -enum { - MESSAGE_GET_PACKAGES = 'PKGG', - // "location": int32 - // the respective installation location constant - MESSAGE_GET_PACKAGES_REPLY = 'PKGR' - // "active packages": string[] - // file names of the active packages (no path) - // "inactive packages": string[] - // file names of the inactive packages (no path) - -}; - - -#endif // _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_ - - -} // namespace BPrivate -} // namespace BPackageKit diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp new file mode 100644 index 0000000000..10d35c0de0 --- /dev/null +++ b/src/kits/package/DaemonClient.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include + +#include +#include + +#include + + +namespace BPackageKit { +namespace BPrivate { + + +BDaemonClient::BDaemonClient() + : + fDaemonMessenger() +{ +} + + +BDaemonClient::~BDaemonClient() +{ +} + + +status_t +BDaemonClient::GetInstallationLocationInfo( + BPackageInstallationLocation location, BInstallationLocationInfo& _info) +{ + status_t error = _InitMessenger(); + if (error != B_OK) + return error; + + // send the request + BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO); + error = request.AddInt32("location", location); + if (error != B_OK) + return error; + + BMessage reply; + fDaemonMessenger.SendMessage(&request, &reply); + if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY) + return B_ERROR; + + // extract the location info + int32 baseDirectoryDevice; + int64 baseDirectoryNode; + int32 packagesDirectoryDevice; + int64 packagesDirectoryNode; + int64 changeCount; + BPackageInfoSet activePackages; + BPackageInfoSet inactivePackages; + if ((error = reply.FindInt32("base directory device", &baseDirectoryDevice)) + != B_OK + || (error = reply.FindInt64("base directory node", &baseDirectoryNode)) + != B_OK + || (error = reply.FindInt32("packages directory device", + &packagesDirectoryDevice)) != B_OK + || (error = reply.FindInt64("packages directory node", + &packagesDirectoryNode)) != B_OK + || (error = _ExtractPackageInfoSet(reply, "active packages", + activePackages)) != B_OK + || (error = _ExtractPackageInfoSet(reply, "inactive packages", + inactivePackages)) != B_OK + || (error = reply.FindInt64("change count", &changeCount)) != B_OK) { + return error; + } + + _info.Unset(); + _info.SetLocation(location); + _info.SetBaseDirectoryRef(node_ref(baseDirectoryDevice, baseDirectoryNode)); + _info.SetPackagesDirectoryRef( + node_ref(packagesDirectoryDevice, packagesDirectoryNode)); + _info.SetActivePackageInfos(activePackages); + _info.SetInactivePackageInfos(inactivePackages); + _info.SetChangeCount(changeCount); + + return B_OK; +} + + +status_t +BDaemonClient::_InitMessenger() +{ + if (fDaemonMessenger.IsValid()) + return B_OK; + + // get the package daemon's address + status_t error; + fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error); + return error; +} + + +status_t +BDaemonClient::_ExtractPackageInfoSet(const BMessage& message, + const char* field, BPackageInfoSet& _infos) +{ + // get the number of items + type_code type; + int32 count; + if (message.GetInfo(field, &type, &count)) { + // the field is missing + return B_OK; + } + if (type != B_MESSAGE_TYPE) + return B_BAD_DATA; + + for (int32 i = 0; i < count; i++) { + BMessage archive; + status_t error = message.FindMessage(field, i, &archive); + if (error != B_OK) + return error; + + BPackageInfo info(&archive, &error); + if (error != B_OK) + return error; + + error = _infos.AddInfo(info); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +} // namespace BPrivate +} // namespace BPackageKit diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index a3c9bede3d..8ebcc9ce2f 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -51,6 +51,7 @@ SharedLibrary libpackage.so BlockBufferCacheNoLock.cpp ChecksumAccessors.cpp Context.cpp + DaemonClient.cpp DropRepositoryRequest.cpp FetchFileJob.cpp InstallationLocationInfo.cpp diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp index 62b4bb90ad..9e5a3a3bcf 100644 --- a/src/kits/package/PackageRoster.cpp +++ b/src/kits/package/PackageRoster.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -28,7 +29,7 @@ #include #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) -# include +# include #endif @@ -188,6 +189,21 @@ BPackageRoster::GetRepositoryConfig(const BString& name, } +status_t +BPackageRoster::GetInstallationLocationInfo( + BPackageInstallationLocation location, BInstallationLocationInfo& _info) +{ +// This method makes sense only on an installed Haiku, but not for the build +// tools. +#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) + return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo( + location, _info); +#else + return B_NOT_SUPPORTED; +#endif +} + + status_t BPackageRoster::GetActivePackages(BPackageInstallationLocation location, BPackageInfoSet& packageInfos) @@ -195,67 +211,12 @@ BPackageRoster::GetActivePackages(BPackageInstallationLocation location, // This method makes sense only on an installed Haiku, but not for the build // tools. #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) - // check the given location - directory_which packagesDirectory; - switch (location) { - case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM: - packagesDirectory = B_SYSTEM_PACKAGES_DIRECTORY; - break; - case B_PACKAGE_INSTALLATION_LOCATION_COMMON: - packagesDirectory = B_COMMON_PACKAGES_DIRECTORY; - break; - case B_PACKAGE_INSTALLATION_LOCATION_HOME: - packagesDirectory = B_USER_PACKAGES_DIRECTORY; - break; - default: - return B_BAD_VALUE; - } - - // get the package daemon's address - status_t error; - BMessenger messenger(PACKAGE_DAEMON_APP_SIGNATURE, -1, &error); + BInstallationLocationInfo info; + status_t error = GetInstallationLocationInfo(location, info); if (error != B_OK) return error; - // request a list of packages - BMessage request(BPackageKit::BPrivate::MESSAGE_GET_PACKAGES); - error = request.AddInt32("location", location); - if (error != B_OK) - return error; - - BMessage reply; - messenger.SendMessage(&request, &reply); - if (reply.what != BPackageKit::BPrivate::MESSAGE_GET_PACKAGES_REPLY) - return B_ERROR; - - // find and open the packages directory - BPath packagesDirPath; - error = find_directory(packagesDirectory, &packagesDirPath); - if (error != B_OK) - return error; - - // iterate through the packages - const char* packageFileName; - for (int32 i = 0; - reply.FindString("active packages", i, &packageFileName) == B_OK; i++) { - // get the full package file path - BPath packagePath; - error = packagePath.SetTo(packagesDirPath.Path(), packageFileName); - if (error != B_OK) - continue; - - // read the package info from the file - BPackageInfo info; - error = info.ReadFromPackageFile(packagePath.Path()); - if (error != B_OK || info.InitCheck() != B_OK) - continue; - - // add the info - error = packageInfos.AddInfo(info); - if (error != B_OK) - return error; - } - + packageInfos = info.ActivePackageInfos(); return B_OK; #else return B_NOT_SUPPORTED; diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp index e5ebee0515..58d76c045f 100644 --- a/src/servers/package/PackageDaemon.cpp +++ b/src/servers/package/PackageDaemon.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include "DebugSupport.h" #include "Root.h" @@ -28,7 +28,7 @@ using namespace BPackageKit::BPrivate; PackageDaemon::PackageDaemon(status_t* _error) : - BServer(PACKAGE_DAEMON_APP_SIGNATURE, false, _error), + BServer(B_PACKAGE_DAEMON_APP_SIGNATURE, false, _error), fSystemRoot(NULL), fRoots(10, true), fVolumeWatcher() @@ -85,12 +85,12 @@ PackageDaemon::MessageReceived(BMessage* message) break; } - case MESSAGE_GET_PACKAGES: + case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO: { if (fSystemRoot == NULL) break; - fSystemRoot->HandleGetPackagesRequest(DetachCurrentMessage()); + fSystemRoot->HandleGetLocationInfoRequest(DetachCurrentMessage()); break; } diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp index b2d63b4bf5..fd0c4565c0 100644 --- a/src/servers/package/Root.cpp +++ b/src/servers/package/Root.cpp @@ -42,11 +42,11 @@ private: }; -// #pragma mark - VolumeJob +// #pragma mark - HandleGetLocationInfoRequestJob -struct Root::HandleGetPackagesJob : public Job { - HandleGetPackagesJob(Root* root, BMessage* message) +struct Root::HandleGetLocationInfoRequestJob : public Job { + HandleGetLocationInfoRequestJob(Root* root, BMessage* message) : fRoot(root), fMessage(message) @@ -55,7 +55,7 @@ struct Root::HandleGetPackagesJob : public Job { virtual void Do() { - fRoot->_HandleGetPackagesRequest(fMessage.Get()); + fRoot->_HandleGetLocationInfoRequest(fMessage.Get()); } private: @@ -209,10 +209,10 @@ Root::FindVolume(dev_t deviceID) const void -Root::HandleGetPackagesRequest(BMessage* message) +Root::HandleGetLocationInfoRequest(BMessage* message) { - HandleGetPackagesJob* job - = new(std::nothrow) HandleGetPackagesJob(this, message); + HandleGetLocationInfoRequestJob* job + = new(std::nothrow) HandleGetLocationInfoRequestJob(this, message); if (job == NULL) { delete message; return; @@ -314,7 +314,7 @@ Root::_ProcessNodeMonitorEvents(Volume* volume) void -Root::_HandleGetPackagesRequest(BMessage* message) +Root::_HandleGetLocationInfoRequest(BMessage* message) { int32 location; if (message->FindInt32("location", &location) != B_OK @@ -341,7 +341,7 @@ Root::_HandleGetPackagesRequest(BMessage* message) } if (volume != NULL) - volume->HandleGetPackagesRequest(message); + volume->HandleGetLocationInfoRequest(message); } diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h index ad84421aa9..62aba1b8d3 100644 --- a/src/servers/package/Root.h +++ b/src/servers/package/Root.h @@ -41,7 +41,7 @@ public: Volume* FindVolume(dev_t deviceID) const; - void HandleGetPackagesRequest(BMessage* message); + void HandleGetLocationInfoRequest(BMessage* message); private: // Volume::Listener @@ -52,9 +52,9 @@ protected: private: struct VolumeJob; - struct HandleGetPackagesJob; + struct HandleGetLocationInfoRequestJob; - friend struct HandleGetPackagesJob; + friend struct HandleGetLocationInfoRequestJob; private: Volume** _GetVolume(PackageFSMountType mountType); @@ -63,7 +63,8 @@ private: void _InitPackages(Volume* volume); void _DeleteVolume(Volume* volume); void _ProcessNodeMonitorEvents(Volume* volume); - void _HandleGetPackagesRequest(BMessage* message); + void _HandleGetLocationInfoRequest( + BMessage* message); status_t _QueueJob(Job* job); diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp index abc5732f7b..401d760430 100644 --- a/src/servers/package/Volume.cpp +++ b/src/servers/package/Volume.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include "DebugSupport.h" @@ -104,7 +104,9 @@ Volume::Volume(BLooper* looper) fPendingNodeMonitorEventsLock("pending node monitor events"), fPendingNodeMonitorEvents(), fPackagesToBeActivated(), - fPackagesToBeDeactivated() + fPackagesToBeDeactivated(), + fChangeCount(0), + fLocationInfoReply(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY) { looper->AddHandler(this); } @@ -335,20 +337,49 @@ INFORM("Volume::InitialVerify(%p, %p)\n", nextVolume, nextNextVolume); void -Volume::HandleGetPackagesRequest(BMessage* message) +Volume::HandleGetLocationInfoRequest(BMessage* message) { - BMessage reply(MESSAGE_GET_PACKAGES_REPLY); + // If the cached reply message is up-to-date, just send it. + int64 changeCount; + if (fLocationInfoReply.FindInt64("change count", &changeCount) == B_OK + && changeCount == fChangeCount) { + message->SendReply(&fLocationInfoReply, (BHandler*)NULL, + kCommunicationTimeout); + return; + } + + // rebuild the reply message + fLocationInfoReply.MakeEmpty(); + + if (fLocationInfoReply.AddInt32("base directory device", + fRootDirectoryRef.device) != B_OK + || fLocationInfoReply.AddInt64("base directory node", + fRootDirectoryRef.node) != B_OK + || fLocationInfoReply.AddInt32("packages directory device", + fPackagesDirectoryRef.device) != B_OK + || fLocationInfoReply.AddInt64("packages directory node", + fPackagesDirectoryRef.node) != B_OK) { + return; + } for (PackageFileNameHashTable::Iterator it = fPackagesByFileName.GetIterator(); it.HasNext();) { Package* package = it.Next(); const char* fieldName = package->IsActive() ? "active packages" : "inactive packages"; - if (reply.AddString(fieldName, package->FileName()) != B_OK) + BMessage packageArchive; + if (package->Info().Archive(&packageArchive) != B_OK + || fLocationInfoReply.AddMessage(fieldName, &packageArchive) + != B_OK) { return; + } } - message->SendReply(&reply, (BHandler*)NULL, kCommunicationTimeout); + if (fLocationInfoReply.AddInt64("change count", fChangeCount) != B_OK) + return; + + message->SendReply(&fLocationInfoReply, (BHandler*)NULL, + kCommunicationTimeout); } @@ -514,6 +545,7 @@ fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size()); for (PackageSet::iterator it = fPackagesToBeActivated.begin(); it != fPackagesToBeActivated.end(); ++it) { (*it)->SetActive(true); + fChangeCount++; } for (PackageSet::iterator it = fPackagesToBeDeactivated.begin(); @@ -671,8 +703,7 @@ INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name); return; } - fPackagesByFileName.Insert(package); - fPackagesByNodeRef.Insert(package); + _AddPackage(package); packageDeleter.Detach(); try { @@ -731,11 +762,19 @@ Volume::_FillInActivationChangeItem(PackageFSActivationChangeItem* item, } +void +Volume::_AddPackage(Package* package) +{ + fPackagesByFileName.Insert(package); + fPackagesByNodeRef.Insert(package); +} + void Volume::_RemovePackage(Package* package) { fPackagesByFileName.Remove(package); fPackagesByNodeRef.Remove(package); + fChangeCount++; } @@ -762,8 +801,7 @@ Volume::_ReadPackagesDirectory() status_t error = package->Init(entry); if (error == B_OK) { - fPackagesByFileName.Insert(package); - fPackagesByNodeRef.Insert(package); + _AddPackage(package); packageDeleter.Detach(); } } diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h index 404f6c4a57..8e65ff3fe1 100644 --- a/src/servers/package/Volume.h +++ b/src/servers/package/Volume.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -48,7 +49,7 @@ public: bool activeOnly); void InitialVerify(Volume* nextVolume, Volume* nextNextVolume); - void HandleGetPackagesRequest(BMessage* message); + void HandleGetLocationInfoRequest(BMessage* message); void Unmounted(); @@ -105,6 +106,8 @@ private: PackageFSActivationChangeItem* item, PackageFSActivationChangeType type, Package* package, char*& nameBuffer); + + void _AddPackage(Package* package); void _RemovePackage(Package* package); status_t _ReadPackagesDirectory(); @@ -133,6 +136,8 @@ private: NodeMonitorEventList fPendingNodeMonitorEvents; PackageSet fPackagesToBeActivated; PackageSet fPackagesToBeDeactivated; + int64 fChangeCount; + BMessage fLocationInfoReply; };