package daemon: Add package monitoring and de-/activation
* packagefs: Disable (comment out) node monitoring of the packages
directory.
* package daemon:
- When a packagefs volume is added load the respective packages
directory and get from the volume which of the packages are
activated.
- Add node monitoring for the packages directory and
activate/deactivate packages as packages are added/removed.
This commit is contained in:
@@ -161,14 +161,15 @@ struct Volume::DomainDirectoryListener : NotificationListener {
|
|||||||
virtual void EventOccurred(NotificationService& service,
|
virtual void EventOccurred(NotificationService& service,
|
||||||
const KMessage* event)
|
const KMessage* event)
|
||||||
{
|
{
|
||||||
DomainDirectoryEventJob* job = new(std::nothrow)
|
// TODO: Remove!
|
||||||
DomainDirectoryEventJob(fVolume, fDomain);
|
// DomainDirectoryEventJob* job = new(std::nothrow)
|
||||||
if (job == NULL || job->Init(event)) {
|
// DomainDirectoryEventJob(fVolume, fDomain);
|
||||||
delete job;
|
// if (job == NULL || job->Init(event)) {
|
||||||
return;
|
// delete job;
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
fVolume->_PushJob(job);
|
//
|
||||||
|
// fVolume->_PushJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
SubDir HAIKU_TOP src servers package ;
|
SubDir HAIKU_TOP src servers package ;
|
||||||
|
|
||||||
UsePrivateSystemHeaders ;
|
UsePrivateSystemHeaders ;
|
||||||
UsePrivateHeaders app package shared ;
|
UsePrivateHeaders app kernel package shared ;
|
||||||
|
|
||||||
Server package_daemon
|
Server package_daemon
|
||||||
:
|
:
|
||||||
DebugSupport.cpp
|
DebugSupport.cpp
|
||||||
|
Package.cpp
|
||||||
PackageDaemon.cpp
|
PackageDaemon.cpp
|
||||||
Root.cpp
|
Root.cpp
|
||||||
Volume.cpp
|
Volume.cpp
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Package.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <File.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include "DebugSupport.h"
|
||||||
|
|
||||||
|
|
||||||
|
Package::Package()
|
||||||
|
:
|
||||||
|
fNodeRef(),
|
||||||
|
fFileName(),
|
||||||
|
fInfo(),
|
||||||
|
fActive(false),
|
||||||
|
fFileNameHashTableNext(NULL),
|
||||||
|
fNodeRefHashTableNext(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Package::~Package()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Package::Init(const entry_ref& entryRef)
|
||||||
|
{
|
||||||
|
// init the file name
|
||||||
|
fFileName = entryRef.name;
|
||||||
|
if (fFileName.IsEmpty())
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
|
// open the file and get the node_ref
|
||||||
|
BFile file;
|
||||||
|
status_t error = file.SetTo(&entryRef, B_READ_ONLY);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
error = file.GetNodeRef(&fNodeRef);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// get the package info
|
||||||
|
int fd = file.Dup();
|
||||||
|
if (fd < 0)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
FileDescriptorCloser fdCloser(fd);
|
||||||
|
|
||||||
|
error = fInfo.ReadFromPackageFile(fd);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <ingo_weinhold@gmx.de>
|
||||||
|
*/
|
||||||
|
#ifndef PACKAGE_H
|
||||||
|
#define PACKAGE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <Node.h>
|
||||||
|
#include <package/PackageInfo.h>
|
||||||
|
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPackageKit;
|
||||||
|
|
||||||
|
|
||||||
|
class Package {
|
||||||
|
public:
|
||||||
|
Package();
|
||||||
|
~Package();
|
||||||
|
|
||||||
|
status_t Init(const entry_ref& entryRef);
|
||||||
|
|
||||||
|
const node_ref& NodeRef() const
|
||||||
|
{ return fNodeRef; }
|
||||||
|
const BString& FileName() const
|
||||||
|
{ return fFileName; }
|
||||||
|
|
||||||
|
const BPackageInfo & Info() const
|
||||||
|
{ return fInfo; }
|
||||||
|
|
||||||
|
bool IsActive() const
|
||||||
|
{ return fActive; }
|
||||||
|
void SetActive(bool active)
|
||||||
|
{ fActive = active; }
|
||||||
|
|
||||||
|
Package*& FileNameHashTableNext()
|
||||||
|
{ return fFileNameHashTableNext; }
|
||||||
|
Package*& NodeRefHashTableNext()
|
||||||
|
{ return fNodeRefHashTableNext; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_ref fNodeRef;
|
||||||
|
BString fFileName;
|
||||||
|
BPackageInfo fInfo;
|
||||||
|
bool fActive;
|
||||||
|
Package* fFileNameHashTableNext;
|
||||||
|
Package* fNodeRefHashTableNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageFileNameHashDefinition {
|
||||||
|
typedef const char* KeyType;
|
||||||
|
typedef Package ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const char* key) const
|
||||||
|
{
|
||||||
|
return BString::HashValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const Package* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->FileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const char* key, const Package* value) const
|
||||||
|
{
|
||||||
|
return value->FileName() == key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Package*& GetLink(Package* value) const
|
||||||
|
{
|
||||||
|
return value->FileNameHashTableNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageNodeRefHashDefinition {
|
||||||
|
typedef node_ref KeyType;
|
||||||
|
typedef Package ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const node_ref& key) const
|
||||||
|
{
|
||||||
|
return (size_t)key.device + 17 * (size_t)key.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const Package* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->NodeRef());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const node_ref& key, const Package* value) const
|
||||||
|
{
|
||||||
|
return key == value->NodeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
Package*& GetLink(Package* value) const
|
||||||
|
{
|
||||||
|
return value->NodeRefHashTableNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef BOpenHashTable<PackageFileNameHashDefinition> PackageFileNameHashTable;
|
||||||
|
typedef BOpenHashTable<PackageNodeRefHashDefinition> PackageNodeRefHashTable;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PACKAGE_H
|
||||||
@@ -69,6 +69,7 @@ PackageDaemon::MessageReceived(BMessage* message)
|
|||||||
int32 opcode;
|
int32 opcode;
|
||||||
if (message->FindInt32("opcode", &opcode) != B_OK)
|
if (message->FindInt32("opcode", &opcode) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (opcode == B_DEVICE_MOUNTED)
|
if (opcode == B_DEVICE_MOUNTED)
|
||||||
_HandleVolumeMounted(message);
|
_HandleVolumeMounted(message);
|
||||||
else if (opcode == B_DEVICE_UNMOUNTED)
|
else if (opcode == B_DEVICE_UNMOUNTED)
|
||||||
@@ -94,27 +95,14 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
|
|||||||
if (strcmp(info.fsh_name, "packagefs") != 0)
|
if (strcmp(info.fsh_name, "packagefs") != 0)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
// open the root directory of the volume
|
|
||||||
node_ref nodeRef;
|
|
||||||
nodeRef.device = info.dev;
|
|
||||||
nodeRef.node = info.root;
|
|
||||||
BDirectory directory;
|
|
||||||
error = directory.SetTo(&nodeRef);
|
|
||||||
if (error != B_OK) {
|
|
||||||
ERROR("PackageDaemon::_RegisterVolume(): failed to open root: %s\n",
|
|
||||||
strerror(error));
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a volume
|
// create a volume
|
||||||
Volume* volume = new(std::nothrow) Volume;
|
Volume* volume = new(std::nothrow) Volume;
|
||||||
if (volume == NULL)
|
if (volume == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
ObjectDeleter<Volume> volumeDeleter(volume);
|
ObjectDeleter<Volume> volumeDeleter(volume);
|
||||||
|
|
||||||
dev_t rootDeviceID;
|
node_ref rootRef;
|
||||||
ino_t rootNodeID;
|
error = volume->Init(node_ref(info.dev, info.root), rootRef);
|
||||||
error = volume->Init(directory, rootDeviceID, rootNodeID);
|
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
@@ -127,7 +115,7 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
|
|||||||
|
|
||||||
// get the root for the volume and register it
|
// get the root for the volume and register it
|
||||||
Root* root;
|
Root* root;
|
||||||
error = _GetOrCreateRoot(rootDeviceID, rootNodeID, root);
|
error = _GetOrCreateRoot(rootRef, root);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
@@ -138,6 +126,19 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
|
|||||||
}
|
}
|
||||||
volumeDeleter.Detach();
|
volumeDeleter.Detach();
|
||||||
|
|
||||||
|
AddHandler(volume);
|
||||||
|
|
||||||
|
// node-monitor the volume's packages directory
|
||||||
|
error = watch_node(&volume->PackagesDirectoryRef(), B_WATCH_DIRECTORY,
|
||||||
|
BMessenger(volume, this));
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("PackageDaemon::_RegisterVolume(): failed to start watching the "
|
||||||
|
"packages directory of the volume at \"%s\": %s\n",
|
||||||
|
volume->Path().String(), strerror(error));
|
||||||
|
// Not good, but not fatal. Only the manual package operations in the
|
||||||
|
// packages directory won't work correctly.
|
||||||
|
}
|
||||||
|
|
||||||
INFORM("volume at \"%s\" registered\n", volume->Path().String());
|
INFORM("volume at \"%s\" registered\n", volume->Path().String());
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -147,6 +148,10 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
|
|||||||
void
|
void
|
||||||
PackageDaemon::_UnregisterVolume(Volume* volume)
|
PackageDaemon::_UnregisterVolume(Volume* volume)
|
||||||
{
|
{
|
||||||
|
stop_watching(BMessenger(volume, this));
|
||||||
|
|
||||||
|
RemoveHandler(volume);
|
||||||
|
|
||||||
Root* root = volume->GetRoot();
|
Root* root = volume->GetRoot();
|
||||||
root->UnregisterVolume(volume);
|
root->UnregisterVolume(volume);
|
||||||
|
|
||||||
@@ -158,9 +163,9 @@ PackageDaemon::_UnregisterVolume(Volume* volume)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
|
PackageDaemon::_GetOrCreateRoot(const node_ref& nodeRef, Root*& _root)
|
||||||
{
|
{
|
||||||
Root* root = _FindRoot(deviceID, nodeID);
|
Root* root = _FindRoot(nodeRef);
|
||||||
if (root != NULL) {
|
if (root != NULL) {
|
||||||
root->AcquireReference();
|
root->AcquireReference();
|
||||||
} else {
|
} else {
|
||||||
@@ -169,7 +174,7 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
|
|||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
ObjectDeleter<Root> rootDeleter(root);
|
ObjectDeleter<Root> rootDeleter(root);
|
||||||
|
|
||||||
status_t error = root->Init(deviceID, nodeID);
|
status_t error = root->Init(nodeRef);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
@@ -179,7 +184,8 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
|
|||||||
rootDeleter.Detach();
|
rootDeleter.Detach();
|
||||||
|
|
||||||
INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
|
INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
|
||||||
"registered\n", root->Path().String(), deviceID, nodeID);
|
"registered\n", root->Path().String(), nodeRef.device,
|
||||||
|
nodeRef.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
_root = root;
|
_root = root;
|
||||||
@@ -188,10 +194,10 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
|
|||||||
|
|
||||||
|
|
||||||
Root*
|
Root*
|
||||||
PackageDaemon::_FindRoot(dev_t deviceID, ino_t nodeID) const
|
PackageDaemon::_FindRoot(const node_ref& nodeRef) const
|
||||||
{
|
{
|
||||||
for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
|
for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
|
||||||
if (root->DeviceID() == deviceID && root->NodeID() == nodeID)
|
if (root->NodeRef() == nodeRef)
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
|
#include <Node.h>
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
#include <VolumeRoster.h>
|
#include <VolumeRoster.h>
|
||||||
|
|
||||||
@@ -36,9 +37,9 @@ private:
|
|||||||
status_t _RegisterVolume(dev_t device);
|
status_t _RegisterVolume(dev_t device);
|
||||||
void _UnregisterVolume(Volume* volume);
|
void _UnregisterVolume(Volume* volume);
|
||||||
|
|
||||||
status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID,
|
status_t _GetOrCreateRoot(const node_ref& nodeRef,
|
||||||
Root*& _root);
|
Root*& _root);
|
||||||
Root* _FindRoot(dev_t deviceID, ino_t nodeID) const;
|
Root* _FindRoot(const node_ref& nodeRef) const;
|
||||||
void _PutRoot(Root* root);
|
void _PutRoot(Root* root);
|
||||||
|
|
||||||
Volume* _FindVolume(dev_t deviceID) const;
|
Volume* _FindVolume(dev_t deviceID) const;
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
|
|
||||||
Root::Root()
|
Root::Root()
|
||||||
:
|
:
|
||||||
fDeviceID(-1),
|
fNodeRef(),
|
||||||
fNodeID(-1),
|
|
||||||
fPath(),
|
fPath(),
|
||||||
fSystemVolume(NULL),
|
fSystemVolume(NULL),
|
||||||
fCommonVolume(NULL),
|
fCommonVolume(NULL),
|
||||||
@@ -35,17 +34,13 @@ Root::~Root()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Root::Init(dev_t deviceID, ino_t nodeID)
|
Root::Init(const node_ref& nodeRef)
|
||||||
{
|
{
|
||||||
fDeviceID = deviceID;
|
fNodeRef = nodeRef;
|
||||||
fNodeID = nodeID;
|
|
||||||
|
|
||||||
// get the path
|
// get the path
|
||||||
node_ref nodeRef;
|
|
||||||
nodeRef.device = fDeviceID;
|
|
||||||
nodeRef.node = fNodeID;
|
|
||||||
BDirectory directory;
|
BDirectory directory;
|
||||||
status_t error = directory.SetTo(&nodeRef);
|
status_t error = directory.SetTo(&fNodeRef);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
ERROR("Root::Init(): failed to open directory: %s\n", strerror(error));
|
ERROR("Root::Init(): failed to open directory: %s\n", strerror(error));
|
||||||
return error;
|
return error;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#define ROOT_H
|
#define ROOT_H
|
||||||
|
|
||||||
|
|
||||||
#include <fs_info.h>
|
#include <Node.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
@@ -25,12 +25,12 @@ public:
|
|||||||
Root();
|
Root();
|
||||||
virtual ~Root();
|
virtual ~Root();
|
||||||
|
|
||||||
status_t Init(dev_t deviceID, ino_t nodeID);
|
status_t Init(const node_ref& nodeRef);
|
||||||
|
|
||||||
dev_t DeviceID() const { return fDeviceID; }
|
const node_ref& NodeRef() const { return fNodeRef; }
|
||||||
ino_t NodeID() const { return fNodeID; }
|
dev_t DeviceID() const { return fNodeRef.device; }
|
||||||
const BString& Path() const
|
ino_t NodeID() const { return fNodeRef.node; }
|
||||||
{ return fPath; }
|
const BString& Path() const { return fPath; }
|
||||||
|
|
||||||
status_t RegisterVolume(Volume* volume);
|
status_t RegisterVolume(Volume* volume);
|
||||||
void UnregisterVolume(Volume* volume);
|
void UnregisterVolume(Volume* volume);
|
||||||
@@ -44,8 +44,7 @@ private:
|
|||||||
Volume** _GetVolume(PackageFSMountType mountType);
|
Volume** _GetVolume(PackageFSMountType mountType);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
dev_t fDeviceID;
|
node_ref fNodeRef;
|
||||||
ino_t fNodeID;
|
|
||||||
BString fPath;
|
BString fPath;
|
||||||
Volume* fSystemVolume;
|
Volume* fSystemVolume;
|
||||||
Volume* fCommonVolume;
|
Volume* fCommonVolume;
|
||||||
|
|||||||
+368
-28
@@ -10,38 +10,67 @@
|
|||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <Directory.h>
|
#include <Directory.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
|
#include <NodeMonitor.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include "DebugSupport.h"
|
#include "DebugSupport.h"
|
||||||
|
|
||||||
|
|
||||||
Volume::Volume()
|
Volume::Volume()
|
||||||
:
|
:
|
||||||
|
BHandler(),
|
||||||
fPath(),
|
fPath(),
|
||||||
fMountType(PACKAGE_FS_MOUNT_TYPE_CUSTOM),
|
fMountType(PACKAGE_FS_MOUNT_TYPE_CUSTOM),
|
||||||
fDeviceID(-1),
|
fRootDirectoryRef(),
|
||||||
fRootDirectoryID(1),
|
fPackagesDirectoryRef(),
|
||||||
fRoot(NULL)
|
fRoot(NULL),
|
||||||
|
fPackagesByFileName(),
|
||||||
|
fPackagesByNodeRef()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Volume::~Volume()
|
Volume::~Volume()
|
||||||
{
|
{
|
||||||
|
fPackagesByFileName.Clear();
|
||||||
|
|
||||||
|
Package* package = fPackagesByNodeRef.Clear(true);
|
||||||
|
while (package != NULL) {
|
||||||
|
Package* next = package->NodeRefHashTableNext();
|
||||||
|
delete package;
|
||||||
|
package = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
|
Volume::Init(const node_ref& rootDirectoryRef, node_ref& _packageRootRef)
|
||||||
{
|
{
|
||||||
|
if (fPackagesByFileName.Init() != B_OK || fPackagesByNodeRef.Init() != B_OK)
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
|
fRootDirectoryRef = rootDirectoryRef;
|
||||||
|
|
||||||
|
// open the root directory
|
||||||
|
BDirectory directory;
|
||||||
|
status_t error = directory.SetTo(&fRootDirectoryRef);
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("Volume::Init(): failed to open root directory: %s\n",
|
||||||
|
strerror(error));
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
// get the directory path
|
// get the directory path
|
||||||
BEntry entry;
|
BEntry entry;
|
||||||
status_t error = directory.GetEntry(&entry);
|
error = directory.GetEntry(&entry);
|
||||||
|
|
||||||
BPath path;
|
BPath path;
|
||||||
if (error == B_OK)
|
if (error == B_OK)
|
||||||
@@ -57,18 +86,6 @@ Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
|
|||||||
if (fPath.IsEmpty())
|
if (fPath.IsEmpty())
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
// stat() the directory
|
|
||||||
struct stat st;
|
|
||||||
error = directory.GetStat(&st);
|
|
||||||
if (error != B_OK) {
|
|
||||||
ERROR("Volume::Init(): failed to stat root directory: %s\n",
|
|
||||||
strerror(error));
|
|
||||||
RETURN_ERROR(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
fDeviceID = st.st_dev;
|
|
||||||
fRootDirectoryID = st.st_ino;
|
|
||||||
|
|
||||||
// get a volume info from the FS
|
// get a volume info from the FS
|
||||||
int fd = directory.Dup();
|
int fd = directory.Dup();
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@@ -76,24 +93,347 @@ Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
|
|||||||
strerror(fd));
|
strerror(fd));
|
||||||
RETURN_ERROR(fd);
|
RETURN_ERROR(fd);
|
||||||
}
|
}
|
||||||
|
FileDescriptorCloser fdCloser(fd);
|
||||||
|
|
||||||
PackageFSVolumeInfo info;
|
PackageFSVolumeInfo info;
|
||||||
if (ioctl(fd, PACKAGE_FS_OPERATION_GET_VOLUME_INFO, &info, sizeof(info))
|
if (ioctl(fd, PACKAGE_FS_OPERATION_GET_VOLUME_INFO, &info, sizeof(info))
|
||||||
!= 0) {
|
!= 0) {
|
||||||
error = errno;
|
ERROR("Volume::Init(): failed to get volume info: %s\n",
|
||||||
close(fd);
|
strerror(errno));
|
||||||
if (error != B_OK) {
|
RETURN_ERROR(errno);
|
||||||
ERROR("Volume::Init(): failed to get volume info: %s\n",
|
|
||||||
strerror(error));
|
|
||||||
RETURN_ERROR(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
fMountType = info.mountType;
|
fMountType = info.mountType;
|
||||||
_rootDeviceID = info.rootDeviceID;
|
fPackagesDirectoryRef.device = info.packagesDeviceID;
|
||||||
_rootNodeID = info.rootDirectoryID;
|
fPackagesDirectoryRef.node = info.packagesDirectoryID;
|
||||||
|
|
||||||
|
// read in all packages in the directory
|
||||||
|
error = _ReadPackagesDirectory();
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
_GetActivePackages(fd);
|
||||||
|
|
||||||
|
_packageRootRef.device = info.rootDeviceID;
|
||||||
|
_packageRootRef.node = info.rootDirectoryID;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case B_NODE_MONITOR:
|
||||||
|
{
|
||||||
|
int32 opcode;
|
||||||
|
if (message->FindInt32("opcode", &opcode) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case B_ENTRY_CREATED:
|
||||||
|
_HandleEntryCreatedOrRemoved(message, true);
|
||||||
|
break;
|
||||||
|
case B_ENTRY_REMOVED:
|
||||||
|
_HandleEntryCreatedOrRemoved(message, false);
|
||||||
|
break;
|
||||||
|
case B_ENTRY_MOVED:
|
||||||
|
_HandleEntryMoved(message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Volume::OpenRootDirectory() const
|
||||||
|
{
|
||||||
|
BDirectory directory;
|
||||||
|
status_t error = directory.SetTo(&fRootDirectoryRef);
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("Volume::OpenRootDirectory(): failed to open root directory: "
|
||||||
|
"%s\n", strerror(error));
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory.Dup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_HandleEntryCreatedOrRemoved(const BMessage* message, bool created)
|
||||||
|
{
|
||||||
|
// only moves to or from our packages directory are interesting
|
||||||
|
int32 deviceID;
|
||||||
|
int64 directoryID;
|
||||||
|
const char* name;
|
||||||
|
if (message->FindInt32("device", &deviceID) != B_OK
|
||||||
|
|| message->FindInt64("directory", &directoryID) != B_OK
|
||||||
|
|| message->FindString("name", &name) != B_OK
|
||||||
|
|| node_ref(deviceID, directoryID) != fPackagesDirectoryRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (created)
|
||||||
|
_PackagesEntryCreated(name);
|
||||||
|
else
|
||||||
|
_PackagesEntryRemoved(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_HandleEntryMoved(const BMessage* message)
|
||||||
|
{
|
||||||
|
int32 deviceID;
|
||||||
|
int64 fromDirectoryID;
|
||||||
|
int64 toDirectoryID;
|
||||||
|
const char* fromName;
|
||||||
|
const char* toName;
|
||||||
|
if (message->FindInt32("device", &deviceID) != B_OK
|
||||||
|
|| message->FindInt64("from directory", &fromDirectoryID) != B_OK
|
||||||
|
|| message->FindInt64("to directory", &toDirectoryID) != B_OK
|
||||||
|
|| message->FindString("from name", &fromName) != B_OK
|
||||||
|
|| message->FindString("name", &toName) != B_OK
|
||||||
|
|| deviceID != fPackagesDirectoryRef.device
|
||||||
|
|| (fromDirectoryID != fPackagesDirectoryRef.node
|
||||||
|
&& toDirectoryID != fPackagesDirectoryRef.node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromDirectoryID == fPackagesDirectoryRef.node)
|
||||||
|
_PackagesEntryRemoved(fromName);
|
||||||
|
if (toDirectoryID == fPackagesDirectoryRef.node)
|
||||||
|
_PackagesEntryCreated(toName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_PackagesEntryCreated(const char* name)
|
||||||
|
{
|
||||||
|
INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
|
||||||
|
entry_ref entry;
|
||||||
|
entry.device = fPackagesDirectoryRef.device;
|
||||||
|
entry.directory = fPackagesDirectoryRef.node;
|
||||||
|
status_t error = entry.set_name(name);
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Package* package = new(std::nothrow) Package;
|
||||||
|
if (package == NULL) {
|
||||||
|
ERROR("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ObjectDeleter<Package> packageDeleter(package);
|
||||||
|
|
||||||
|
error = package->Init(entry);
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("failed to init package for file \"%s\"\n", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fPackagesByFileName.Insert(package);
|
||||||
|
fPackagesByNodeRef.Insert(package);
|
||||||
|
packageDeleter.Detach();
|
||||||
|
|
||||||
|
// activate package
|
||||||
|
// TODO: Don't do that here!
|
||||||
|
size_t nameLength = strlen(package->FileName());
|
||||||
|
size_t requestSize = sizeof(PackageFSActivationChangeRequest) + nameLength;
|
||||||
|
PackageFSActivationChangeRequest* request
|
||||||
|
= (PackageFSActivationChangeRequest*)malloc(requestSize);
|
||||||
|
if (request == NULL) {
|
||||||
|
ERROR("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MemoryDeleter requestDeleter(request);
|
||||||
|
|
||||||
|
request->itemCount = 1;
|
||||||
|
PackageFSActivationChangeItem& item = request->items[0];
|
||||||
|
item.type = PACKAGE_FS_ACTIVATE_PACKAGE;
|
||||||
|
|
||||||
|
item.packageDeviceID = package->NodeRef().device;
|
||||||
|
item.packageNodeID = package->NodeRef().node;
|
||||||
|
|
||||||
|
item.nameLength = nameLength;
|
||||||
|
item.parentDeviceID = fPackagesDirectoryRef.device;
|
||||||
|
item.parentDirectoryID = fPackagesDirectoryRef.node;
|
||||||
|
strcpy(item.name, package->FileName());
|
||||||
|
|
||||||
|
int fd = OpenRootDirectory();
|
||||||
|
if (fd < 0) {
|
||||||
|
ERROR("Volume::_PackagesEntryCreated(): failed to open root directory: "
|
||||||
|
"%s", strerror(fd));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileDescriptorCloser fdCloser(fd);
|
||||||
|
|
||||||
|
if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
|
||||||
|
!= 0) {
|
||||||
|
ERROR("Volume::_PackagesEntryCreated(): activate packages: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
package->SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_PackagesEntryRemoved(const char* name)
|
||||||
|
{
|
||||||
|
INFORM("Volume::_PackagesEntryRemoved(\"%s\")\n", name);
|
||||||
|
Package* package = fPackagesByFileName.Lookup(name);
|
||||||
|
if (package == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (package->IsActive()) {
|
||||||
|
// deactivate the package
|
||||||
|
// TODO: Don't do that here!
|
||||||
|
size_t nameLength = strlen(package->FileName());
|
||||||
|
size_t requestSize = sizeof(PackageFSActivationChangeRequest)
|
||||||
|
+ nameLength;
|
||||||
|
PackageFSActivationChangeRequest* request
|
||||||
|
= (PackageFSActivationChangeRequest*)malloc(requestSize);
|
||||||
|
if (request == NULL) {
|
||||||
|
ERROR("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MemoryDeleter requestDeleter(request);
|
||||||
|
|
||||||
|
request->itemCount = 1;
|
||||||
|
PackageFSActivationChangeItem& item = request->items[0];
|
||||||
|
item.type = PACKAGE_FS_DEACTIVATE_PACKAGE;
|
||||||
|
|
||||||
|
item.packageDeviceID = package->NodeRef().device;
|
||||||
|
item.packageNodeID = package->NodeRef().node;
|
||||||
|
|
||||||
|
item.nameLength = nameLength;
|
||||||
|
item.parentDeviceID = fPackagesDirectoryRef.device;
|
||||||
|
item.parentDirectoryID = fPackagesDirectoryRef.node;
|
||||||
|
strcpy(item.name, package->FileName());
|
||||||
|
|
||||||
|
int fd = OpenRootDirectory();
|
||||||
|
if (fd < 0) {
|
||||||
|
ERROR("Volume::_PackagesEntryRemoved(): failed to open root "
|
||||||
|
"directory: %s", strerror(fd));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileDescriptorCloser fdCloser(fd);
|
||||||
|
|
||||||
|
if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request,
|
||||||
|
requestSize) != 0) {
|
||||||
|
ERROR("Volume::_PackagesEntryRemoved(): activate packages: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fPackagesByFileName.Remove(package);
|
||||||
|
fPackagesByNodeRef.Remove(package);
|
||||||
|
delete package;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Volume::_ReadPackagesDirectory()
|
||||||
|
{
|
||||||
|
BDirectory directory;
|
||||||
|
status_t error = directory.SetTo(&fPackagesDirectoryRef);
|
||||||
|
if (error != B_OK) {
|
||||||
|
ERROR("Volume::_ReadPackagesDirectory(): open packages directory: %s\n",
|
||||||
|
strerror(error));
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_ref entry;
|
||||||
|
while (directory.GetNextRef(&entry) == B_OK) {
|
||||||
|
Package* package = new(std::nothrow) Package;
|
||||||
|
if (package == NULL)
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
ObjectDeleter<Package> packageDeleter(package);
|
||||||
|
|
||||||
|
status_t error = package->Init(entry);
|
||||||
|
if (error == B_OK) {
|
||||||
|
fPackagesByFileName.Insert(package);
|
||||||
|
fPackagesByNodeRef.Insert(package);
|
||||||
|
packageDeleter.Detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Volume::_GetActivePackages(int fd)
|
||||||
|
{
|
||||||
|
uint32 maxPackageCount = 16 * 1024;
|
||||||
|
PackageFSGetPackageInfosRequest* request = NULL;
|
||||||
|
MemoryDeleter requestDeleter;
|
||||||
|
size_t bufferSize;
|
||||||
|
for (;;) {
|
||||||
|
bufferSize = sizeof(PackageFSGetPackageInfosRequest)
|
||||||
|
+ (maxPackageCount - 1) * sizeof(PackageFSPackageInfo);
|
||||||
|
request = (PackageFSGetPackageInfosRequest*)malloc(bufferSize);
|
||||||
|
if (request == NULL)
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
requestDeleter.SetTo(request);
|
||||||
|
|
||||||
|
if (ioctl(fd, PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS, request,
|
||||||
|
bufferSize) != 0) {
|
||||||
|
ERROR("Volume::_GetActivePackages(): failed to get active package "
|
||||||
|
"info from package FS: %s\n", strerror(errno));
|
||||||
|
RETURN_ERROR(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->packageCount <= maxPackageCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
maxPackageCount = request->packageCount;
|
||||||
|
requestDeleter.Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark the returned packages active
|
||||||
|
for (uint32 i = 0; i < request->packageCount; i++) {
|
||||||
|
Package* package = fPackagesByNodeRef.Lookup(
|
||||||
|
node_ref(request->infos[i].packageDeviceID,
|
||||||
|
request->infos[i].packageNodeID));
|
||||||
|
if (package == NULL) {
|
||||||
|
WARN("active package (dev: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
|
||||||
|
"not found in package directory\n",
|
||||||
|
request->infos[i].packageDeviceID,
|
||||||
|
request->infos[i].packageNodeID);
|
||||||
|
// TODO: Deactivate the package right away?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
package->SetActive(true);
|
||||||
|
INFORM("active package: \"%s\"\n", package->FileName().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PackageNodeRefHashTable::Iterator it = fPackagesByNodeRef.GetIterator();
|
||||||
|
it.HasNext();) {
|
||||||
|
Package* package = it.Next();
|
||||||
|
if (!package->IsActive())
|
||||||
|
INFORM("inactive package: \"%s\"\n", package->FileName().String());
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageNodeRefHashTable fPackagesByNodeRef;
|
||||||
|
// INFORM("%" B_PRIu32 " active packages:\n", request->packageCount);
|
||||||
|
// for (uint32 i = 0; i < request->packageCount; i++) {
|
||||||
|
// INFORM(" dev: %" B_PRIdDEV ", node: %" B_PRIdINO "\n",
|
||||||
|
// request->infos[i].packageDeviceID, request->infos[i].packageNodeID);
|
||||||
|
// }
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,47 +9,75 @@
|
|||||||
#define VOLUME_H
|
#define VOLUME_H
|
||||||
|
|
||||||
|
|
||||||
#include <fs_info.h>
|
#include <Handler.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include <packagefs.h>
|
#include <packagefs.h>
|
||||||
|
|
||||||
|
#include "Package.h"
|
||||||
|
|
||||||
|
|
||||||
class BDirectory;
|
class BDirectory;
|
||||||
|
|
||||||
class Root;
|
class Root;
|
||||||
|
|
||||||
|
|
||||||
class Volume {
|
class Volume : public BHandler {
|
||||||
public:
|
public:
|
||||||
Volume();
|
Volume();
|
||||||
~Volume();
|
virtual ~Volume();
|
||||||
|
|
||||||
status_t Init(BDirectory& directory,
|
status_t Init(const node_ref& rootDirectoryRef,
|
||||||
dev_t& _rootDeviceID, ino_t& _rootNodeID);
|
node_ref& _packageRootRef);
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
const BString& Path() const
|
const BString& Path() const
|
||||||
{ return fPath; }
|
{ return fPath; }
|
||||||
PackageFSMountType MountType() const
|
PackageFSMountType MountType() const
|
||||||
{ return fMountType; }
|
{ return fMountType; }
|
||||||
|
|
||||||
|
const node_ref& RootDirectoryRef() const
|
||||||
|
{ return fRootDirectoryRef; }
|
||||||
dev_t DeviceID() const
|
dev_t DeviceID() const
|
||||||
{ return fDeviceID; }
|
{ return fRootDirectoryRef.device; }
|
||||||
ino_t RootDirectoryID() const
|
ino_t RootDirectoryID() const
|
||||||
{ return fRootDirectoryID; }
|
{ return fRootDirectoryRef.node; }
|
||||||
|
|
||||||
|
const node_ref& PackagesDirectoryRef() const
|
||||||
|
{ return fPackagesDirectoryRef; }
|
||||||
|
dev_t PackagesDeviceID() const
|
||||||
|
{ return fPackagesDirectoryRef.device; }
|
||||||
|
ino_t PackagesDirectoryID() const
|
||||||
|
{ return fPackagesDirectoryRef.node; }
|
||||||
|
|
||||||
Root* GetRoot() const
|
Root* GetRoot() const
|
||||||
{ return fRoot; }
|
{ return fRoot; }
|
||||||
void SetRoot(Root* root)
|
void SetRoot(Root* root)
|
||||||
{ fRoot = root; }
|
{ fRoot = root; }
|
||||||
|
|
||||||
|
int OpenRootDirectory() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _HandleEntryCreatedOrRemoved(
|
||||||
|
const BMessage* message, bool created);
|
||||||
|
void _HandleEntryMoved(const BMessage* message);
|
||||||
|
|
||||||
|
void _PackagesEntryCreated(const char* name);
|
||||||
|
void _PackagesEntryRemoved(const char* name);
|
||||||
|
|
||||||
|
status_t _ReadPackagesDirectory();
|
||||||
|
status_t _GetActivePackages(int fd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BString fPath;
|
BString fPath;
|
||||||
PackageFSMountType fMountType;
|
PackageFSMountType fMountType;
|
||||||
dev_t fDeviceID;
|
node_ref fRootDirectoryRef;
|
||||||
ino_t fRootDirectoryID;
|
node_ref fPackagesDirectoryRef;
|
||||||
Root* fRoot;
|
Root* fRoot;
|
||||||
|
PackageFileNameHashTable fPackagesByFileName;
|
||||||
|
PackageNodeRefHashTable fPackagesByNodeRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // VOLUME_H
|
#endif // VOLUME_H
|
||||||
|
|||||||
Reference in New Issue
Block a user