311 lines
5.2 KiB
C++
311 lines
5.2 KiB
C++
/*
|
|
* Copyright 2011, Haiku, Inc. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Clemens Zeidler <haiku@clemens-zeidler.de>
|
|
*/
|
|
|
|
#include "FileMonitor.h"
|
|
|
|
#include <Looper.h>
|
|
|
|
#include <Messenger.h>
|
|
#include <NodeMonitor.h>
|
|
|
|
|
|
FileMonitor::FileMonitor(EntryViewInterface* listener)
|
|
:
|
|
fListener(listener),
|
|
fCurrentReadList(NULL),
|
|
fCurrentReadIndex(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
FileMonitor::~FileMonitor()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::SetReadThread(ReadThread* readThread)
|
|
{
|
|
fReadThread = readThread;
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::Reset()
|
|
{
|
|
fWatchedFileList.clear();
|
|
stop_watching(this);
|
|
|
|
BMessenger messenger(this);
|
|
messenger.SendMessage(kMsgCleared);
|
|
|
|
if (fCurrentReadList != NULL)
|
|
fCurrentReadIndex = fCurrentReadList->size();
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::MessageReceived(BMessage* msg)
|
|
{
|
|
switch (msg->what) {
|
|
case kMsgAddRefs:
|
|
{
|
|
if (fCurrentReadList == NULL)
|
|
fCurrentReadList = fReadThread->ReadRefList();
|
|
uint32 terminate = fCurrentReadIndex + 50;
|
|
for (; fCurrentReadIndex < terminate; fCurrentReadIndex++) {
|
|
if (fCurrentReadIndex >= fCurrentReadList->size()) {
|
|
fCurrentReadList = NULL;
|
|
fCurrentReadIndex = 0;
|
|
fReadThread->ReadDone();
|
|
break;
|
|
}
|
|
|
|
entry_ref& entry = (*fCurrentReadList)[fCurrentReadIndex];
|
|
node_ref nodeRef;
|
|
BNode node(&entry);
|
|
if (node.GetNodeRef(&nodeRef) != B_OK)
|
|
continue;
|
|
|
|
EntryCreated(entry.name, entry.directory, entry.device,
|
|
nodeRef.node);
|
|
}
|
|
if (fCurrentReadList)
|
|
Looper()->PostMessage(kMsgAddRefs, this);
|
|
|
|
break;
|
|
}
|
|
|
|
case kMsgCleared:
|
|
fListener->EntriesCleared();
|
|
break;
|
|
|
|
default:
|
|
NodeMonitorHandler::MessageReceived(msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::EntryCreated(const char *name, ino_t directory, dev_t device,
|
|
ino_t node)
|
|
{
|
|
WatchedFile file;
|
|
NodeMonitorHandler::make_node_ref(device, node, &file.node);
|
|
if (fWatchedFileList.find(file.node) != fWatchedFileList.end())
|
|
return;
|
|
|
|
NodeMonitorHandler::make_entry_ref(device, directory, name, &file.entry);
|
|
fWatchedFileList[file.node] = file;
|
|
|
|
watch_node(&file.node, B_WATCH_NAME | B_WATCH_STAT | B_WATCH_ATTR, this);
|
|
fListener->EntryCreated(&fWatchedFileList[file.node]);
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::EntryRemoved(const char *name, ino_t directory, dev_t device,
|
|
ino_t node)
|
|
{
|
|
WatchedFile* file = _FindFile(device, node);
|
|
if (file == NULL)
|
|
return;
|
|
|
|
fListener->EntryRemoved(file);
|
|
fWatchedFileList.erase(file->node);
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::EntryMoved(const char *name, const char *fromName,
|
|
ino_t fromDirectory, ino_t toDirectory, dev_t device, ino_t node,
|
|
dev_t nodeDevice)
|
|
{
|
|
WatchedFile* file = _FindFile(device, node);
|
|
if (file == NULL)
|
|
return;
|
|
NodeMonitorHandler::make_entry_ref(device, toDirectory, name, &file->entry);
|
|
NodeMonitorHandler::make_node_ref(device, node, &file->node);
|
|
fListener->EntryMoved(file);
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::StatChanged(ino_t node, dev_t device, int32 statFields)
|
|
{
|
|
WatchedFile* file = _FindFile(device, node);
|
|
if (file == NULL)
|
|
return;
|
|
fListener->StatChanged(file);
|
|
}
|
|
|
|
|
|
void
|
|
FileMonitor::AttrChanged(ino_t node, dev_t device)
|
|
{
|
|
WatchedFile* file = _FindFile(device, node);
|
|
if (file == NULL)
|
|
return;
|
|
fListener->AttrChanged(file);
|
|
}
|
|
|
|
|
|
WatchedFile*
|
|
FileMonitor::_FindFile(dev_t device, ino_t node)
|
|
{
|
|
node_ref nodeRef;
|
|
NodeMonitorHandler::make_node_ref(device, node, &nodeRef);
|
|
|
|
WatchedFileList::iterator it = fWatchedFileList.find(nodeRef);
|
|
if (it == fWatchedFileList.end())
|
|
return NULL;
|
|
|
|
return &it->second;
|
|
}
|
|
|
|
|
|
int32
|
|
ReadThreadFunction(void *data)
|
|
{
|
|
ReadThread* that = (ReadThread*)data;
|
|
return that->Process();
|
|
}
|
|
|
|
|
|
ReadThread::ReadThread(FileMonitor* target)
|
|
:
|
|
fTarget(target),
|
|
fReading(false),
|
|
fStopped(false),
|
|
fThreadId(-1),
|
|
fNReaded(0),
|
|
fRunning(false)
|
|
{
|
|
fWriteRefList = &fRefList1;
|
|
fReadRefList = &fRefList2;
|
|
}
|
|
|
|
|
|
status_t
|
|
ReadThread::Run()
|
|
{
|
|
if (fThreadId >= 0)
|
|
return B_ERROR;
|
|
|
|
fStopped = false;
|
|
fThreadId = spawn_thread(ReadThreadFunction, "file reader", B_LOW_PRIORITY,
|
|
this);
|
|
fRunning = true;
|
|
status_t status = resume_thread(fThreadId);
|
|
if (status != B_OK)
|
|
fRunning = false;
|
|
return status;
|
|
}
|
|
|
|
|
|
bool
|
|
ReadThread::Running()
|
|
{
|
|
return fRunning;
|
|
}
|
|
|
|
|
|
status_t
|
|
ReadThread::Wait()
|
|
{
|
|
status_t exitValue;
|
|
return wait_for_thread(fThreadId, &exitValue);
|
|
}
|
|
|
|
|
|
void
|
|
ReadThread::Stop()
|
|
{
|
|
fStopped = true;
|
|
}
|
|
|
|
|
|
bool
|
|
ReadThread::Stopped()
|
|
{
|
|
return fStopped;
|
|
}
|
|
|
|
|
|
RefList*
|
|
ReadThread::ReadRefList()
|
|
{
|
|
return fReadRefList;
|
|
}
|
|
|
|
|
|
void
|
|
ReadThread::ReadDone()
|
|
{
|
|
fReadRefList->clear();
|
|
// and release the list
|
|
fReading = false;
|
|
|
|
if (!fRunning && fWriteRefList->size() != 0) {
|
|
BMessenger messenger(fTarget);
|
|
_PublishEntrys(messenger);
|
|
}
|
|
}
|
|
|
|
|
|
int32
|
|
ReadThread::Process()
|
|
{
|
|
BMessenger messenger(fTarget);
|
|
|
|
entry_ref entry;
|
|
while (ReadNextEntry(entry)) {
|
|
if (Stopped()) {
|
|
fWriteRefList->clear();
|
|
break;
|
|
}
|
|
|
|
fWriteRefList->push_back(entry);
|
|
|
|
fNReaded++;
|
|
if (fNReaded >= 50)
|
|
_PublishEntrys(messenger);
|
|
}
|
|
|
|
fRunning = false;
|
|
|
|
_PublishEntrys(messenger);
|
|
|
|
fThreadId = -1;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
ReadThread::_SwapLists()
|
|
{
|
|
RefList* lastReadList = fReadRefList;
|
|
fReadRefList = fWriteRefList;
|
|
fWriteRefList = lastReadList;
|
|
}
|
|
|
|
|
|
void
|
|
ReadThread::_PublishEntrys(BMessenger& messenger)
|
|
{
|
|
if (fReading || Stopped())
|
|
return;
|
|
_SwapLists();
|
|
fReading = true;
|
|
fNReaded = 0;
|
|
messenger.SendMessage(kMsgAddRefs);
|
|
}
|