#include "FolderWatcher.h"
#include <stdio.h>
#include <kernel/fs_attr.h>
#include <Node.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
FolderWatcher::FolderWatcher(BLooper* looper, const BDirectory& folder, bool watchAttrChanges)
: fFolder(folder)
, fListener(NULL)
, fWatchAttrChanges(watchAttrChanges)
{
if (looper->Lock()) {
looper->AddHandler(this);
looper->Unlock();
}
if (watchAttrChanges) {
BEntry entry;
node_ref node;
while (fFolder.GetNextEntry(&entry) == B_OK && entry.GetNodeRef(&node) == B_OK) {
StartAttrWatching(&node);
}
}
node_ref ref;
fFolder.GetNodeRef(&ref);
watch_node(&ref, B_WATCH_DIRECTORY, this);
}
FolderWatcher::~FolderWatcher() {
node_ref ref;
fFolder.GetNodeRef(&ref);
watch_node(&ref, B_STOP_WATCHING, this);
stop_watching(this);
if (LockLooper()) {
BLooper* looper = Looper();
looper->RemoveHandler(this);
looper->Unlock();
}
}
void FolderWatcher::SetListener(FolderListener* listener) {
fListener = listener;
}
bool FolderWatcher::BuildEntryRef(BMessage* msg, const char* dirName, entry_ref* entry) {
const char* name;
if (msg->FindInt32("device", &entry->device) == B_OK &&
msg->FindInt64(dirName, &entry->directory) == B_OK &&
msg->FindString("name", &name) == B_OK) {
entry->set_name(name);
return true;
}
return false;
}
bool FolderWatcher::BuildNodeRef(BMessage* msg, node_ref* node) {
return (msg->FindInt32("device", &node->device) == B_OK &&
msg->FindInt64("node", &node->node) == B_OK);
}
void FolderWatcher::HandleCreatedEntry(BMessage* msg, const char* dirName) {
node_ref node;
entry_ref entry;
if (BuildEntryRef(msg, dirName, &entry) &&
BuildNodeRef(msg, &node)) {
if (fWatchAttrChanges) StartAttrWatching(&node);
fListener->EntryCreated(&node, &entry);
}
}
void FolderWatcher::HandleRemovedEntry(BMessage* msg) {
node_ref node;
if (BuildNodeRef(msg, &node)) {
if (fWatchAttrChanges) StopAttrWatching(&node);
fListener->EntryRemoved(&node);
}
}
void FolderWatcher::HandleChangedAttr(BMessage* msg) {
node_ref node;
if (BuildNodeRef(msg, &node)) {
fListener->AttributeChanged(&node);
}
}
void FolderWatcher::MessageReceived(BMessage* msg) {
int32 opcode;
node_ref folder;
ino_t dir;
if (msg->what == B_NODE_MONITOR) {
if (fListener == NULL || msg->FindInt32("opcode", &opcode) != B_OK) return;
switch (opcode) {
case B_ENTRY_CREATED:
HandleCreatedEntry(msg, "directory");
break;
case B_ENTRY_REMOVED:
HandleRemovedEntry(msg);
break;
case B_ENTRY_MOVED:
fFolder.GetNodeRef(&folder);
if (msg->FindInt64("to directory", &dir) == B_OK && folder.node == dir) {
HandleCreatedEntry(msg, "to directory");
} else if (msg->FindInt64("from directory", &dir) == B_OK && folder.node == dir) {
HandleRemovedEntry(msg);
}
break;
case B_ATTR_CHANGED:
HandleChangedAttr(msg);
break;
default:
break;
}
} else {
inherited::MessageReceived(msg);
}
}
status_t FolderWatcher::StartAttrWatching(node_ref* node) {
return watch_node(node, B_WATCH_ATTR, this);
}
status_t FolderWatcher::StopAttrWatching(node_ref* node) {
return watch_node(node, B_STOP_WATCHING, this);
}