Initial work on an index server. No add-on yet so quite useless at the moment, but a clucent full-text search add-on is coming soon.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39160 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef INDEX_SERVER_ADD_ON_H
|
||||||
|
#define INDEX_SERVER_ADD_ON_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <image.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <Volume.h>
|
||||||
|
|
||||||
|
#include "Referenceable.h"
|
||||||
|
|
||||||
|
|
||||||
|
class analyser_settings {
|
||||||
|
public:
|
||||||
|
analyser_settings();
|
||||||
|
|
||||||
|
bool catchUpEnabled;
|
||||||
|
//! the volume is scanned form 0 to syncPosition, from
|
||||||
|
//! syncPosition to watchingStart the volume is not scanned
|
||||||
|
bigtime_t syncPosition;
|
||||||
|
bigtime_t watchingStart;
|
||||||
|
bigtime_t watchingPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FileAnalyser;
|
||||||
|
|
||||||
|
|
||||||
|
/*! Thread safe class to sync settings between different FileAnalyser. For
|
||||||
|
example the watcher analyser and the catch up analyser. Because the lock
|
||||||
|
overhead use it only when necessary or use a cached analyser_settings if
|
||||||
|
possible. */
|
||||||
|
class AnalyserSettings : public BReferenceable {
|
||||||
|
public:
|
||||||
|
AnalyserSettings(const BString& name,
|
||||||
|
const BVolume& volume);
|
||||||
|
|
||||||
|
const BString& Name() { return fName; }
|
||||||
|
const BVolume& Volume() { return fVolume; }
|
||||||
|
|
||||||
|
bool ReadSettings();
|
||||||
|
bool WriteSettings();
|
||||||
|
|
||||||
|
analyser_settings RawSettings();
|
||||||
|
|
||||||
|
// settings
|
||||||
|
void SetCatchUpEnabled(bool enabled);
|
||||||
|
void SetSyncPosition(bigtime_t time);
|
||||||
|
void SetWatchingStart(bigtime_t time);
|
||||||
|
void SetWatchingPosition(bigtime_t time);
|
||||||
|
|
||||||
|
bool CatchUpEnabled();
|
||||||
|
bigtime_t SyncPosition();
|
||||||
|
bigtime_t WatchingStart();
|
||||||
|
bigtime_t WatchingPosition();
|
||||||
|
private:
|
||||||
|
BString fName;
|
||||||
|
BVolume fVolume;
|
||||||
|
|
||||||
|
BLocker fSettingsLock;
|
||||||
|
analyser_settings fAnalyserSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FileAnalyser {
|
||||||
|
public:
|
||||||
|
FileAnalyser(const BString& name,
|
||||||
|
const BVolume& volume);
|
||||||
|
virtual ~FileAnalyser() {}
|
||||||
|
|
||||||
|
void SetSettings(AnalyserSettings* settings);
|
||||||
|
AnalyserSettings* Settings() const;
|
||||||
|
const analyser_settings& CachedSettings() const;
|
||||||
|
void UpdateSettingsCache();
|
||||||
|
|
||||||
|
const BString& Name() const { return fName; }
|
||||||
|
const BVolume& Volume() const { return fVolume; }
|
||||||
|
|
||||||
|
virtual status_t InitCheck() = 0;
|
||||||
|
|
||||||
|
virtual void AnalyseEntry(const entry_ref& ref) = 0;
|
||||||
|
virtual void DeleteEntry(const entry_ref& ref) { }
|
||||||
|
virtual void MoveEntry(const entry_ref& oldRef,
|
||||||
|
const entry_ref& newRef) { }
|
||||||
|
//! If the indexer send a bunch of entry this indicates that the last one
|
||||||
|
//! has been arrived.
|
||||||
|
virtual void LastEntry() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BVolume fVolume;
|
||||||
|
BReference<AnalyserSettings> fAnalyserSettings;
|
||||||
|
analyser_settings fCachedSettings;
|
||||||
|
private:
|
||||||
|
BString fName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef BObjectList<FileAnalyser> FileAnalyserList;
|
||||||
|
|
||||||
|
|
||||||
|
class IndexServerAddOn {
|
||||||
|
public:
|
||||||
|
IndexServerAddOn(image_id id, const char* name)
|
||||||
|
:
|
||||||
|
fImageId(id),
|
||||||
|
fName(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~IndexServerAddOn() {}
|
||||||
|
|
||||||
|
image_id ImageId() { return fImageId; }
|
||||||
|
BString Name() { return fName; }
|
||||||
|
|
||||||
|
virtual FileAnalyser* CreateFileAnalyser(const BVolume& volume) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
image_id fImageId;
|
||||||
|
BString fName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef IndexServerAddOn* create_index_server_addon(image_id id,
|
||||||
|
const char* name);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef INDEX_SERVER_PRIVATE_H
|
||||||
|
#define INDEX_SERVER_PRIVATE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
const BString kIndexServerDirectory = ".IndexServer";
|
||||||
|
const BString kVolumeStatusFileName = "VolumeStatus";
|
||||||
|
|
||||||
|
// messages between preferences app
|
||||||
|
const uint32 kStopWatching = 'StoW';
|
||||||
|
const uint32 kStartWatching = 'StaW';
|
||||||
|
|
||||||
|
const uint32 kRegisterWatcher = 'RegW';
|
||||||
|
const uint32 kVolumenAdded = 'VAdd';
|
||||||
|
const uint32 kVolumenRemoved = 'VRem';
|
||||||
|
const uint32 kAddOnAdded = 'AAdd';
|
||||||
|
const uint32 kAddOnRemoved = 'ARem';
|
||||||
|
|
||||||
|
const uint32 kGetVolumenInfos = 'GVIn';
|
||||||
|
const uint32 kGetAddOnInfos = 'GAIn';
|
||||||
|
|
||||||
|
const uint32 kEnableAddOn = 'EnaA';
|
||||||
|
const uint32 kDisableAddOn = 'DisA';
|
||||||
|
|
||||||
|
#endif // INDEX_SERVER_PRIVATE_H
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef ANALYSER_DISPATCHER
|
||||||
|
#define ANALYSER_DISPATCHER
|
||||||
|
|
||||||
|
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "IndexServerAddOn.h"
|
||||||
|
|
||||||
|
|
||||||
|
class FileAnalyser;
|
||||||
|
|
||||||
|
|
||||||
|
class AnalyserDispatcher : public BLooper {
|
||||||
|
public:
|
||||||
|
AnalyserDispatcher();
|
||||||
|
~AnalyserDispatcher();
|
||||||
|
|
||||||
|
void Stop();
|
||||||
|
bool Stopped();
|
||||||
|
|
||||||
|
bool Busy();
|
||||||
|
|
||||||
|
void AnalyseEntry(const entry_ref& ref);
|
||||||
|
void DeleteEntry(const entry_ref& ref);
|
||||||
|
void MoveEntry(const entry_ref& oldRef,
|
||||||
|
const entry_ref& newRef);
|
||||||
|
void LastEntry();
|
||||||
|
|
||||||
|
//! thread safe
|
||||||
|
bool AddAnalyser(FileAnalyser* analyser);
|
||||||
|
bool RemoveAnalyser(const BString& name);
|
||||||
|
|
||||||
|
void WriteAnalyserSettings();
|
||||||
|
void SetSyncPosition(bigtime_t time);
|
||||||
|
void SetWatchingStart(bigtime_t time);
|
||||||
|
void SetWatchingPosition(bigtime_t time);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FileAnalyserList fFileAnalyserList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileAnalyser* _FindAnalyser(const BString& name);
|
||||||
|
|
||||||
|
vint32 fStopped;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ANALYSER_DISPATCHER
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CatchUpManager.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Debug.h>
|
||||||
|
#include <Query.h>
|
||||||
|
|
||||||
|
#include "IndexServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint32 kCatchUp = '&CaU';
|
||||||
|
const uint32 kCatchUpDone = '&CUD';
|
||||||
|
|
||||||
|
const bigtime_t kSecond = 1000000;
|
||||||
|
|
||||||
|
|
||||||
|
CatchUpAnalyser::CatchUpAnalyser(const BVolume& volume, time_t start,
|
||||||
|
time_t end, BHandler* manager)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fStart(start),
|
||||||
|
fEnd(end),
|
||||||
|
fCatchUpManager(manager)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpAnalyser::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kCatchUp:
|
||||||
|
_CatchUp();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLooper::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpAnalyser::StartAnalysing()
|
||||||
|
{
|
||||||
|
PostMessage(kCatchUp);
|
||||||
|
Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpAnalyser::AnalyseEntry(const entry_ref& ref)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++) {
|
||||||
|
FileAnalyser* analyser = fFileAnalyserList.ItemAt(i);
|
||||||
|
const analyser_settings& settings = analyser->CachedSettings();
|
||||||
|
if (settings.syncPosition / kSecond >= fStart
|
||||||
|
&& settings.watchingStart / kSecond <= fEnd)
|
||||||
|
analyser->AnalyseEntry(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpAnalyser::_CatchUp()
|
||||||
|
{
|
||||||
|
STRACE("_CatchUp start %i, end %i\n", (int)fStart, (int)fEnd);
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
STRACE("- Analyser %s\n", fFileAnalyserList.ItemAt(i)->Name().String());
|
||||||
|
|
||||||
|
BQuery query;
|
||||||
|
query.SetVolume(&fVolume);
|
||||||
|
query.PushAttr("last_modified");
|
||||||
|
query.PushInt32(fStart);
|
||||||
|
query.PushOp(B_GE);
|
||||||
|
query.PushAttr("last_modified");
|
||||||
|
query.PushInt32(fEnd);
|
||||||
|
query.PushOp(B_LE);
|
||||||
|
query.PushOp(B_AND);
|
||||||
|
|
||||||
|
query.Fetch();
|
||||||
|
|
||||||
|
std::vector<entry_ref> entryList;
|
||||||
|
entry_ref ref;
|
||||||
|
while (query.GetNextRef(&ref) == B_OK)
|
||||||
|
entryList.push_back(ref);
|
||||||
|
|
||||||
|
printf("CatchUpAnalyser:: entryList.size() %i\n", (int)entryList.size());
|
||||||
|
|
||||||
|
if (entryList.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < entryList.size(); i++) {
|
||||||
|
if (Stopped())
|
||||||
|
return;
|
||||||
|
AnalyseEntry(entryList[i]);
|
||||||
|
}
|
||||||
|
LastEntry();
|
||||||
|
|
||||||
|
_WriteSyncSatus(fEnd);
|
||||||
|
|
||||||
|
BMessenger managerMessenger(fCatchUpManager);
|
||||||
|
BMessage msg(kCatchUpDone);
|
||||||
|
msg.AddPointer("Analyser", this);
|
||||||
|
managerMessenger.SendMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpAnalyser::_WriteSyncSatus(bigtime_t syncTime)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++) {
|
||||||
|
AnalyserSettings* settings = fFileAnalyserList.ItemAt(i)->Settings();
|
||||||
|
ASSERT(settings);
|
||||||
|
settings->SetSyncPosition(syncTime);
|
||||||
|
settings->WriteSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CatchUpManager::CatchUpManager(const BVolume& volume)
|
||||||
|
:
|
||||||
|
fVolume(volume)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CatchUpManager::~CatchUpManager()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++)
|
||||||
|
delete fFileAnalyserQueue.ItemAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpManager::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
CatchUpAnalyser* analyser;
|
||||||
|
switch (message->what) {
|
||||||
|
case kCatchUpDone:
|
||||||
|
message->AddPointer("Analyser", &analyser);
|
||||||
|
fCatchUpAnalyserList.RemoveItem(analyser);
|
||||||
|
analyser->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CatchUpManager::AddAnalyser(const FileAnalyser* analyserOrg)
|
||||||
|
{
|
||||||
|
IndexServer* server = (IndexServer*)be_app;
|
||||||
|
FileAnalyser* analyser = server->CreateFileAnalyser(analyserOrg->Name(),
|
||||||
|
fVolume);
|
||||||
|
if (!analyser)
|
||||||
|
return false;
|
||||||
|
ASSERT(analyserOrg->Settings());
|
||||||
|
analyser->SetSettings(analyserOrg->Settings());
|
||||||
|
|
||||||
|
bool status = fFileAnalyserQueue.AddItem(analyser);
|
||||||
|
if (!status)
|
||||||
|
delete analyser;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpManager::RemoveAnalyser(const BString& name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
|
||||||
|
FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
|
||||||
|
if (analyser->Name() == name) {
|
||||||
|
fFileAnalyserQueue.RemoveItem(analyser);
|
||||||
|
delete analyser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fCatchUpAnalyserList.CountItems(); i++)
|
||||||
|
fCatchUpAnalyserList.ItemAt(i)->RemoveAnalyser(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CatchUpManager::CatchUp()
|
||||||
|
{
|
||||||
|
STRACE("CatchUpManager::CatchUp()\n");
|
||||||
|
bigtime_t startBig = real_time_clock_usecs();
|
||||||
|
bigtime_t endBig = 0;
|
||||||
|
for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
|
||||||
|
FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
|
||||||
|
analyser->UpdateSettingsCache();
|
||||||
|
const analyser_settings& settings = analyser->CachedSettings();
|
||||||
|
STRACE("%s, %i, %i\n", analyser->Name().String(),
|
||||||
|
(int)settings.syncPosition, (int)settings.watchingStart);
|
||||||
|
if (settings.syncPosition < startBig)
|
||||||
|
startBig = settings.syncPosition;
|
||||||
|
if (settings.watchingStart > endBig)
|
||||||
|
endBig = settings.watchingStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
CatchUpAnalyser* catchUpAnalyser = new CatchUpAnalyser(fVolume,
|
||||||
|
startBig / kSecond, endBig / kSecond, this);
|
||||||
|
if (!catchUpAnalyser)
|
||||||
|
return false;
|
||||||
|
if (!fCatchUpAnalyserList.AddItem(catchUpAnalyser)) {
|
||||||
|
delete catchUpAnalyser;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fFileAnalyserQueue.CountItems(); i++) {
|
||||||
|
FileAnalyser* analyser = fFileAnalyserQueue.ItemAt(i);
|
||||||
|
// if AddAnalyser fails at least don't leak
|
||||||
|
if (!catchUpAnalyser->AddAnalyser(analyser))
|
||||||
|
delete analyser;
|
||||||
|
|
||||||
|
}
|
||||||
|
fFileAnalyserQueue.MakeEmpty();
|
||||||
|
|
||||||
|
catchUpAnalyser->StartAnalysing();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CatchUpManager::Stop()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fCatchUpAnalyserList.CountItems(); i++) {
|
||||||
|
CatchUpAnalyser* catchUpAnalyser = fCatchUpAnalyserList.ItemAt(i);
|
||||||
|
catchUpAnalyser->Stop();
|
||||||
|
catchUpAnalyser->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
}
|
||||||
|
fCatchUpAnalyserList.MakeEmpty();
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef CATCH_UP_MANAGER_H
|
||||||
|
#define CATCH_UP_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "AnalyserDispatcher.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG_CATCH_UP
|
||||||
|
#ifdef DEBUG_CATCH_UP
|
||||||
|
#include <stdio.h>
|
||||||
|
# define STRACE(x...) printf(x)
|
||||||
|
#else
|
||||||
|
# define STRACE(x...) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class CatchUpAnalyser : public AnalyserDispatcher {
|
||||||
|
public:
|
||||||
|
CatchUpAnalyser(const BVolume& volume,
|
||||||
|
time_t start, time_t end,
|
||||||
|
BHandler* manager);
|
||||||
|
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
void StartAnalysing();
|
||||||
|
|
||||||
|
void AnalyseEntry(const entry_ref& ref);
|
||||||
|
|
||||||
|
const BVolume& Volume() { return fVolume; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _CatchUp();
|
||||||
|
void _WriteSyncSatus(bigtime_t syncTime);
|
||||||
|
|
||||||
|
BVolume fVolume;
|
||||||
|
time_t fStart;
|
||||||
|
time_t fEnd;
|
||||||
|
|
||||||
|
BHandler* fCatchUpManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef BObjectList<CatchUpAnalyser> CatchUpAnalyserList;
|
||||||
|
|
||||||
|
|
||||||
|
class CatchUpManager : public BHandler {
|
||||||
|
public:
|
||||||
|
CatchUpManager(const BVolume& volume);
|
||||||
|
~CatchUpManager();
|
||||||
|
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
|
||||||
|
//! Add analyser to the queue.
|
||||||
|
bool AddAnalyser(const FileAnalyser* analyser);
|
||||||
|
void RemoveAnalyser(const BString& name);
|
||||||
|
|
||||||
|
//! Spawn a CatchUpAnalyser and fill it with the analyser in the
|
||||||
|
//! queue
|
||||||
|
bool CatchUp();
|
||||||
|
//! Stop all catch up threads and put the analyser back into the
|
||||||
|
//! queue.
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BVolume fVolume;
|
||||||
|
|
||||||
|
FileAnalyserList fFileAnalyserQueue;
|
||||||
|
CatchUpAnalyserList fCatchUpAnalyserList;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IndexServer.h"
|
||||||
|
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <driver_settings.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
|
||||||
|
VolumeObserverHandler::VolumeObserverHandler(IndexServer* indexServer)
|
||||||
|
:
|
||||||
|
fIndexServer(indexServer)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeObserverHandler::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
if (message->what != B_NODE_MONITOR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_t device;
|
||||||
|
int32 opcode;
|
||||||
|
message->FindInt32("opcode", &opcode) ;
|
||||||
|
switch (opcode) {
|
||||||
|
case B_DEVICE_MOUNTED :
|
||||||
|
message->FindInt32("new device", &device);
|
||||||
|
fIndexServer->AddVolume(BVolume(device));
|
||||||
|
break ;
|
||||||
|
|
||||||
|
case B_DEVICE_UNMOUNTED :
|
||||||
|
message->FindInt32("device", &device);
|
||||||
|
fIndexServer->RemoveVolume(BVolume(device));
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AnalyserMonitorHandler::AnalyserMonitorHandler(IndexServer* indexServer)
|
||||||
|
:
|
||||||
|
fIndexServer(indexServer)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserMonitorHandler::AddOnEnabled(const add_on_entry_info* entryInfo)
|
||||||
|
{
|
||||||
|
entry_ref ref;
|
||||||
|
make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
|
||||||
|
entryInfo->name, &ref);
|
||||||
|
fIndexServer->RegisterAddOn(ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserMonitorHandler::AddOnDisabled(const add_on_entry_info* entryInfo)
|
||||||
|
{
|
||||||
|
entry_ref ref;
|
||||||
|
make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node,
|
||||||
|
entryInfo->name, &ref);
|
||||||
|
fIndexServer->UnregisterAddOn(ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
IndexServer::IndexServer()
|
||||||
|
:
|
||||||
|
BApplication("application/x-vnd.Haiku-index_server"),
|
||||||
|
|
||||||
|
fVolumeObserverHandler(this),
|
||||||
|
fAddOnMonitorHandler(this),
|
||||||
|
fPulseRunner(NULL)
|
||||||
|
{
|
||||||
|
AddHandler(&fVolumeObserverHandler);
|
||||||
|
AddHandler(&fAddOnMonitorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndexServer::~IndexServer()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fAddOnList.CountItems(); i++) {
|
||||||
|
IndexServerAddOn* addon = fAddOnList.ItemAt(i);
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
|
||||||
|
fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
|
||||||
|
image_id image = addon->ImageId();
|
||||||
|
delete addon;
|
||||||
|
unload_add_on(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
_StopWatchingVolumes();
|
||||||
|
|
||||||
|
delete fPulseRunner;
|
||||||
|
|
||||||
|
RemoveHandler(&fVolumeObserverHandler);
|
||||||
|
RemoveHandler(&fAddOnMonitorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::ReadyToRun()
|
||||||
|
{
|
||||||
|
_StartWatchingAddOns();
|
||||||
|
_StartWatchingVolumes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
BApplication::MessageReceived(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
IndexServer::QuitRequested()
|
||||||
|
{
|
||||||
|
_StopWatchingVolumes();
|
||||||
|
return BApplication::QuitRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::AddVolume(const BVolume& volume)
|
||||||
|
{
|
||||||
|
// ignore volumes like / or /dev
|
||||||
|
if (volume.Capacity() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if volume is already in our list
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
|
||||||
|
VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
|
||||||
|
if (current->Volume() == volume)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[256];
|
||||||
|
volume.GetName(name);
|
||||||
|
STRACE("IndexServer::AddVolume %s\n", name);
|
||||||
|
|
||||||
|
VolumeWatcher* watcher = new VolumeWatcher(volume);
|
||||||
|
/* if (!watcher->Enabled()) {
|
||||||
|
delete watcher;
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
fVolumeWatcherList.AddItem(watcher);
|
||||||
|
_SetupVolumeWatcher(watcher);
|
||||||
|
watcher->StartWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::RemoveVolume(const BVolume& volume)
|
||||||
|
{
|
||||||
|
VolumeWatcher* watcher = NULL;
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
|
||||||
|
VolumeWatcher* current = fVolumeWatcherList.ItemAt(i);
|
||||||
|
if (current->Volume() == volume) {
|
||||||
|
watcher = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!watcher)
|
||||||
|
return;
|
||||||
|
|
||||||
|
watcher->Stop();
|
||||||
|
fVolumeWatcherList.RemoveItem(watcher);
|
||||||
|
watcher->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::RegisterAddOn(entry_ref ref)
|
||||||
|
{
|
||||||
|
STRACE("RegisterAddOn %s\n", ref.name);
|
||||||
|
|
||||||
|
BPath path(&ref);
|
||||||
|
image_id image = load_add_on(path.Path());
|
||||||
|
if (image < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
create_index_server_addon* createFunc;
|
||||||
|
|
||||||
|
// Get the instantiation function
|
||||||
|
status_t status = get_image_symbol(image, "instantiate_index_server_addon",
|
||||||
|
B_SYMBOL_TYPE_TEXT, (void**)&createFunc);
|
||||||
|
if (status != B_OK) {
|
||||||
|
unload_add_on(image);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexServerAddOn* addon = createFunc(image, ref.name);
|
||||||
|
if (!addon) {
|
||||||
|
unload_add_on(image);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fAddOnList.AddItem(addon)) {
|
||||||
|
unload_add_on(image);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
|
||||||
|
VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
|
||||||
|
FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
|
||||||
|
if (!analyser)
|
||||||
|
continue;
|
||||||
|
if (!watcher->AddAnalyser(analyser))
|
||||||
|
delete analyser;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::UnregisterAddOn(entry_ref ref)
|
||||||
|
{
|
||||||
|
IndexServerAddOn* addon = _FindAddon(ref.name);
|
||||||
|
if (!addon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++)
|
||||||
|
fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name());
|
||||||
|
|
||||||
|
fAddOnList.RemoveItem(addon);
|
||||||
|
unload_add_on(addon->ImageId());
|
||||||
|
delete addon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileAnalyser*
|
||||||
|
IndexServer::CreateFileAnalyser(const BString& name, const BVolume& volume)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
IndexServerAddOn* addon = _FindAddon(name);
|
||||||
|
if (!addon) {
|
||||||
|
Unlock();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
|
||||||
|
Unlock();
|
||||||
|
return analyser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::_StartWatchingVolumes()
|
||||||
|
{
|
||||||
|
BVolume volume;
|
||||||
|
while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE)
|
||||||
|
AddVolume(volume);
|
||||||
|
fVolumeRoster.StartWatching(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::_StopWatchingVolumes()
|
||||||
|
{
|
||||||
|
STRACE("_StopWatchingVolumes\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) {
|
||||||
|
VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i);
|
||||||
|
watcher->Stop();
|
||||||
|
watcher->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
}
|
||||||
|
fVolumeWatcherList.MakeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::_SetupVolumeWatcher(VolumeWatcher* watcher)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fAddOnList.CountItems(); i++) {
|
||||||
|
IndexServerAddOn* addon = fAddOnList.ItemAt(i);
|
||||||
|
FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume());
|
||||||
|
if (!analyser)
|
||||||
|
continue;
|
||||||
|
if (!watcher->AddAnalyser(analyser))
|
||||||
|
delete analyser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileAnalyser*
|
||||||
|
IndexServer::_SetupFileAnalyser(IndexServerAddOn* addon, const BVolume& volume)
|
||||||
|
{
|
||||||
|
FileAnalyser* analyser = addon->CreateFileAnalyser(volume);
|
||||||
|
if (!analyser)
|
||||||
|
return NULL;
|
||||||
|
AnalyserSettings* settings = new AnalyserSettings(analyser->Name(),
|
||||||
|
analyser->Volume());
|
||||||
|
BReference<AnalyserSettings> settingsRef(settings, true);
|
||||||
|
if (!settings) {
|
||||||
|
delete analyser;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
analyser->SetSettings(settings);
|
||||||
|
return analyser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
IndexServer::_StartWatchingAddOns()
|
||||||
|
{
|
||||||
|
AddHandler(&fAddOnMonitorHandler);
|
||||||
|
BMessage pulse(B_PULSE);
|
||||||
|
fPulseRunner = new BMessageRunner(&fAddOnMonitorHandler, &pulse, 1000000LL);
|
||||||
|
// the monitor handler needs a pulse to check if add-ons are ready
|
||||||
|
|
||||||
|
char parameter[32];
|
||||||
|
size_t parameterLength = sizeof(parameter);
|
||||||
|
bool safeMode = false;
|
||||||
|
if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter,
|
||||||
|
¶meterLength) == B_OK) {
|
||||||
|
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
|
||||||
|
|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
|
||||||
|
|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1"))
|
||||||
|
safeMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load dormant media nodes
|
||||||
|
const directory_which directories[] = {
|
||||||
|
B_USER_ADDONS_DIRECTORY,
|
||||||
|
B_COMMON_ADDONS_DIRECTORY,
|
||||||
|
B_BEOS_ADDONS_DIRECTORY
|
||||||
|
};
|
||||||
|
|
||||||
|
// when safemode, only B_BEOS_ADDONS_DIRECTORY is used
|
||||||
|
for (uint32 i = safeMode ? 2 : 0;
|
||||||
|
i < sizeof(directories) / sizeof(directory_which); i++) {
|
||||||
|
BDirectory directory;
|
||||||
|
node_ref nodeRef;
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(directories[i], &path) == B_OK
|
||||||
|
&& path.Append("index_server") == B_OK
|
||||||
|
&& directory.SetTo(path.Path()) == B_OK
|
||||||
|
&& directory.GetNodeRef(&nodeRef) == B_OK)
|
||||||
|
fAddOnMonitorHandler.AddDirectory(&nodeRef, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndexServerAddOn*
|
||||||
|
IndexServer::_FindAddon(const BString& name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fAddOnList.CountItems(); i++) {
|
||||||
|
IndexServerAddOn* current = fAddOnList.ItemAt(i);
|
||||||
|
if (current->Name() == name)
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef INDEX_SERVER_H
|
||||||
|
#define INDEX_SERVER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <MessageRunner.h>
|
||||||
|
#include <VolumeRoster.h>
|
||||||
|
|
||||||
|
#include <AddOnMonitorHandler.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "IndexServerAddOn.h"
|
||||||
|
#include "VolumeWatcher.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG_INDEX_SERVER
|
||||||
|
#ifdef DEBUG_INDEX_SERVER
|
||||||
|
#include <stdio.h>
|
||||||
|
# define STRACE(x...) printf(x)
|
||||||
|
#else
|
||||||
|
# define STRACE(x...) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class IndexServer;
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeObserverHandler : public BHandler {
|
||||||
|
public:
|
||||||
|
VolumeObserverHandler(IndexServer* indexServer);
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
private:
|
||||||
|
IndexServer* fIndexServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AnalyserMonitorHandler : public AddOnMonitorHandler {
|
||||||
|
public:
|
||||||
|
AnalyserMonitorHandler(
|
||||||
|
IndexServer* indexServer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AddOnEnabled(
|
||||||
|
const add_on_entry_info* entryInfo);
|
||||||
|
void AddOnDisabled(
|
||||||
|
const add_on_entry_info* entryInfo);
|
||||||
|
|
||||||
|
IndexServer* fIndexServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class IndexServer : public BApplication {
|
||||||
|
public:
|
||||||
|
IndexServer();
|
||||||
|
virtual ~IndexServer();
|
||||||
|
|
||||||
|
virtual void ReadyToRun();
|
||||||
|
virtual void MessageReceived(BMessage *message);
|
||||||
|
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
void AddVolume(const BVolume& volume);
|
||||||
|
void RemoveVolume(const BVolume& volume);
|
||||||
|
|
||||||
|
void RegisterAddOn(entry_ref ref);
|
||||||
|
void UnregisterAddOn(entry_ref ref);
|
||||||
|
|
||||||
|
//! thread safe
|
||||||
|
FileAnalyser* CreateFileAnalyser(const BString& name,
|
||||||
|
const BVolume& volume);
|
||||||
|
private:
|
||||||
|
void _StartWatchingVolumes();
|
||||||
|
void _StopWatchingVolumes();
|
||||||
|
|
||||||
|
void _SetupVolumeWatcher(VolumeWatcher* watcher);
|
||||||
|
FileAnalyser* _SetupFileAnalyser(IndexServerAddOn* addon,
|
||||||
|
const BVolume& volume);
|
||||||
|
void _StartWatchingAddOns();
|
||||||
|
|
||||||
|
inline IndexServerAddOn* _FindAddon(const BString& name);
|
||||||
|
|
||||||
|
BVolumeRoster fVolumeRoster;
|
||||||
|
BObjectList<VolumeWatcher> fVolumeWatcherList;
|
||||||
|
BObjectList<IndexServerAddOn> fAddOnList;
|
||||||
|
|
||||||
|
VolumeObserverHandler fVolumeObserverHandler;
|
||||||
|
|
||||||
|
AnalyserMonitorHandler fAddOnMonitorHandler;
|
||||||
|
BMessageRunner* fPulseRunner;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
SubDir HAIKU_TOP src servers index_server ;
|
||||||
|
|
||||||
|
AddResources index_server : index_server.rdef ;
|
||||||
|
|
||||||
|
UsePrivateHeaders index_server shared storage kernel app ;
|
||||||
|
UsePrivateSystemHeaders ;
|
||||||
|
|
||||||
|
Server index_server :
|
||||||
|
CatchUpManager.cpp
|
||||||
|
main.cpp
|
||||||
|
IndexServer.cpp
|
||||||
|
IndexServerAddOn.cpp
|
||||||
|
ModifiedNotifications.cpp
|
||||||
|
VolumeWatcher.cpp
|
||||||
|
|
||||||
|
# storage
|
||||||
|
AddOnMonitorHandler.cpp
|
||||||
|
NodeMonitorHandler.cpp
|
||||||
|
:
|
||||||
|
be
|
||||||
|
$(TARGET_LIBSTDC++)
|
||||||
|
;
|
||||||
|
|
||||||
|
SEARCH on [ FGristFiles AddOnMonitorHandler.cpp NodeMonitorHandler.cpp ]
|
||||||
|
+= [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) kits storage ] ;
|
||||||
|
|
||||||
|
SEARCH on [ FGristFiles IndexServerAddOn.cpp ]
|
||||||
|
+= [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) add-ons index_server ] ;
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ModifiedNotifications.h"
|
||||||
|
|
||||||
|
#include "fs_query.h"
|
||||||
|
|
||||||
|
#include <MessengerPrivate.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
#include "query_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
NotifyAllQuery::NotifyAllQuery()
|
||||||
|
:
|
||||||
|
fQueryFd(-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotifyAllQuery::~NotifyAllQuery()
|
||||||
|
{
|
||||||
|
StopWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotifyAllQuery::StartWatching(const BVolume& volume, const char* query,
|
||||||
|
const BMessenger& target)
|
||||||
|
{
|
||||||
|
if (fQueryFd >= 0)
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
BMessenger::Private messengerPrivate(const_cast<BMessenger&>(target));
|
||||||
|
port_id port = messengerPrivate.Port();
|
||||||
|
long token = (messengerPrivate.IsPreferredTarget() ? -1
|
||||||
|
: messengerPrivate.Token());
|
||||||
|
|
||||||
|
fQueryFd = _kern_open_query(volume.Device(), query, strlen(query),
|
||||||
|
B_LIVE_QUERY | B_ATTR_CHANGE_NOTIFICATION, port, token);
|
||||||
|
if (fQueryFd < 0)
|
||||||
|
return fQueryFd;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NotifyAllQuery::StopWatching()
|
||||||
|
{
|
||||||
|
status_t error = B_OK;
|
||||||
|
if (fQueryFd >= 0) {
|
||||||
|
error = _kern_close(fQueryFd);
|
||||||
|
fQueryFd = -1;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ModfiedNotifications::~ModfiedNotifications()
|
||||||
|
{
|
||||||
|
StopWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ModfiedNotifications::StartWatching(const BVolume& volume, time_t startTime,
|
||||||
|
const BMessenger& target)
|
||||||
|
{
|
||||||
|
BString string = "(last_modified>=";
|
||||||
|
string << startTime;
|
||||||
|
string << ")";
|
||||||
|
return fQuery.StartWatching(volume, string.String(), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ModfiedNotifications::StopWatching()
|
||||||
|
{
|
||||||
|
return fQuery.StopWatching();
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef MODIFIED_NOTIFICATIONS_H
|
||||||
|
#define MODIFIED_NOTIFICATIONS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
#include <Volume.h>
|
||||||
|
#include <Messenger.h>
|
||||||
|
|
||||||
|
|
||||||
|
class NotifyAllQuery {
|
||||||
|
public:
|
||||||
|
NotifyAllQuery();
|
||||||
|
~NotifyAllQuery();
|
||||||
|
|
||||||
|
status_t StartWatching(const BVolume& volume,
|
||||||
|
const char* query,
|
||||||
|
const BMessenger& target);
|
||||||
|
status_t StopWatching();
|
||||||
|
private:
|
||||||
|
int fQueryFd;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ModfiedNotifications {
|
||||||
|
public:
|
||||||
|
~ModfiedNotifications();
|
||||||
|
|
||||||
|
status_t StartWatching(const BVolume& volume,
|
||||||
|
time_t startTime, const BMessenger& target);
|
||||||
|
status_t StopWatching();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NotifyAllQuery fQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MODIFIED_NOTIFICATIONS_H
|
||||||
@@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "VolumeWatcher.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <NodeMonitor.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <VolumeRoster.h>
|
||||||
|
#include <Query.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "IndexServerPrivate.h"
|
||||||
|
|
||||||
|
|
||||||
|
const bigtime_t kSecond = 1000000;
|
||||||
|
|
||||||
|
|
||||||
|
WatchNameHandler::WatchNameHandler(VolumeWatcher* volumeWatcher)
|
||||||
|
:
|
||||||
|
fVolumeWatcher(volumeWatcher)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WatchNameHandler::EntryCreated(const char *name, ino_t directory, dev_t device,
|
||||||
|
ino_t node)
|
||||||
|
{
|
||||||
|
entry_ref ref(device, directory, name);
|
||||||
|
fVolumeWatcher->fCreatedList.CurrentList()->push_back(ref);
|
||||||
|
fVolumeWatcher->_NewEntriesArrived();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WatchNameHandler::EntryRemoved(const char *name, ino_t directory, dev_t device,
|
||||||
|
ino_t node)
|
||||||
|
{
|
||||||
|
entry_ref ref(device, directory, name);
|
||||||
|
fVolumeWatcher->fDeleteList.CurrentList()->push_back(ref);
|
||||||
|
fVolumeWatcher->_NewEntriesArrived();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WatchNameHandler::EntryMoved(const char *name, const char *fromName,
|
||||||
|
ino_t from_directory, ino_t to_directory, dev_t device, ino_t node,
|
||||||
|
dev_t nodeDevice)
|
||||||
|
{
|
||||||
|
entry_ref ref(device, to_directory, name);
|
||||||
|
entry_ref refFrom(device, from_directory, fromName);
|
||||||
|
|
||||||
|
fVolumeWatcher->fMovedList.CurrentList()->push_back(ref);
|
||||||
|
fVolumeWatcher->fMovedFromList.CurrentList()->push_back(refFrom);
|
||||||
|
fVolumeWatcher->_NewEntriesArrived();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WatchNameHandler::StatChanged(ino_t node, dev_t device, int32 statFields)
|
||||||
|
{
|
||||||
|
if ((statFields & B_STAT_MODIFICATION_TIME) == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AnalyserDispatcher::AnalyserDispatcher()
|
||||||
|
:
|
||||||
|
BLooper(NULL, B_LOW_PRIORITY),
|
||||||
|
|
||||||
|
fStopped(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AnalyserDispatcher::~AnalyserDispatcher()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
delete fFileAnalyserList.ItemAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::Stop()
|
||||||
|
{
|
||||||
|
atomic_set(&fStopped, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
AnalyserDispatcher::Stopped()
|
||||||
|
{
|
||||||
|
return (atomic_get(&fStopped) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::AnalyseEntry(const entry_ref& ref)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->AnalyseEntry(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::DeleteEntry(const entry_ref& ref)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->DeleteEntry(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::MoveEntry(const entry_ref& oldRef, const entry_ref& newRef)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->MoveEntry(oldRef, newRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::LastEntry()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->LastEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
AnalyserDispatcher::AddAnalyser(FileAnalyser* analyser)
|
||||||
|
{
|
||||||
|
if (analyser == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result;
|
||||||
|
Lock();
|
||||||
|
if (_FindAnalyser(analyser->Name())) {
|
||||||
|
Unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result = fFileAnalyserList.AddItem(analyser);
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
AnalyserDispatcher::RemoveAnalyser(const BString& name)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
FileAnalyser* analyser = _FindAnalyser(name);
|
||||||
|
if (analyser) {
|
||||||
|
fFileAnalyserList.RemoveItem(analyser);
|
||||||
|
delete analyser;
|
||||||
|
Unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileAnalyser*
|
||||||
|
AnalyserDispatcher::_FindAnalyser(const BString& name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++) {
|
||||||
|
FileAnalyser* analyser = fFileAnalyserList.ItemAt(i);
|
||||||
|
if (analyser->Name() == name)
|
||||||
|
return analyser;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::WriteAnalyserSettings()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->Settings()->WriteSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::SetSyncPosition(bigtime_t time)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->Settings()->SetSyncPosition(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::SetWatchingStart(bigtime_t time)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->Settings()->SetWatchingStart(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AnalyserDispatcher::SetWatchingPosition(bigtime_t time)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fFileAnalyserList.CountItems(); i++)
|
||||||
|
fFileAnalyserList.ItemAt(i)->Settings()->SetWatchingPosition(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VolumeWorker::VolumeWorker(VolumeWatcher* watcher)
|
||||||
|
:
|
||||||
|
fVolumeWatcher(watcher),
|
||||||
|
fBusy(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWorker::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kTriggerWork:
|
||||||
|
_Work();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLooper::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWorker::IsBusy()
|
||||||
|
{
|
||||||
|
return (atomic_get(&fBusy) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWorker::_Work()
|
||||||
|
{
|
||||||
|
list_collection collection;
|
||||||
|
fVolumeWatcher->GetSecureEntries(collection);
|
||||||
|
|
||||||
|
if (collection.createdList->size() == 0
|
||||||
|
&& collection.deletedList->size() == 0
|
||||||
|
&& collection.modifiedList->size() == 0
|
||||||
|
&& collection.movedList->size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_SetBusy(true);
|
||||||
|
for (unsigned int i = 0; i < collection.createdList->size() || Stopped();
|
||||||
|
i++)
|
||||||
|
AnalyseEntry(collection.createdList->at(i));
|
||||||
|
collection.createdList->clear();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < collection.modifiedList->size() || Stopped();
|
||||||
|
i++)
|
||||||
|
AnalyseEntry(collection.modifiedList->at(i));
|
||||||
|
collection.modifiedList->clear();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < collection.createdList->size() || Stopped();
|
||||||
|
i++)
|
||||||
|
AnalyseEntry(collection.createdList->at(i));
|
||||||
|
collection.createdList->clear();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < collection.movedList->size() || Stopped();
|
||||||
|
i++)
|
||||||
|
MoveEntry(collection.movedFromList->at(i), collection.movedList->at(i));
|
||||||
|
collection.movedList->clear();
|
||||||
|
collection.movedFromList->clear();
|
||||||
|
|
||||||
|
LastEntry();
|
||||||
|
PostMessage(kTriggerWork);
|
||||||
|
|
||||||
|
_SetBusy(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWorker::_SetBusy(bool busy)
|
||||||
|
{
|
||||||
|
if (busy)
|
||||||
|
atomic_set(&fBusy, 1);
|
||||||
|
else
|
||||||
|
atomic_set(&fBusy, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VolumeWatcherBase::VolumeWatcherBase(const BVolume& volume)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fEnabled(true),
|
||||||
|
fLastUpdated(0)
|
||||||
|
{
|
||||||
|
ReadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* kEnabledAttr = "Enabled";
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcherBase::ReadSettings()
|
||||||
|
{
|
||||||
|
// TODO remove this
|
||||||
|
BVolume bootVolume;
|
||||||
|
BVolumeRoster roster;
|
||||||
|
roster.GetBootVolume(&bootVolume);
|
||||||
|
if (bootVolume == fVolume) {
|
||||||
|
fEnabled = true;
|
||||||
|
WriteSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
BDirectory rootDir;
|
||||||
|
fVolume.GetRootDirectory(&rootDir);
|
||||||
|
BPath path(&rootDir);
|
||||||
|
path.Append(kIndexServerDirectory);
|
||||||
|
path.Append(kVolumeStatusFileName);
|
||||||
|
BFile file(path.Path(), B_READ_ONLY);
|
||||||
|
if (file.InitCheck() != B_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 enabled;
|
||||||
|
file.WriteAttr(kEnabledAttr, B_UINT32_TYPE, 0, &enabled, sizeof(uint32));
|
||||||
|
fEnabled = enabled == 0 ? false : true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcherBase::WriteSettings()
|
||||||
|
{
|
||||||
|
BDirectory rootDir;
|
||||||
|
fVolume.GetRootDirectory(&rootDir);
|
||||||
|
BPath path(&rootDir);
|
||||||
|
path.Append(kIndexServerDirectory);
|
||||||
|
if (create_directory(path.Path(), 777) != B_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path.Append(kVolumeStatusFileName);
|
||||||
|
BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
|
||||||
|
if (file.InitCheck() != B_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 enabled = fEnabled ? 1 : 0;
|
||||||
|
file.WriteAttr(kEnabledAttr, B_UINT32_TYPE, 0, &enabled, sizeof(uint32));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SwapEntryRefVector::SwapEntryRefVector()
|
||||||
|
{
|
||||||
|
fCurrentList = &fFirstList;
|
||||||
|
fNextList = &fSecondList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EntryRefVector*
|
||||||
|
SwapEntryRefVector::SwapList()
|
||||||
|
{
|
||||||
|
EntryRefVector* temp = fCurrentList;
|
||||||
|
fCurrentList = fNextList;
|
||||||
|
fNextList = temp;
|
||||||
|
return fCurrentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EntryRefVector*
|
||||||
|
SwapEntryRefVector::CurrentList()
|
||||||
|
{
|
||||||
|
return fCurrentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VolumeWatcher::VolumeWatcher(const BVolume& volume)
|
||||||
|
:
|
||||||
|
VolumeWatcherBase(volume),
|
||||||
|
|
||||||
|
fWatching(false),
|
||||||
|
fWatchNameHandler(this),
|
||||||
|
fCatchUpManager(volume)
|
||||||
|
{
|
||||||
|
AddHandler(&fWatchNameHandler);
|
||||||
|
|
||||||
|
fVolumeWorker = new VolumeWorker(this);
|
||||||
|
fVolumeWorker->Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VolumeWatcher::~VolumeWatcher()
|
||||||
|
{
|
||||||
|
printf("~VolumeWatcher()\n");
|
||||||
|
Stop();
|
||||||
|
thread_id threadId = fVolumeWorker->Thread();
|
||||||
|
fVolumeWorker->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
status_t error;
|
||||||
|
wait_for_thread(threadId, &error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWatcher::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
int32 opcode;
|
||||||
|
switch (message->what) {
|
||||||
|
case B_QUERY_UPDATE:
|
||||||
|
message->FindInt32("opcode", &opcode);
|
||||||
|
if (opcode == B_ATTR_CHANGED || opcode == B_ENTRY_CREATED) {
|
||||||
|
const char *name;
|
||||||
|
ino_t directory;
|
||||||
|
dev_t device;
|
||||||
|
if ((message->FindString("name", &name) != B_OK) ||
|
||||||
|
(message->FindInt64("directory", &directory) != B_OK) ||
|
||||||
|
(message->FindInt32("device", &device) != B_OK))
|
||||||
|
break;
|
||||||
|
entry_ref ref(device, directory, name);
|
||||||
|
fModifiedList.CurrentList()->push_back(ref);
|
||||||
|
_NewEntriesArrived();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLooper::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcher::StartWatching()
|
||||||
|
{
|
||||||
|
Run();
|
||||||
|
|
||||||
|
watch_volume(fVolume.Device(), B_WATCH_NAME | B_WATCH_STAT,
|
||||||
|
&fWatchNameHandler);
|
||||||
|
if (fModfiedNotifications.StartWatching(fVolume.Device(), real_time_clock(),
|
||||||
|
this) != B_OK)
|
||||||
|
return false;
|
||||||
|
// set the time after start watching to not miss anything
|
||||||
|
fVolumeWorker->SetWatchingStart(real_time_clock_usecs());
|
||||||
|
|
||||||
|
char name[255];
|
||||||
|
fVolume.GetName(name);
|
||||||
|
|
||||||
|
fCatchUpManager.CatchUp();
|
||||||
|
|
||||||
|
fWatching = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWatcher::Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
char name[255];
|
||||||
|
fVolume.GetName(name);
|
||||||
|
|
||||||
|
// set the time before stop watching to not miss anything
|
||||||
|
fVolumeWorker->SetWatchingPosition(real_time_clock_usecs());
|
||||||
|
|
||||||
|
stop_watching(&fWatchNameHandler);
|
||||||
|
|
||||||
|
fVolumeWorker->WriteAnalyserSettings();
|
||||||
|
|
||||||
|
// don't stop the work because we have to handle all entries after writing
|
||||||
|
// the watching position
|
||||||
|
//fVolumeWorker->Stop();
|
||||||
|
fCatchUpManager.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcher::AddAnalyser(FileAnalyser* analyser)
|
||||||
|
{
|
||||||
|
if (!fVolumeWorker->AddAnalyser(analyser))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Lock();
|
||||||
|
if (!fCatchUpManager.AddAnalyser(analyser)) {
|
||||||
|
Unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fWatching)
|
||||||
|
fCatchUpManager.CatchUp();
|
||||||
|
Unlock();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcher::RemoveAnalyser(const BString& name)
|
||||||
|
{
|
||||||
|
if (!fVolumeWorker->RemoveAnalyser(name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Lock();
|
||||||
|
fCatchUpManager.RemoveAnalyser(name);
|
||||||
|
Unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWatcher::GetSecureEntries(list_collection& collection)
|
||||||
|
{
|
||||||
|
collection.createdList = fCreatedList.SwapList();
|
||||||
|
collection.deletedList = fDeleteList.SwapList();
|
||||||
|
collection.modifiedList = fModifiedList.SwapList();
|
||||||
|
collection.movedList = fMovedList.SwapList();
|
||||||
|
collection.movedFromList = fMovedFromList.SwapList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VolumeWatcher::FindEntryRef(ino_t node, dev_t device, entry_ref& entry)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VolumeWatcher::_NewEntriesArrived()
|
||||||
|
{
|
||||||
|
// The fVolumeWorker has to exist as long as we live so directly post to
|
||||||
|
// the queue.
|
||||||
|
if (fVolumeWorker->IsBusy())
|
||||||
|
return;
|
||||||
|
fVolumeWorker->PostMessage(kTriggerWork);
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef VOLUME_WATCHER_H
|
||||||
|
#define VOLUME_WATCHER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Debug.h>
|
||||||
|
#include <Handler.h>
|
||||||
|
#include <NodeMonitorHandler.h>
|
||||||
|
#include <Volume.h>
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "AnalyserDispatcher.h"
|
||||||
|
#include "CatchUpManager.h"
|
||||||
|
#include "IndexServerAddOn.h"
|
||||||
|
#include "ModifiedNotifications.h"
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeWatcher;
|
||||||
|
|
||||||
|
|
||||||
|
class WatchNameHandler : public NodeMonitorHandler {
|
||||||
|
public:
|
||||||
|
WatchNameHandler(VolumeWatcher* volumeWatcher);
|
||||||
|
|
||||||
|
void EntryCreated(const char *name, ino_t directory,
|
||||||
|
dev_t device, ino_t node);
|
||||||
|
void EntryRemoved(const char *name, ino_t directory,
|
||||||
|
dev_t device, ino_t node);
|
||||||
|
void EntryMoved(const char *name,
|
||||||
|
const char *fromName, ino_t from_directory,
|
||||||
|
ino_t to_directory, dev_t device,
|
||||||
|
ino_t node, dev_t nodeDevice);
|
||||||
|
void StatChanged(ino_t node, dev_t device,
|
||||||
|
int32 statFields);
|
||||||
|
private:
|
||||||
|
VolumeWatcher* fVolumeWatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::vector<entry_ref> EntryRefVector;
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeWatcher;
|
||||||
|
|
||||||
|
|
||||||
|
const uint32 kTriggerWork = '&twk'; // what a bad message
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeWorker : public AnalyserDispatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VolumeWorker(VolumeWatcher* watcher);
|
||||||
|
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
|
||||||
|
bool IsBusy();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Work();
|
||||||
|
|
||||||
|
void _SetBusy(bool busy = true);
|
||||||
|
|
||||||
|
VolumeWatcher* fVolumeWatcher;
|
||||||
|
vint32 fBusy;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeWatcherBase {
|
||||||
|
public:
|
||||||
|
VolumeWatcherBase(const BVolume& volume);
|
||||||
|
|
||||||
|
const BVolume& Volume() { return fVolume; }
|
||||||
|
|
||||||
|
bool Enabled() { return fEnabled; }
|
||||||
|
bigtime_t GetLastUpdated() { return fLastUpdated; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ReadSettings();
|
||||||
|
bool WriteSettings();
|
||||||
|
|
||||||
|
BVolume fVolume;
|
||||||
|
|
||||||
|
bool fEnabled;
|
||||||
|
|
||||||
|
bigtime_t fLastUpdated;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*! Used to thread safe exchange refs. While the watcher thread file the current
|
||||||
|
list the worker thread can handle the second list. The worker thread gets his entries by calling SwapList while holding the watcher thread lock. */
|
||||||
|
class SwapEntryRefVector {
|
||||||
|
public:
|
||||||
|
SwapEntryRefVector();
|
||||||
|
|
||||||
|
EntryRefVector* SwapList();
|
||||||
|
EntryRefVector* CurrentList();
|
||||||
|
private:
|
||||||
|
EntryRefVector fFirstList;
|
||||||
|
EntryRefVector fSecondList;
|
||||||
|
EntryRefVector* fCurrentList;
|
||||||
|
EntryRefVector* fNextList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct list_collection
|
||||||
|
{
|
||||||
|
EntryRefVector* createdList;
|
||||||
|
EntryRefVector* deletedList;
|
||||||
|
EntryRefVector* modifiedList;
|
||||||
|
EntryRefVector* movedList;
|
||||||
|
EntryRefVector* movedFromList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*! Watch a volume and delegate changed entries to a VolumeWorker. */
|
||||||
|
class VolumeWatcher : public VolumeWatcherBase, public BLooper {
|
||||||
|
public:
|
||||||
|
VolumeWatcher(const BVolume& volume);
|
||||||
|
~VolumeWatcher();
|
||||||
|
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
bool StartWatching();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
//! thread safe
|
||||||
|
bool AddAnalyser(FileAnalyser* analyser);
|
||||||
|
bool RemoveAnalyser(const BString& name);
|
||||||
|
|
||||||
|
void GetSecureEntries(list_collection& collection);
|
||||||
|
|
||||||
|
bool FindEntryRef(ino_t node, dev_t device,
|
||||||
|
entry_ref& entry);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class WatchNameHandler;
|
||||||
|
|
||||||
|
void _NewEntriesArrived();
|
||||||
|
|
||||||
|
bool fWatching;
|
||||||
|
|
||||||
|
WatchNameHandler fWatchNameHandler;
|
||||||
|
|
||||||
|
SwapEntryRefVector fCreatedList;
|
||||||
|
SwapEntryRefVector fDeleteList;
|
||||||
|
SwapEntryRefVector fModifiedList;
|
||||||
|
SwapEntryRefVector fMovedList;
|
||||||
|
SwapEntryRefVector fMovedFromList;
|
||||||
|
|
||||||
|
VolumeWorker* fVolumeWorker;
|
||||||
|
CatchUpManager fCatchUpManager;
|
||||||
|
ModfiedNotifications fModfiedNotifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
resource app_signature "application/x-vnd.Haiku-index_server";
|
||||||
|
|
||||||
|
resource app_version {
|
||||||
|
major = 1,
|
||||||
|
middle = 0,
|
||||||
|
minor = 0,
|
||||||
|
|
||||||
|
variety = B_APPV_FINAL,
|
||||||
|
internal = 0,
|
||||||
|
|
||||||
|
short_info = "Index Server",
|
||||||
|
long_info = "Index Server ©2010 Haiku, Inc."
|
||||||
|
};
|
||||||
|
|
||||||
|
resource app_flags B_SINGLE_LAUNCH;
|
||||||
|
|
||||||
|
resource vector_icon {
|
||||||
|
$"6E6369660B05000400540510057802001604378852378852378852B788524B07"
|
||||||
|
$"8548705100883FFFBF88FF88020016033B1FD73CCE7EBF7EBC3DE4084BE51A48"
|
||||||
|
$"106D58E700FDFFFF020106023C80000000000000003A00004940004A800000CE"
|
||||||
|
$"CEFFFF9898FF03666698020006023E5400000000000000400000495800000000"
|
||||||
|
$"006464BAFFC7C7E005FF020006033D0000000000000000400000498000000000"
|
||||||
|
$"00D1D1EA964C4C76FF75759B0E0604FEC7E3BF763F603F60C62C605E4D5EC91C"
|
||||||
|
$"5EC2C7C7E3BF76CA3DC0D6C7E3BF760604FA503C533E5E305E30CC4DB8A05F2A"
|
||||||
|
$"602C5F2A0605EB035626582456264436513D5D2E5D2ECBFCB7AD5E256128CA9B"
|
||||||
|
$"B3E50604BF503B503B5239C66C34C73836C5A0324A334B324A3345370802C62C"
|
||||||
|
$"30C9E92702073B343B34B7D134204520BE002045204F204F20C977BDC360B7D1"
|
||||||
|
$"60C3B460564F56C977564F5645564556BE003B34C3B2343B3402053B363B36B8"
|
||||||
|
$"4136224522BE7022C50BBDC354B84254C34354C7B94554C50B54BE703B36C342"
|
||||||
|
$"363B3602053B3A3B3AC2603AC6214550BF5250C429BDC350C26150B923502645"
|
||||||
|
$"26C42926BF523B3AB9223A3B3A02053B4E3B4EC15C4EC52447C45F4BC45FC0F0"
|
||||||
|
$"3B40C15C40BA2840B66147B724C0F0B7244B3B4EBA274E3B4E0003B6A1C2E3B6"
|
||||||
|
$"A1C2E3B7DDC1B43BC0CBBAC9C0CBC0BAC0CBC4D7C2D6C399C1A8C4D7C2D60207"
|
||||||
|
$"3B3C3B3CB9933C284528BFC328C204B66147B641C248B724C0F03B40BA2740C1"
|
||||||
|
$"5C40C52447C45FC0F0C542C2484E454EC2044EBFC33B3CC1EF3C3B3C02023144"
|
||||||
|
$"2E43344535403841323F0203C230C23DC230C23DC171C316BE81C3B6C065C37C"
|
||||||
|
$"BE81C3B6C14BC395C04CC3EFC28FC32402073B543B54B8415422C1EC22C51F22"
|
||||||
|
$"C1EC22C58B22C58B22C8F23B5EB8425EC3435E54C58B54C8F254C58B54C1EC54"
|
||||||
|
$"C1EC54C51F3B54C342543B540B0A01020001000A020102000A040103000A0001"
|
||||||
|
$"05000A05020607000A060108000A0701091815FF01178200040A08010A000A09"
|
||||||
|
$"020B0C000A0301041001178320040A0A010D00"
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IndexServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
IndexServer indexServer;
|
||||||
|
indexServer.Run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user