semi-tested semi-implemented with horrific big methods
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6454 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,548 @@
|
||||
#include "AddOnMonitorHandler.h"
|
||||
#include <Directory.h>
|
||||
|
||||
#define ADD_ON_STABLE_SECONDS 15
|
||||
|
||||
/*
|
||||
* public functions
|
||||
*/
|
||||
|
||||
AddOnMonitorHandler::AddOnMonitorHandler(const char * name)
|
||||
: NodeMonitorHandler(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AddOnMonitorHandler::~AddOnMonitorHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::MessageReceived(BMessage * msg)
|
||||
{
|
||||
if (msg->what == B_PULSE) {
|
||||
HandlePulse();
|
||||
}
|
||||
inherited::MessageReceived(msg);
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ status_t
|
||||
AddOnMonitorHandler::AddDirectory(const node_ref * nref)
|
||||
{
|
||||
BDirectory directory(nref);
|
||||
status_t status = directory.InitCheck();
|
||||
if (status != B_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
add_on_directory_info dir_info;
|
||||
dir_info.nref = *nref;
|
||||
directories.push_back(dir_info);
|
||||
|
||||
status = watch_node(nref, B_WATCH_DIRECTORY, this);
|
||||
if (status != B_OK) {
|
||||
directories.pop_back();
|
||||
return status;
|
||||
}
|
||||
|
||||
BEntry entry;
|
||||
while (directory.GetNextEntry(&entry, true) == B_OK) {
|
||||
add_on_entry_info entry_info;
|
||||
if (entry.GetName(entry_info.name) != B_OK) {
|
||||
continue; // discard and proceed
|
||||
}
|
||||
if (entry.GetNodeRef(&entry_info.nref) != B_OK) {
|
||||
continue; // discard and proceed
|
||||
}
|
||||
entry_info.dir_nref = *nref;
|
||||
pending_entries.push_back(entry_info);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AddOnMonitorHandler hooks
|
||||
*/
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::AddOnCreated(const add_on_entry_info * entry_info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::AddOnEnabled(const add_on_entry_info * entry_info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::AddOnDisabled(const add_on_entry_info * entry_info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::AddOnRemoved(const add_on_entry_info * entry_info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NodeMonitorHandler hooks
|
||||
*/
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::EntryCreated(const char *name, ino_t directory,
|
||||
dev_t device, ino_t node)
|
||||
{
|
||||
add_on_entry_info entry_info;
|
||||
strncpy(entry_info.name, name, sizeof(entry_info.name));
|
||||
make_node_ref(device, node, &entry_info.nref);
|
||||
make_node_ref(device, directory, &entry_info.dir_nref);
|
||||
pending_entries.push_back(entry_info);
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::EntryRemoved(ino_t directory, dev_t device, ino_t node)
|
||||
{
|
||||
node_ref entry_nref;
|
||||
make_node_ref(device, node, &entry_nref);
|
||||
|
||||
// Search pending entries first, which can simply be discarded
|
||||
// We might have this entry in the pending list multiple times,
|
||||
// so we search entire list through, even after finding one.
|
||||
std::list<add_on_entry_info>::iterator eiter = pending_entries.begin();
|
||||
while (eiter != pending_entries.end()) {
|
||||
if (eiter->nref == entry_nref) {
|
||||
eiter = pending_entries.erase(eiter);
|
||||
} else {
|
||||
eiter++;
|
||||
}
|
||||
}
|
||||
|
||||
add_on_entry_info info;
|
||||
node_ref dir_nref;
|
||||
make_node_ref(device, directory, &dir_nref);
|
||||
|
||||
// find the entry's info, and the entry's directory info
|
||||
std::list<add_on_directory_info>::iterator diter = directories.begin();
|
||||
for( ; diter != directories.end() ; diter++) {
|
||||
if (diter->nref == dir_nref) {
|
||||
std::list<add_on_entry_info>::iterator eiter = diter->entries.begin();
|
||||
for( ; eiter != diter->entries.end() ; eiter++) {
|
||||
info = *eiter;
|
||||
if (eiter->nref == entry_nref) {
|
||||
info = *eiter;
|
||||
diter->entries.erase(eiter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if it was not found, we're done
|
||||
if (diter == directories.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start at the top again, and search until the directory we found
|
||||
// the old add_on in. If we find a add_on with the same name then
|
||||
// the old add_on was not enabled. So we deallocate the old
|
||||
// add_on and return.
|
||||
std::list<add_on_directory_info>::iterator diter2 = directories.begin();
|
||||
for( ; diter2 != diter ; diter2++) {
|
||||
std::list<add_on_entry_info>::iterator eiter = diter2->entries.begin();
|
||||
for( ; eiter != diter2->entries.end() ; eiter++) {
|
||||
if (strcmp(eiter->name, info.name) == 0) {
|
||||
AddOnRemoved(&info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The active plugin was removed. We need to disable and
|
||||
// then subsequently deallocate it.
|
||||
AddOnDisabled(&info);
|
||||
AddOnRemoved(&info);
|
||||
|
||||
// Continue searching for a add_on below us. If we find a add_on
|
||||
// with the same name, we must enable it.
|
||||
for (diter++ ; diter != directories.end() ; diter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter = diter->entries.begin();
|
||||
for( ; eiter != diter->entries.end() ; eiter++) {
|
||||
if (strcmp(eiter->name, info.name) == 0) {
|
||||
AddOnEnabled(&*eiter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void
|
||||
AddOnMonitorHandler::EntryMoved(const char *name, ino_t from_directory,
|
||||
ino_t to_directory, dev_t device, ino_t node)
|
||||
{
|
||||
node_ref from_nref;
|
||||
make_node_ref(device, from_directory, &from_nref);
|
||||
std::list<add_on_directory_info>::iterator from_iter = directories.begin();
|
||||
for ( ; from_iter != directories.end() ; from_iter++) {
|
||||
if (from_iter->nref == from_nref) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node_ref to_nref;
|
||||
make_node_ref(device, to_directory, &to_nref);
|
||||
std::list<add_on_directory_info>::iterator to_iter = directories.begin();
|
||||
for ( ; to_iter != directories.end() ; to_iter++) {
|
||||
if (to_iter->nref == to_nref) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((from_iter == directories.end()) && (to_iter == directories.end())) {
|
||||
// huh? whatever...
|
||||
return;
|
||||
}
|
||||
|
||||
add_on_entry_info info;
|
||||
node_ref entry_nref;
|
||||
make_node_ref(device, node, &entry_nref);
|
||||
|
||||
if (to_iter == directories.end()) {
|
||||
// moved out of our view
|
||||
std::list<add_on_entry_info>::iterator eiter = from_iter->entries.begin();
|
||||
for( ; eiter != from_iter->entries.end() ; eiter++) {
|
||||
if (entry_nref == eiter->nref) {
|
||||
// save the info and remove the entry
|
||||
info = *eiter;
|
||||
from_iter->entries.erase(eiter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eiter == from_iter->entries.end()) {
|
||||
// we don't know anything about this entry yet.. ignore it
|
||||
return;
|
||||
}
|
||||
|
||||
// if the name is the same, save the information about this
|
||||
// add_on into former_entries for later use
|
||||
if (strcmp(info.name, name) == 0) {
|
||||
former_entries.push_back(info);
|
||||
}
|
||||
|
||||
// Start at the top again, and search until the from directory.
|
||||
// If we find a add_on with the same name then the moved add_on
|
||||
// was not enabled. So we are done.
|
||||
std::list<add_on_directory_info>::iterator diter = directories.begin();
|
||||
for( ; diter != from_iter ; diter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = diter->entries.begin();
|
||||
for( ; eiter2 != diter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally disable the add_on
|
||||
AddOnDisabled(&info);
|
||||
|
||||
// Continue searching for a add_on below us. If we find a add_on
|
||||
// with the same name, we must enable it.
|
||||
for (from_iter++ ; from_iter != directories.end() ; from_iter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = from_iter->entries.begin();
|
||||
for( ; eiter2 != from_iter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
AddOnEnabled(&*eiter2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, if the new name is different, destroy the addon
|
||||
if (strcmp(info.name, name) != 0) {
|
||||
AddOnRemoved(&info);
|
||||
}
|
||||
|
||||
// done
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_iter == directories.end()) {
|
||||
// moved into our view
|
||||
std::list<add_on_entry_info>::iterator eiter = former_entries.begin();
|
||||
for( ; eiter != former_entries.end() ; eiter++) {
|
||||
if (entry_nref == eiter->nref) {
|
||||
// save the info and remove the entry
|
||||
info = *eiter;
|
||||
former_entries.erase(eiter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eiter != former_entries.end()) {
|
||||
if (strcmp(info.name, name) != 0) {
|
||||
// name changed on the way in, remove the old one
|
||||
AddOnRemoved(&info);
|
||||
}
|
||||
}
|
||||
|
||||
// update the info
|
||||
strncpy(info.name, name, sizeof(info.name));
|
||||
info.nref = entry_nref;
|
||||
info.dir_nref = to_nref;
|
||||
|
||||
if (eiter == former_entries.end()) {
|
||||
// this add_on was not seen before
|
||||
AddOnCreated(&info);
|
||||
}
|
||||
|
||||
// Start at the top again, and search until the to directory.
|
||||
// If we find a add_on with the same name then the moved add_on
|
||||
// is not to be enabled. So we are done.
|
||||
std::list<add_on_directory_info>::iterator diter = directories.begin();
|
||||
for( ; diter != to_iter ; diter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = diter->entries.begin();
|
||||
for( ; eiter2 != diter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The new add_on should be enabled, but first we check to see
|
||||
// if there is an add_on below us. If we find one, we disable it.
|
||||
bool shadowing = false;
|
||||
for (diter++ ; diter != directories.end() ; diter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = diter->entries.begin();
|
||||
for( ; eiter2 != diter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
AddOnDisabled(&*eiter2);
|
||||
shadowing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shadowing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// enable the new add_on
|
||||
AddOnEnabled(&info);
|
||||
|
||||
// put the new entry into the target directory
|
||||
to_iter->entries.push_back(info);
|
||||
|
||||
// done
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<add_on_entry_info>::iterator eiter = from_iter->entries.begin();
|
||||
for( ; eiter != from_iter->entries.end() ; eiter++) {
|
||||
if (entry_nref == eiter->nref) {
|
||||
// save the old info and remove the entry
|
||||
info = *eiter;
|
||||
from_iter->entries.erase(eiter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(info.name, name) == 0) {
|
||||
// same name moved in heirarchy
|
||||
debugger("add_on moved inside the heirarchy");
|
||||
} else {
|
||||
// check to see if it was formerly enabled
|
||||
bool was_enabled = true;
|
||||
std::list<add_on_directory_info>::iterator old_iter = directories.begin();
|
||||
for( ; old_iter != from_iter ; old_iter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = old_iter->entries.begin();
|
||||
for( ; eiter2 != old_iter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
was_enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!was_enabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if it was enabled, disable it and enable the one under us, if it exists
|
||||
if (was_enabled) {
|
||||
AddOnDisabled(&info);
|
||||
bool done = false;
|
||||
for( ; old_iter != directories.end() ; old_iter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = old_iter->entries.begin();
|
||||
for( ; eiter2 != old_iter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
AddOnEnabled(&*eiter2);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kaboom!
|
||||
AddOnRemoved(&info);
|
||||
|
||||
// set up new addon info
|
||||
strncpy(info.name, name, sizeof(info.name));
|
||||
info.dir_nref = to_nref;
|
||||
|
||||
// presto!
|
||||
AddOnCreated(&info);
|
||||
|
||||
// check to see if we are newly enabled
|
||||
bool is_enabled = true;
|
||||
std::list<add_on_directory_info>::iterator new_iter = directories.begin();
|
||||
for( ; new_iter != to_iter ; new_iter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = new_iter->entries.begin();
|
||||
for( ; eiter2 != new_iter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
is_enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_enabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if it is newly enabled, check under us for an enabled one, and disable that first
|
||||
if (is_enabled) {
|
||||
bool done = false;
|
||||
for( ; new_iter != directories.end() ; new_iter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter2 = new_iter->entries.begin();
|
||||
for( ; eiter2 != new_iter->entries.end() ; eiter2++) {
|
||||
if (strcmp(eiter2->name, info.name) == 0) {
|
||||
AddOnDisabled(&*eiter2);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
AddOnEnabled(&info);
|
||||
}
|
||||
}
|
||||
|
||||
// put the new entry into the target directory
|
||||
to_iter->entries.push_back(info);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* process pending entries
|
||||
*/
|
||||
|
||||
void
|
||||
AddOnMonitorHandler::HandlePulse()
|
||||
{
|
||||
BDirectory directory;
|
||||
std::list<add_on_entry_info>::iterator iter = pending_entries.begin();
|
||||
while (iter != pending_entries.end()) {
|
||||
add_on_entry_info info = *iter;
|
||||
|
||||
node_ref dir_nref;
|
||||
if ((directory.GetNodeRef(&dir_nref) != B_OK) ||
|
||||
(dir_nref != info.dir_nref)) {
|
||||
if (directory.SetTo(&info.dir_nref) != B_OK) {
|
||||
// invalid directory, discard this pending entry
|
||||
iter = pending_entries.erase(iter);
|
||||
continue;
|
||||
}
|
||||
dir_nref = info.dir_nref;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (directory.GetStatFor(info.name, &st) != B_OK) {
|
||||
// invalid file name, discard this pending entry
|
||||
iter = pending_entries.erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
// stat units are seconds, real_time_clock units are seconds
|
||||
if (real_time_clock() - st.st_mtime < ADD_ON_STABLE_SECONDS) {
|
||||
// entry not stable, skip the entry for this pulse
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we are going to deal with the stable entry, so remove it
|
||||
iter = pending_entries.erase(iter);
|
||||
|
||||
// put the new entry into the directory info
|
||||
std::list<add_on_directory_info>::iterator diter = directories.begin();
|
||||
for( ; diter != directories.end() ; diter++) {
|
||||
if (diter->nref == dir_nref) {
|
||||
diter->entries.push_back(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// report it
|
||||
AddOnCreated(&info);
|
||||
|
||||
// Start at the top again, and search until the directory we put
|
||||
// the new add_on in. If we find a add_on with the same name then
|
||||
// the new add_on should not be enabled.
|
||||
bool enabled = true;
|
||||
std::list<add_on_directory_info>::iterator diter2 = directories.begin();
|
||||
for( ; diter2 != diter ; diter2++) {
|
||||
std::list<add_on_entry_info>::iterator eiter = diter2->entries.begin();
|
||||
for( ; eiter != diter2->entries.end() ; eiter++) {
|
||||
if (strcmp(eiter->name, info.name) == 0) {
|
||||
enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!enabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!enabled) {
|
||||
// if we are not enabled, go on to the next pending entry
|
||||
continue;
|
||||
}
|
||||
|
||||
// The new add_on should be enabled, but first we check to see
|
||||
// if there is an add_on below us. If we find one, we disable it.
|
||||
bool shadowing = false;
|
||||
for (diter++ ; diter != directories.end() ; diter++) {
|
||||
std::list<add_on_entry_info>::iterator eiter = diter->entries.begin();
|
||||
for( ; eiter != diter->entries.end() ; eiter++) {
|
||||
if (strcmp(eiter->name, info.name) == 0) {
|
||||
AddOnDisabled(&*eiter);
|
||||
shadowing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shadowing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// finally, enable the new entry
|
||||
AddOnEnabled(&info);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user