[haiku-commits] r38280 - in haiku/trunk: headers/private/storage src/kits/storage

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 19 Aug 2010 21:52:19 +0200 (CEST)

Author: stippi
Date: 2010-08-19 21:52:19 +0200 (Thu, 19 Aug 2010)
New Revision: 38280
Changeset: http://dev.haiku-os.org/changeset/38280

Modified:
   haiku/trunk/headers/private/storage/AddOnMonitorHandler.h
   haiku/trunk/src/kits/storage/AddOnMonitorHandler.cpp
Log:
 * Refactored a lot of repetitive code and made
   everything more readible.
 * Once I understood better how everthing is supposed
   to work, I've fixed some bugs.
 * The most important problem was that AddDirectory()
   placed the wrong entry (resolved symlinks) into the
   entry list it keeps for each directory. This resulted
   in the mechanisms not working at all when an add-on
   was a symlink.
 * There was a hidden TODO, which would mean that moving
   an add-on from one watched directory into another,
   like from home/config/add-ons/... into common/add-ons/...
   would drop the client application (media_server,
   input_server, ...) into the debugger.
 * The fFormerEntries list did not seem to serve any
   purpose. Basically it would not disable add-ons
   removed from a watched directory unless it changed
   it's name at the same time. I've removed it completely,
   since it didn't seem to be an optimization
   (entry cache) either.
 * Each actual add-on file is now node-monitored for
   stat changes. So if you have a link in the add-on
   folder, and the linked to add-on changes, it triggers
   a reload of the add-on now. This will make it much
   more pleasant to develop add-ons and have them affective
   immediately.

I tested with a fresh image, but there are no immediate
regressions I am aware of. I could imagine that messing
with certain add-ons can have a bad effect now, like
removing the keyboard input_server add-on may trigger the
keyboard to stop working immediately without an input_server
restart, but Tracker should warn before it happens.


Modified: haiku/trunk/headers/private/storage/AddOnMonitorHandler.h
===================================================================
--- haiku/trunk/headers/private/storage/AddOnMonitorHandler.h   2010-08-19 
19:40:15 UTC (rev 38279)
+++ haiku/trunk/headers/private/storage/AddOnMonitorHandler.h   2010-08-19 
19:52:19 UTC (rev 38280)
@@ -1,10 +1,11 @@
 /*
- * Copyright 2004-2008, Haiku, Inc. All rights reserved.
+ * Copyright 2004-2010, Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _ADD_ON_MONITOR_HANDLER_H
 #define _ADD_ON_MONITOR_HANDLER_H
 
+
 #include <list>
 
 #include "NodeMonitorHandler.h"
@@ -13,55 +14,112 @@
 namespace BPrivate {
 namespace Storage {
 
+
 struct add_on_entry_info {
        char name[B_FILE_NAME_LENGTH];
        node_ref nref;
        node_ref dir_nref;
+       node_ref addon_nref;
 };
 
-struct add_on_directory_info {
-       node_ref nref;
-       std::list<add_on_entry_info> entries;
-};
 
 class AddOnMonitorHandler : public NodeMonitorHandler {
 public:
-                                               AddOnMonitorHandler(const char* 
name = NULL);
-       virtual                         ~AddOnMonitorHandler();
+                                                               
AddOnMonitorHandler(const char* name = NULL);
+       virtual                                         ~AddOnMonitorHandler();
 
-       virtual void            MessageReceived(BMessage* msg);
+       virtual void                            MessageReceived(BMessage* 
message);
 
-       // supply the add-on directories here, in the order you want them 
checked
-       virtual status_t        AddDirectory(const node_ref* nref);
+       // Supply the add-on directories here, in the order you want them 
checked.
+       // Add-ons in directories added earlier will shadow add-ons in 
directories
+       // added later, if they share the same file name. If an add-on is 
removed
+       // from or renamed in a directory and it has previously shadowed another
+       // add-on, the previously shadowed add-on shall become enabled
+       // (AddOnEnabled()). If an add-on appears in a directory, or is renamed,
+       // it can cause another add-on to become disabled, if it has the same 
name.
+       // Note that directories are not watched recursively, and all entries
+       // are reported as add-ons regardless of their node type (files,
+       // directories, symlinks).
+       virtual status_t                        AddDirectory(const node_ref* 
nref);
 
 protected:
-       // hooks for subclass
-       virtual void            AddOnCreated(const add_on_entry_info* 
entryInfo);
-       virtual void            AddOnEnabled(const add_on_entry_info* 
entryInfo);
-       virtual void            AddOnDisabled(const add_on_entry_info* 
entryInfo);
-       virtual void            AddOnRemoved(const add_on_entry_info* 
entryInfo);
+       // hooks for sub-class
+       virtual void                            AddOnCreated(
+                                                                       const 
add_on_entry_info* entryInfo);
+       virtual void                            AddOnEnabled(
+                                                                       const 
add_on_entry_info* entryInfo);
+       virtual void                            AddOnDisabled(
+                                                                       const 
add_on_entry_info* entryInfo);
+                                                                       // name 
field will be invalid!
+       virtual void                            AddOnRemoved(
+                                                                       const 
add_on_entry_info* entryInfo);
+                                                                       // name 
field will be invalid!
 
 protected:
-       virtual void            EntryCreated(const char* name, ino_t directory,
-                                                       dev_t device, ino_t 
node);
-       virtual void            EntryRemoved(ino_t directory, dev_t device, 
ino_t node);
-       virtual void            EntryMoved(const char* name, ino_t 
fromDirectory,
-                                                       ino_t toDirectory, 
dev_t device, ino_t node);
+       virtual void                            EntryCreated(const char* name, 
ino_t directory,
+                                                                       dev_t 
device, ino_t node);
+       virtual void                            EntryRemoved(ino_t directory, 
dev_t device,
+                                                                       ino_t 
node);
+       virtual void                            EntryMoved(const char* name,
+                                                                       ino_t 
fromDirectory, ino_t toDirectory,
+                                                                       dev_t 
device, ino_t node);
+       virtual void                            StatChanged(ino_t node, dev_t 
device);
 
 private:
-       typedef NodeMonitorHandler inherited;
+                       void                            _HandlePulse();
+                       void                            
_EntryCreated(add_on_entry_info& info);
 
-                       void            _HandlePulse();
+                       typedef NodeMonitorHandler inherited;
+                       typedef std::list<add_on_entry_info> EntryList;
 
-       std::list<add_on_directory_info> fDirectories;
-       std::list<add_on_entry_info> fPendingEntries;
-       std::list<add_on_entry_info> fFormerEntries;
+                       struct add_on_directory_info {
+                               node_ref                nref;
+                               EntryList               entries;
+                       };
+
+                       typedef std::list<add_on_directory_info> DirectoryList;
+
+                       bool                            _FindEntry(const 
node_ref& entry,
+                                                                       const 
EntryList& list,
+                                                                       
EntryList::iterator& it) const;
+                       bool                            _FindEntry(const char* 
name,
+                                                                       const 
EntryList& list,
+                                                                       
EntryList::iterator& it) const;
+
+                       bool                            _HasEntry(const 
node_ref& entry,
+                                                                       
EntryList& list) const;
+                       bool                            _HasEntry(const char* 
name,
+                                                                       
EntryList& list) const;
+
+                       bool                            _FindDirectory(ino_t 
directory, dev_t device,
+                                                                       
DirectoryList::iterator& it) const;
+                       bool                            _FindDirectory(
+                                                                       const 
node_ref& directoryNodeRef,
+                                                                       
DirectoryList::iterator& it) const;
+                       bool                            _FindDirectory(ino_t 
directory, dev_t device,
+                                                                       
DirectoryList::iterator& it,
+                                                                       const 
DirectoryList::const_iterator& end)
+                                                                               
const;
+                       bool                            _FindDirectory(
+                                                                       const 
node_ref& directoryNodeRef,
+                                                                       
DirectoryList::iterator& it,
+                                                                       const 
DirectoryList::const_iterator& end)
+                                                                               
const;
+
+                       void                            _AddNewEntry(EntryList& 
list,
+                                                                       
add_on_entry_info& info);
+
+private:
+                       DirectoryList           fDirectories;
+                       EntryList                       fPendingEntries;
 };
 
 
 }; // namespace Storage
 }; // namespace BPrivate
 
+
 using namespace BPrivate::Storage;
 
+
 #endif // _ADD_ON_MONITOR_HANDLER_H

Modified: haiku/trunk/src/kits/storage/AddOnMonitorHandler.cpp
===================================================================
--- haiku/trunk/src/kits/storage/AddOnMonitorHandler.cpp        2010-08-19 
19:40:15 UTC (rev 38279)
+++ haiku/trunk/src/kits/storage/AddOnMonitorHandler.cpp        2010-08-19 
19:52:19 UTC (rev 38280)
@@ -4,6 +4,7 @@
  *
  * Authors:
  *             Andrew Bachmann
+ *             Stephan Aßmus <superstippi@xxxxxx>
  */
 
 
@@ -29,6 +30,16 @@
 
 AddOnMonitorHandler::~AddOnMonitorHandler()
 {
+       // TODO: Actually calling watch_node() here should be too late, since we
+       // are likely not attached to a looper anymore, and thus consitute no 
valid
+       // BMessenger at this time.
+       DirectoryList::iterator it = fDirectories.begin();
+       for (; it != fDirectories.end(); it++) {
+               EntryList::iterator eiter = it->entries.begin();
+               for (; eiter != it->entries.end(); eiter++)
+                       watch_node(&eiter->addon_nref, B_STOP_WATCHING, this);
+               watch_node(&it->nref, B_STOP_WATCHING, this);
+       }
 }
 
 
@@ -47,16 +58,17 @@
 {
        // Keep the looper thread locked, since this method is likely to be 
called
        // in a thread other than the looper thread. Otherwise we may access the
-       // lists concurrently with the looper thread, when node monitor 
notifications
-       // arrive while we are still adding initial entries from the directory, 
or
-       // (much more likely) if the looper thread handles a pulse message and 
wants
-       // to process pending entries while we are still adding them.
+       // lists concurrently with the looper thread, when node monitor
+       // notifications arrive while we are still adding initial entries from 
the
+       // directory, or (much more likely) if the looper thread handles a pulse
+       // message and wants to process pending entries while we are still 
adding
+       // them.
        BAutolock _(Looper());
 
        // ignore directories added twice
-       std::list<add_on_directory_info>::iterator iterator = 
fDirectories.begin();
-       for (; iterator != fDirectories.end() ; iterator++) {
-               if (iterator->nref == *nref)
+       DirectoryList::iterator it = fDirectories.begin();
+       for (; it != fDirectories.end(); it++) {
+               if (it->nref == *nref)
                        return B_OK;
        }
 
@@ -65,25 +77,24 @@
        if (status != B_OK)
                return status;
 
+       status = watch_node(nref, B_WATCH_DIRECTORY, this);
+       if (status != B_OK)
+               return status;
+
        add_on_directory_info dirInfo;
        dirInfo.nref = *nref;
        fDirectories.push_back(dirInfo);
 
-       status = watch_node(nref, B_WATCH_DIRECTORY, this);
-       if (status != B_OK) {
-               fDirectories.pop_back();
-               return status;
-       }
+       add_on_entry_info entryInfo;
+       entryInfo.dir_nref = *nref;
 
        BEntry entry;
-       while (directory.GetNextEntry(&entry, true) == B_OK) {
-               add_on_entry_info entryInfo;
+       while (directory.GetNextEntry(&entry) == B_OK) {
                if (entry.GetName(entryInfo.name) != B_OK
                        || entry.GetNodeRef(&entryInfo.nref) != B_OK) {
                        continue;
                }
 
-               entryInfo.dir_nref = *nref;
                fPendingEntries.push_back(entryInfo);
        }
 
@@ -143,70 +154,55 @@
        // 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 = fPendingEntries.begin();
+       EntryList::iterator eiter = fPendingEntries.begin();
        while (eiter != fPendingEntries.end()) {
-               if (eiter->nref == entryNodeRef) {
+               if (eiter->nref == entryNodeRef)
                        eiter = fPendingEntries.erase(eiter);
-               } else {
+               else
                        eiter++;
-               }
        }
 
-       add_on_entry_info info;
-       node_ref dirNodeRef;
-       make_node_ref(device, directory, &dirNodeRef);
-
-       // find the entry's info, and the entry's directory info
-       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();
-                       for (; eiter != diter->entries.end() ; eiter++) {
-                               info = *eiter;
-                               if (eiter->nref == entryNodeRef) {
-                                       info = *eiter;
-                                       diter->entries.erase(eiter);
-                                       break;
-                               }
-                       }
-                       break;
-               }
+       // Find the directory of the entry.
+       DirectoryList::iterator diter = fDirectories.begin();
+       if (!_FindDirectory(directory, device, diter)) {
+               // If it was not found, we're done
+               return;
        }
 
-       // if it was not found, we're done
-       if (diter == fDirectories.end())
+       eiter = diter->entries.begin();
+       if (!_FindEntry(entryNodeRef, diter->entries, eiter)) {
+               // This must be the directory, but we didn't find the entry.
                return;
+       }
 
+       add_on_entry_info info = *eiter;
+       watch_node(&entryNodeRef, B_STOP_WATCHING, this);
+       diter->entries.erase(eiter);
+
        // Start at the top again, and search until the directory we found
        // the old add-on in. If we find an 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();
-       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 old add-on was not enabled. So we deallocate the old add-on and
+       // return.
+       DirectoryList::iterator diter2 = fDirectories.begin();
+       for (; diter2 != diter; diter2++) {
+               if (_HasEntry(info.name, diter2->entries)) {
+                       AddOnRemoved(&info);
+                       return;
                }
        }
 
-       // The active add-on was removed. We need to disable and
-       // then subsequently deallocate it.
+       // An active add-on was removed. We need to disable and then 
subsequently
+       // deallocate it.
        AddOnDisabled(&info);
        AddOnRemoved(&info);
 
        // Continue searching for an add-on below us. If we find an add-on
        // with the same name, we must enable it.
-       for (diter++ ; diter != fDirectories.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;
-                       }
+       for (diter++; diter != fDirectories.end(); diter++) {
+               eiter = diter->entries.begin();
+               if (_FindEntry(info.name, diter->entries, eiter)) {
+                       AddOnEnabled(&*eiter);
+                       break;
                }
        }
 }
@@ -216,69 +212,49 @@
 AddOnMonitorHandler::EntryMoved(const char* name, ino_t fromDirectory,
        ino_t toDirectory, dev_t device, ino_t node)
 {
-       // 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;
-       }
-
-       // 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;
-       }
 
-       if (from_iter == fDirectories.end() && to_iter == fDirectories.end()) {
+       // Search the "from" and "to" directory in the known directories
+       DirectoryList::iterator from_iter = fDirectories.begin();
+       bool watchingFromDirectory = _FindDirectory(fromDirectory, device,
+               from_iter);
+
+       DirectoryList::iterator to_iter = fDirectories.begin();
+       bool watchingToDirectory = _FindDirectory(toNodeRef, to_iter);
+
+       if (!watchingFromDirectory && !watchingToDirectory) {
                // It seems the notification was for a directory we are not
-               // actually watching by intention.
+               // actually watching (at least not by intention).
                return;
        }
 
        add_on_entry_info info;
+
        node_ref entryNodeRef;
        make_node_ref(device, node, &entryNodeRef);
 
-       if (to_iter == fDirectories.end()) {
+       if (!watchingToDirectory) {
                // 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 (entryNodeRef == eiter->nref) {
-                               // save the info and remove the entry
-                               info = *eiter;
-                               from_iter->entries.erase(eiter);
-                               break;
-                       }
-               }
-
-               if (eiter == from_iter->entries.end()) {
+               EntryList::iterator eiter = from_iter->entries.begin();
+               if (!_FindEntry(entryNodeRef, from_iter->entries, eiter)) {
                        // 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 fFormerEntries for later use
-               if (strcmp(info.name, name) == 0)
-                       fFormerEntries.push_back(info);
+               // save the info and remove the entry
+               info = *eiter;
+               watch_node(&entryNodeRef, B_STOP_WATCHING, this);
+               from_iter->entries.erase(eiter);
 
                // 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 = 
fDirectories.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;
-                               }
-                       }
+               DirectoryList::iterator diter = fDirectories.begin();
+               for (; diter != from_iter; diter++) {
+                       eiter = diter->entries.begin();
+                       if (_FindEntry(info.name, diter->entries, eiter))
+                               return;
                }
 
                // finally disable the add-on
@@ -286,141 +262,110 @@
 
                // 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 != fDirectories.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;
-                               }
+               for (from_iter++; from_iter != fDirectories.end(); from_iter++) 
{
+                       eiter = from_iter->entries.begin();
+                       if (_FindEntry(info.name, from_iter->entries, eiter)) {
+                               AddOnEnabled(&*eiter);
+                               return;
                        }
                }
 
-               // finally, if the new name is different, destroy the addon
-               if (strcmp(info.name, name) != 0)
-                       AddOnRemoved(&info);
+               // finally destroy the addon
+               AddOnRemoved(&info);
 
                // done
                return;
        }
 
-       if (from_iter == fDirectories.end()) {
+       if (!watchingFromDirectory) {
                // moved into our view
-               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;
-                               fFormerEntries.erase(eiter);
-                               break;
-                       }
-               }
 
-               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));
                info.nref = entryNodeRef;
                info.dir_nref = toNodeRef;
 
-               if (eiter == fFormerEntries.end()) {
-                       // this add-on was not seen before
-                       AddOnCreated(&info);
-               }
+               AddOnCreated(&info);
 
                // Start at the top again, and search until the to directory.
                // 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();
-               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;
+               DirectoryList::iterator diter = fDirectories.begin();
+               for (; diter != to_iter; diter++) {
+                       if (_HasEntry(info.name, diter->entries)) {
+                               // The new add-on is being shadowed.
+                               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 != fDirectories.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;
-                               }
+               for (diter++ ; diter != fDirectories.end(); diter++) {
+                       EntryList::iterator eiter = diter->entries.begin();
+                       if (_FindEntry(info.name, diter->entries, eiter)) {
+                               AddOnDisabled(&*eiter);
+                               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);
+               _AddNewEntry(to_iter->entries, info);
 
                // done
                return;
        }
 
-       std::list<add_on_entry_info>::iterator eiter = 
from_iter->entries.begin();
-       for (; eiter != from_iter->entries.end() ; eiter++) {
-               if (entryNodeRef == eiter->nref) {
-                       // save the old info and remove the entry
-                       info = *eiter;
-                       from_iter->entries.erase(eiter);
-                       break;
-               }
+       // The add-on was renamed, or moved within our hierarchy.
+
+       EntryList::iterator eiter = from_iter->entries.begin();
+       if (_FindEntry(entryNodeRef, from_iter->entries, eiter)) {
+               // save the old info and remove the entry
+               info = *eiter;
+       } else {
+               // If an entry moved from one watched directory into another 
watched
+               // directory, there will be two notifications, and this may be 
the
+               // second. We have handled everything in the first. In that 
case the
+               // entry was already removed from the fromDirectory and added 
in the
+               // toDirectory list.
+               return;
        }
 
        if (strcmp(info.name, name) == 0) {
-               // same name moved in heirarchy
-               debugger("add-on moved inside the heirarchy");
+               // It should be impossible for the name to stay the same, 
unless the
+               // node moved in the watched hierarchy. Handle this case by 
removing
+               // the entry and readding it. TODO: This can temporarily enable 
add-ons
+               // which should in fact stay hidden (moving add-on from home to 
common
+               // folder or vice versa, the system add-on should remain 
hidden).
+               EntryRemoved(fromDirectory, device, node);
+               info.dir_nref = toNodeRef;
+               _EntryCreated(info);
        } else {
+               // Erase the entry
+               from_iter->entries.erase(eiter);
+
                // check to see if it was formerly enabled
-               bool was_enabled = true;
-               std::list<add_on_directory_info>::iterator old_iter
-                       = fDirectories.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) {
+               bool wasEnabled = true;
+               DirectoryList::iterator old_iter = fDirectories.begin();
+               for (; old_iter != from_iter; old_iter++) {
+                       if (_HasEntry(info.name, old_iter->entries)) {
+                               wasEnabled = false;
                                break;
                        }
                }
 
-               // if it was enabled, disable it and enable the one under us, 
if it
-               // exists
-               if (was_enabled) {
+               // If it was enabled, disable it and enable the one under us, 
if it
+               // exists.
+               if (wasEnabled) {
                        AddOnDisabled(&info);
-                       bool done = false;
-                       for (; old_iter != fDirectories.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;
-                                       }
+                       for (; old_iter != fDirectories.end(); old_iter++) {
+                               eiter = old_iter->entries.begin();
+                               if (_FindEntry(info.name, old_iter->entries, 
eiter)) {
+                                       AddOnEnabled(&*eiter);
+                                       break;
                                }
-                               if (done)
-                                       break;
                        }
                }
 
@@ -436,56 +381,75 @@
 
                // check to see if we are newly enabled
                bool isEnabled = true;
-               std::list<add_on_directory_info>::iterator new_iter
-                       = fDirectories.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) {
-                                       isEnabled = false;
-                                       break;
-                               }
+               DirectoryList::iterator new_iter = fDirectories.begin();
+               for (; new_iter != to_iter; new_iter++) {
+                       if (_HasEntry(info.name, new_iter->entries)) {
+                               isEnabled = false;
+                               break;
                        }
-                       if (!isEnabled)
-                               break;
                }
 
                // if it is newly enabled, check under us for an enabled one, 
and
                // disable that first
                if (isEnabled) {
-                       bool done = false;
-                       for (; new_iter != fDirectories.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;
-                                       }
+                       for (; new_iter != fDirectories.end(); new_iter++) {
+                               eiter = new_iter->entries.begin();
+                               if (_FindEntry(info.name, new_iter->entries, 
eiter)) {
+                                       AddOnDisabled(&*eiter);
+                                       break;
                                }
-                               if (done)
-                                       break;
                        }
                        AddOnEnabled(&info);
                }
+               // put the new entry into the target directory
+               to_iter->entries.push_back(info);
        }
+}
 
-       // put the new entry into the target directory
-       to_iter->entries.push_back(info);
+
+void
+AddOnMonitorHandler::StatChanged(ino_t node, dev_t device)
+{
+       // This notification is received for the add-ons themselves.
+
+       // TODO: Add the entry to the pending list, disable/enable it
+       // when the modification time remains stable.
+
+       node_ref entryNodeRef;
+       make_node_ref(device, node, &entryNodeRef);
+
+       DirectoryList::iterator diter = fDirectories.begin();
+       for (; diter != fDirectories.end(); diter++) {
+               EntryList::iterator eiter = diter->entries.begin();
+               for (; eiter != diter->entries.end(); eiter++) {
+                       if (eiter->addon_nref == entryNodeRef) {
+                               // Trigger reloading of the add-on
+                               const add_on_entry_info* info = &*eiter;
+                               AddOnDisabled(info);
+                               AddOnRemoved(info);
+                               AddOnCreated(info);
+                               AddOnEnabled(info);
+                               return;
+                       }
+               }
+       }
 }
 
 
+// #pragma mark - private
+
+
 //!    Process pending entries.
 void
 AddOnMonitorHandler::_HandlePulse()
 {
        BDirectory directory;
-       std::list<add_on_entry_info>::iterator iter = fPendingEntries.begin();
+       EntryList::iterator iter = fPendingEntries.begin();
        while (iter != fPendingEntries.end()) {
                add_on_entry_info info = *iter;
 
+               // Initialize directory, or re-use from previous iteration, if
+               // directory node_ref remained the same from the last pending 
entry.
                node_ref dirNodeRef;
                if (directory.GetNodeRef(&dirNodeRef) != B_OK
                        || dirNodeRef != info.dir_nref) {
@@ -514,58 +478,150 @@
                // we are going to deal with the stable entry, so remove it
                iter = fPendingEntries.erase(iter);
 
-               // put the new entry into the directory info
-               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;
-                       }
+               _EntryCreated(info);
+       }
+}
+
+
+void
+AddOnMonitorHandler::_EntryCreated(add_on_entry_info& info)
+{
+       // put the new entry into the directory info
+       DirectoryList::iterator diter = fDirectories.begin();
+       for (; diter != fDirectories.end(); diter++) {
+               if (diter->nref == info.dir_nref) {
+                       _AddNewEntry(diter->entries, info);
+                       break;
                }
+       }
 
-               // report it
-               AddOnCreated(&info);
+       // report it
+       AddOnCreated(&info);
 
-               // Start at the top again, and search until the directory we put
-               // the new add-on in.  If we find an 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
-                       = fDirectories.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;
+       // Start at the top again, and search until the directory we put
+       // the new add-on in.  If we find an add-on with the same name then
+       // the new add-on should not be enabled.
+       bool enabled = true;
+       DirectoryList::iterator diter2 = fDirectories.begin();
+       for (; diter2 != diter; diter2++) {
+               if (_HasEntry(info.name, diter2->entries)) {
+                       enabled = false;
+                       break;
                }
-               if (!enabled) {
-                       // if we are not enabled, go on to the next pending 
entry
-                       continue;
-               }
+       }
+       if (!enabled)
+               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 != fDirectories.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;
+       // The new add-on should be enabled, but first we check to see
+       // if there is an add-on shadowed by the new one.  If we find one,
+       // we disable it.
+       for (diter++ ; diter != fDirectories.end(); diter++) {
+               EntryList::iterator eiter = diter->entries.begin();
+               if (_FindEntry(info.name, diter->entries, eiter)) {
+                       AddOnDisabled(&*eiter);
+                       break;
                }
+       }
 
-               // finally, enable the new entry
-               AddOnEnabled(&info);
+       // enable the new entry
+       AddOnEnabled(&info);
+}
+
+
+bool
+AddOnMonitorHandler::_FindEntry(const node_ref& entry, const EntryList& list,
+       EntryList::iterator& it) const
+{
+       for (; it != list.end(); it++) {
+               if (it->nref == entry)
+                       return true;
        }
+       return false;
 }
+
+
+bool
+AddOnMonitorHandler::_FindEntry(const char* name, const EntryList& list,
+       EntryList::iterator& it) const
+{
+       for (; it != list.end(); it++) {
+               if (strcmp(it->name, name) == 0)
+                       return true;
+       }
+       return false;
+}
+
+
+bool
+AddOnMonitorHandler::_HasEntry(const node_ref& entry, EntryList& list) const
+{
+       EntryList::iterator it = list.begin();
+       return _FindEntry(entry, list, it);
+}
+
+
+bool
+AddOnMonitorHandler::_HasEntry(const char* name, EntryList& list) const
+{
+       EntryList::iterator it = list.begin();
+       return _FindEntry(name, list, it);
+}
+
+
+bool
+AddOnMonitorHandler::_FindDirectory(ino_t directory, dev_t device,
+       DirectoryList::iterator& it) const
+{
+       node_ref nodeRef;
+       make_node_ref(device, directory, &nodeRef);
+       return _FindDirectory(nodeRef, it, fDirectories.end());
+}
+
+
+bool
+AddOnMonitorHandler::_FindDirectory(const node_ref& directoryNodeRef,
+       DirectoryList::iterator& it) const
+{
+       return _FindDirectory(directoryNodeRef, it, fDirectories.end());
+}
+
+
+bool
+AddOnMonitorHandler::_FindDirectory(ino_t directory, dev_t device,
+       DirectoryList::iterator& it,
+       const DirectoryList::const_iterator& end) const
+{
+       node_ref nodeRef;
+       make_node_ref(device, directory, &nodeRef);
+       return _FindDirectory(nodeRef, it, end);
+}
+
+
+bool
+AddOnMonitorHandler::_FindDirectory(const node_ref& directoryNodeRef,
+       DirectoryList::iterator& it,
+       const DirectoryList::const_iterator& end) const
+{
+       for (; it != end; it++) {
+               if (it->nref == directoryNodeRef)
+                       return true;
+       }
+       return false;
+}
+
+
+void
+AddOnMonitorHandler::_AddNewEntry(EntryList& list, add_on_entry_info& info)
+{
+       BDirectory directory(&info.dir_nref);
+       BEntry entry(&directory, info.name, true);
+
+       node_ref addOnRef;      
+       if (entry.GetNodeRef(&addOnRef) == B_OK) {
+               watch_node(&addOnRef, B_WATCH_STAT, this);
+               info.addon_nref = addOnRef;
+       } else
+               info.addon_nref = info.nref;
+
+       list.push_back(info);
+}


Other related posts:

  • » [haiku-commits] r38280 - in haiku/trunk: headers/private/storage src/kits/storage - superstippi