Files
haiku-beta6/src/kits/storage/AddOnMonitorHandler.cpp
T

563 lines
14 KiB
C++
Raw Normal View History

2008-10-18 13:53:03 +00:00
/*
* Copyright 2004-2008, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Andrew Bachmann
*/
#include "AddOnMonitorHandler.h"
2008-10-18 13:53:03 +00:00
#include <string.h>
#include <Directory.h>
2008-10-18 13:53:03 +00:00
#ifndef ADD_ON_STABLE_SECONDS
2008-10-18 13:53:03 +00:00
# define ADD_ON_STABLE_SECONDS 5
#endif
2008-10-18 13:53:03 +00:00
AddOnMonitorHandler::AddOnMonitorHandler(const char* name)
: NodeMonitorHandler(name != NULL ? name : "AddOnMonitorHandler")
{
}
AddOnMonitorHandler::~AddOnMonitorHandler()
{
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::MessageReceived(BMessage* msg)
{
2008-10-18 13:53:03 +00:00
if (msg->what == B_PULSE)
_HandlePulse();
inherited::MessageReceived(msg);
}
2008-10-18 13:53:03 +00:00
status_t
AddOnMonitorHandler::AddDirectory(const node_ref* nref)
{
// ignore directories added twice
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator iterator = fDirectories.begin();
for (; iterator != fDirectories.end() ; iterator++) {
if (iterator->nref == *nref)
return B_OK;
}
BDirectory directory(nref);
status_t status = directory.InitCheck();
2008-10-18 13:53:03 +00:00
if (status != B_OK)
return status;
2008-10-18 13:53:03 +00:00
add_on_directory_info dirInfo;
dirInfo.nref = *nref;
fDirectories.push_back(dirInfo);
status = watch_node(nref, B_WATCH_DIRECTORY, this);
if (status != B_OK) {
2008-10-18 13:53:03 +00:00
fDirectories.pop_back();
return status;
}
BEntry entry;
while (directory.GetNextEntry(&entry, true) == B_OK) {
2008-10-18 13:53:03 +00:00
add_on_entry_info entryInfo;
if (entry.GetName(entryInfo.name) != B_OK
|| entry.GetNodeRef(&entryInfo.nref) != B_OK) {
continue;
}
2008-10-18 13:53:03 +00:00
entryInfo.dir_nref = *nref;
fPendingEntries.push_back(entryInfo);
}
return B_OK;
}
2008-10-18 13:53:03 +00:00
// #pragma mark - AddOnMonitorHandler hooks
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::AddOnCreated(const add_on_entry_info* entryInfo)
{
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::AddOnEnabled(const add_on_entry_info* entryInfo)
{
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::AddOnDisabled(const add_on_entry_info* entryInfo)
{
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::AddOnRemoved(const add_on_entry_info* entryInfo)
{
}
2008-10-18 13:53:03 +00:00
// #pragma mark - NodeMonitorHandler hooks
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::EntryCreated(const char* name, ino_t directory,
dev_t device, ino_t node)
{
2008-10-18 13:53:03 +00:00
add_on_entry_info entryInfo;
strncpy(entryInfo.name, name, sizeof(entryInfo.name));
make_node_ref(device, node, &entryInfo.nref);
make_node_ref(device, directory, &entryInfo.dir_nref);
fPendingEntries.push_back(entryInfo);
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::EntryRemoved(ino_t directory, dev_t device, ino_t node)
{
2008-10-18 13:53:03 +00:00
node_ref entryNodeRef;
make_node_ref(device, node, &entryNodeRef);
// 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.
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter = fPendingEntries.begin();
while (eiter != fPendingEntries.end()) {
if (eiter->nref == entryNodeRef) {
eiter = fPendingEntries.erase(eiter);
} else {
eiter++;
}
}
add_on_entry_info info;
2008-10-18 13:53:03 +00:00
node_ref dirNodeRef;
make_node_ref(device, directory, &dirNodeRef);
// find the entry's info, and the entry's directory info
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator diter = fDirectories.begin();
for (; diter != fDirectories.end() ; diter++) {
if (diter->nref == dirNodeRef) {
std::list<add_on_entry_info>::iterator eiter
= diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != diter->entries.end() ; eiter++) {
info = *eiter;
2008-10-18 13:53:03 +00:00
if (eiter->nref == entryNodeRef) {
info = *eiter;
diter->entries.erase(eiter);
break;
}
}
break;
}
}
// if it was not found, we're done
2008-10-18 13:53:03 +00:00
if (diter == fDirectories.end()) {
return;
}
// Start at the top again, and search until the directory we found
2008-10-18 13:53:03 +00:00
// 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 = fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; diter2 != diter ; diter2++) {
std::list<add_on_entry_info>::iterator eiter = diter2->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != diter2->entries.end() ; eiter++) {
if (strcmp(eiter->name, info.name) == 0) {
AddOnRemoved(&info);
return;
}
}
}
2008-10-18 13:53:03 +00:00
// The active add-on was removed. We need to disable and
// then subsequently deallocate it.
AddOnDisabled(&info);
AddOnRemoved(&info);
2008-10-18 13:53:03 +00:00
// Continue searching for a add-on below us. If we find a add-on
// with the same name, we must enable it.
2008-10-18 13:53:03 +00:00
for (diter++ ; diter != fDirectories.end() ; diter++) {
std::list<add_on_entry_info>::iterator eiter = diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != diter->entries.end() ; eiter++) {
if (strcmp(eiter->name, info.name) == 0) {
AddOnEnabled(&*eiter);
return;
}
}
}
}
2008-10-18 13:53:03 +00:00
void
AddOnMonitorHandler::EntryMoved(const char* name, ino_t fromDirectory,
ino_t toDirectory, dev_t device, ino_t node)
{
2008-10-18 13:53:03 +00:00
// Search the "from" directory in the known entries
node_ref fromNodeRef;
make_node_ref(device, fromDirectory, &fromNodeRef);
std::list<add_on_directory_info>::iterator from_iter = fDirectories.begin();
for (; from_iter != fDirectories.end(); from_iter++) {
if (from_iter->nref == fromNodeRef)
break;
}
2008-10-18 13:53:03 +00:00
// Search the "to" directory in the known entries
node_ref toNodeRef;
make_node_ref(device, toDirectory, &toNodeRef);
std::list<add_on_directory_info>::iterator to_iter = fDirectories.begin();
for ( ; to_iter != fDirectories.end() ; to_iter++) {
if (to_iter->nref == toNodeRef) {
break;
}
}
2008-10-18 13:53:03 +00:00
if (from_iter == fDirectories.end() && to_iter == fDirectories.end()) {
// huh? whatever...
return;
}
add_on_entry_info info;
2008-10-18 13:53:03 +00:00
node_ref entryNodeRef;
make_node_ref(device, node, &entryNodeRef);
2008-10-18 13:53:03 +00:00
if (to_iter == fDirectories.end()) {
// moved out of our view
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter
= from_iter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != from_iter->entries.end() ; eiter++) {
2008-10-18 13:53:03 +00:00
if (entryNodeRef == 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
2008-10-18 13:53:03 +00:00
// add-on into fFormerEntries for later use
if (strcmp(info.name, name) == 0)
fFormerEntries.push_back(info);
// Start at the top again, and search until the from directory.
2008-10-18 13:53:03 +00:00
// If we find a add-on with the same name then the moved add-on
// was not enabled. So we are done.
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator diter = fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; diter != from_iter ; diter++) {
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter2
= diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != diter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
return;
}
}
}
2008-10-18 13:53:03 +00:00
// finally disable the add-on
AddOnDisabled(&info);
2008-10-18 13:53:03 +00:00
// Continue searching for a add-on below us. If we find a add-on
// with the same name, we must enable it.
2008-10-18 13:53:03 +00:00
for (from_iter++ ; from_iter != fDirectories.end() ; from_iter++) {
std::list<add_on_entry_info>::iterator eiter2
= from_iter->entries.begin();
2008-04-26 12:16:53 +00:00
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;
}
2008-10-18 13:53:03 +00:00
if (from_iter == fDirectories.end()) {
// moved into our view
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter = fFormerEntries.begin();
for (; eiter != fFormerEntries.end() ; eiter++) {
if (entryNodeRef == eiter->nref) {
// save the info and remove the entry
info = *eiter;
2008-10-18 13:53:03 +00:00
fFormerEntries.erase(eiter);
break;
}
}
2008-10-18 13:53:03 +00:00
if (eiter != fFormerEntries.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));
2008-10-18 13:53:03 +00:00
info.nref = entryNodeRef;
info.dir_nref = toNodeRef;
2008-10-18 13:53:03 +00:00
if (eiter == fFormerEntries.end()) {
// this add-on was not seen before
AddOnCreated(&info);
}
// Start at the top again, and search until the to directory.
2008-10-18 13:53:03 +00:00
// If we find an 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 = fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; diter != to_iter ; diter++) {
std::list<add_on_entry_info>::iterator eiter2 = diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != diter->entries.end() ; eiter2++) {
2008-10-18 13:53:03 +00:00
if (strcmp(eiter2->name, info.name) == 0)
return;
}
}
2008-10-18 13:53:03 +00:00
// 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;
2008-10-18 13:53:03 +00:00
for (diter++ ; diter != fDirectories.end() ; diter++) {
std::list<add_on_entry_info>::iterator eiter2 = diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != diter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
AddOnDisabled(&*eiter2);
shadowing = true;
break;
}
}
2008-10-18 13:53:03 +00:00
if (shadowing)
break;
}
2008-10-18 13:53:03 +00:00
// enable the new add-on
AddOnEnabled(&info);
2008-10-18 13:53:03 +00:00
// 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();
2008-04-26 12:16:53 +00:00
for (; eiter != from_iter->entries.end() ; eiter++) {
2008-10-18 13:53:03 +00:00
if (entryNodeRef == 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
2008-10-18 13:53:03 +00:00
debugger("add-on moved inside the heirarchy");
} else {
// check to see if it was formerly enabled
bool was_enabled = true;
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator old_iter
= fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; old_iter != from_iter ; old_iter++) {
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter2
= old_iter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != old_iter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
was_enabled = false;
break;
}
}
if (!was_enabled) {
break;
}
}
2008-10-18 13:53:03 +00:00
// if it was enabled, disable it and enable the one under us, if it
// exists
if (was_enabled) {
AddOnDisabled(&info);
bool done = false;
2008-10-18 13:53:03 +00:00
for (; old_iter != fDirectories.end() ; old_iter++) {
std::list<add_on_entry_info>::iterator eiter2
= old_iter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != old_iter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
AddOnEnabled(&*eiter2);
done = true;
break;
}
}
2008-10-18 13:53:03 +00:00
if (done)
break;
}
}
// kaboom!
AddOnRemoved(&info);
// set up new addon info
strncpy(info.name, name, sizeof(info.name));
2008-10-18 13:53:03 +00:00
info.dir_nref = toNodeRef;
// presto!
AddOnCreated(&info);
2008-10-18 13:53:03 +00:00
// check to see if we are newly enabled
2008-10-18 13:53:03 +00:00
bool isEnabled = true;
std::list<add_on_directory_info>::iterator new_iter
= fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; new_iter != to_iter ; new_iter++) {
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter2
= new_iter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != new_iter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
2008-10-18 13:53:03 +00:00
isEnabled = false;
break;
}
}
2008-10-18 13:53:03 +00:00
if (!isEnabled)
break;
}
2008-10-18 13:53:03 +00:00
// if it is newly enabled, check under us for an enabled one, and
// disable that first
if (isEnabled) {
bool done = false;
2008-10-18 13:53:03 +00:00
for (; new_iter != fDirectories.end() ; new_iter++) {
std::list<add_on_entry_info>::iterator eiter2
= new_iter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter2 != new_iter->entries.end() ; eiter2++) {
if (strcmp(eiter2->name, info.name) == 0) {
AddOnDisabled(&*eiter2);
done = true;
break;
}
}
2008-10-18 13:53:03 +00:00
if (done)
break;
}
AddOnEnabled(&info);
}
}
// put the new entry into the target directory
to_iter->entries.push_back(info);
}
2008-10-18 13:53:03 +00:00
//! Process pending entries.
void
2008-10-18 13:53:03 +00:00
AddOnMonitorHandler::_HandlePulse()
{
BDirectory directory;
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator iter = fPendingEntries.begin();
while (iter != fPendingEntries.end()) {
add_on_entry_info info = *iter;
2008-10-18 13:53:03 +00:00
node_ref dirNodeRef;
if ((directory.GetNodeRef(&dirNodeRef) != B_OK) ||
(dirNodeRef != info.dir_nref)) {
if (directory.SetTo(&info.dir_nref) != B_OK) {
// invalid directory, discard this pending entry
2008-10-18 13:53:03 +00:00
iter = fPendingEntries.erase(iter);
continue;
}
2008-10-18 13:53:03 +00:00
dirNodeRef = info.dir_nref;
}
struct stat st;
if (directory.GetStatFor(info.name, &st) != B_OK) {
// invalid file name, discard this pending entry
2008-10-18 13:53:03 +00:00
iter = fPendingEntries.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
2008-10-18 13:53:03 +00:00
iter = fPendingEntries.erase(iter);
// put the new entry into the directory info
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator diter = fDirectories.begin();
for (; diter != fDirectories.end() ; diter++) {
if (diter->nref == dirNodeRef) {
diter->entries.push_back(info);
break;
}
}
// report it
AddOnCreated(&info);
// Start at the top again, and search until the directory we put
2008-10-18 13:53:03 +00:00
// 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;
2008-10-18 13:53:03 +00:00
std::list<add_on_directory_info>::iterator diter2
= fDirectories.begin();
2008-04-26 12:16:53 +00:00
for (; diter2 != diter ; diter2++) {
2008-10-18 13:53:03 +00:00
std::list<add_on_entry_info>::iterator eiter
= diter2->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != diter2->entries.end() ; eiter++) {
if (strcmp(eiter->name, info.name) == 0) {
enabled = false;
break;
}
}
2008-10-18 13:53:03 +00:00
if (!enabled)
break;
}
if (!enabled) {
// if we are not enabled, go on to the next pending entry
continue;
}
2008-10-18 13:53:03 +00:00
// 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;
2008-10-18 13:53:03 +00:00
for (diter++ ; diter != fDirectories.end() ; diter++) {
std::list<add_on_entry_info>::iterator eiter = diter->entries.begin();
2008-04-26 12:16:53 +00:00
for (; eiter != diter->entries.end() ; eiter++) {
if (strcmp(eiter->name, info.name) == 0) {
AddOnDisabled(&*eiter);
shadowing = true;
break;
}
}
2008-10-18 13:53:03 +00:00
if (shadowing)
break;
}
// finally, enable the new entry
AddOnEnabled(&info);
}
}