* Revamped BPathMonitor API as suggested by Ingo - we could rename it to BNodeMonitor

and add wrappers for watch_node() as well, though.
* Implemented more or less all what is needed for the path monitoring to work.
* Added a test application: works fine under Haiku, but somewhat flaky under BeOS,
  dunno why yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21066 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-05-08 00:30:59 +00:00
parent 7f61f501cf
commit d00539e3ba
4 changed files with 752 additions and 221 deletions
+7 -11
View File
@@ -17,22 +17,18 @@
namespace BPrivate {
class PathHandler;
class BPathMonitor {
public:
BPathMonitor();
BPathMonitor(const char* path, uint32 flags, BMessenger target);
~BPathMonitor();
static status_t StartWatching(const char* path, uint32 flags, BMessenger target);
status_t InitCheck() const;
status_t SetTo(const char* path, uint32 flags, BMessenger target);
status_t SetTarget(BMessenger target);
void Unset();
static status_t StopWatching(const char* path, BMessenger target);
static status_t StopWatching(BMessenger target);
private:
PathHandler* fHandler;
status_t fStatus;
BPathMonitor();
~BPathMonitor();
static status_t _InitIfNeeded();
};
} // namespace BPrivate
+548 -210
View File
@@ -9,13 +9,19 @@
#include <PathMonitor.h>
#include <ObjectList.h>
#include <Application.h>
#include <Autolock.h>
#include <Directory.h>
#include <Entry.h>
#include <Handler.h>
#include <Locker.h>
#include <Looper.h>
#include <Path.h>
#include <String.h>
#include <map>
#include <set>
using namespace BPrivate;
@@ -24,10 +30,23 @@ using namespace std;
#define WATCH_NODE_FLAG_MASK 0x00ff
typedef set<node_ref> DirectorySet;
namespace BPrivate {
struct watched_directory {
node_ref node;
bool contained;
};
typedef set<watched_directory> DirectorySet;
typedef set<node_ref> FileSet;
class PathHandler;
typedef map<BString, PathHandler*> HandlerMap;
struct watcher {
HandlerMap handlers;
};
typedef map<BMessenger, watcher*> WatcherMap;
class PathHandler : public BHandler {
public:
PathHandler(const char* path, uint32 flags, BMessenger target);
@@ -38,15 +57,30 @@ class PathHandler : public BHandler {
void Quit();
virtual void MessageReceived(BMessage* message);
void Dump();
private:
status_t _GetClosest(const char* path, bool updatePath,
node_ref& nodeRef);
bool _WatchRecursively();
bool _WatchFilesOnly();
void _EntryCreated(BMessage* message);
void _EntryRemoved(BMessage* message);
void _EntryMoved(BMessage* message);
bool _IsContained(const node_ref& nodeRef) const;
bool _IsContained(BEntry& entry) const;
bool _HasDirectory(const node_ref& nodeRef) const;
bool _HasDirectory(const node_ref& nodeRef, bool* _contained = NULL) const;
bool _CloserToPath(BEntry& entry) const;
void _NotifyTarget(BMessage* message) const;
status_t _AddDirectory(BEntry& entry);
status_t _RemoveDirectory(const node_ref& nodeRef);
status_t _RemoveDirectory(BEntry& entry);
status_t _AddDirectory(node_ref& nodeRef);
status_t _RemoveDirectory(const node_ref& nodeRef, ino_t directoryNode);
status_t _RemoveDirectory(BEntry& entry, ino_t directoryNode);
bool _HasFile(const node_ref& nodeRef) const;
status_t _AddFile(BEntry& entry);
status_t _RemoveFile(const node_ref& nodeRef);
status_t _RemoveFile(BEntry& entry);
BPath fPath;
int32 fPathLength;
@@ -55,9 +89,12 @@ class PathHandler : public BHandler {
status_t fStatus;
bool fOwnsLooper;
DirectorySet fDirectories;
FileSet fFiles;
};
}
static WatcherMap sWatchers;
static BLocker* sLocker;
static status_t
@@ -87,51 +124,48 @@ operator<(const node_ref& a, const node_ref& b)
}
bool
operator<(const watched_directory& a, const watched_directory& b)
{
return a.node < b.node;
}
// #pragma mark -
PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target)
: BHandler(path),
fPath(path, NULL, true),
fTarget(target),
fFlags(flags),
fOwnsLooper(false)
{
fPathLength = strlen(fPath.Path());
BPath first(path);
node_ref nodeRef;
while (true) {
// try to find the first part of the path that exists
BDirectory directory;
fStatus = directory.SetTo(first.Path());
if (fStatus == B_OK) {
fStatus = directory.GetNodeRef(&nodeRef);
if (fStatus == B_OK)
break;
}
if (first.GetParent(&first) != B_OK) {
fStatus = B_ERROR;
break;
}
if (path == NULL || !path[0]) {
fStatus = B_BAD_VALUE;
return;
}
// TODO: support watching not-yet-mounted volumes as well!
node_ref nodeRef;
fStatus = _GetClosest(path, true, nodeRef);
if (fStatus < B_OK)
return;
BLooper* looper;
if (be_app != NULL) {
be_app->AddHandler(this);
looper = be_app;
} else {
// TODO: only have a single global looper!
BLooper* looper = new BLooper("PathMonitor looper");
looper = new BLooper("PathMonitor looper");
looper->Run();
looper->AddHandler(this);
fOwnsLooper = true;
}
fStatus = watch_node(&nodeRef, flags & WATCH_NODE_FLAG_MASK, this);
looper->Lock();
looper->AddHandler(this);
looper->Unlock();
fStatus = _AddDirectory(nodeRef);
}
@@ -147,13 +181,6 @@ PathHandler::InitCheck() const
}
void
PathHandler::SetTarget(BMessenger target)
{
fTarget = target;
}
void
PathHandler::Quit()
{
@@ -162,6 +189,237 @@ PathHandler::Quit()
}
void
PathHandler::Dump()
{
printf("WATCHING DIRECTORIES:\n");
DirectorySet::iterator i = fDirectories.begin();
for (; i != fDirectories.end(); i++) {
printf(" %ld:%Ld (%s)\n", i->node.device, i->node.node, i->contained ? "contained" : "-");
}
printf("WATCHING FILES:\n");
FileSet::iterator j = fFiles.begin();
for (; j != fFiles.end(); j++) {
printf(" %ld:%Ld\n", j->device, j->node);
}
}
status_t
PathHandler::_GetClosest(const char* path, bool updatePath, node_ref& nodeRef)
{
BPath first(path);
BString missing;
while (true) {
// try to find the first part of the path that exists
BDirectory directory;
status_t status = directory.SetTo(first.Path());
if (status == B_OK) {
status = directory.GetNodeRef(&nodeRef);
if (status == B_OK) {
if (updatePath) {
// normalize path
status = fPath.SetTo(&directory, NULL, true);
if (status == B_OK) {
fPath.Append(missing.String());
fPathLength = strlen(fPath.Path());
}
}
return status;
}
}
if (updatePath) {
if (missing.Length() > 0)
missing.Prepend("/");
missing.Prepend(first.Leaf());
}
if (first.GetParent(&first) != B_OK)
return B_ERROR;
}
}
bool
PathHandler::_WatchRecursively()
{
return (fFlags & B_WATCH_RECURSIVELY) != 0;
}
bool
PathHandler::_WatchFilesOnly()
{
return (fFlags & B_WATCH_FILES_ONLY) != 0;
}
void
PathHandler::_EntryCreated(BMessage* message)
{
const char* name;
node_ref nodeRef;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("directory", &nodeRef.node) != B_OK
|| message->FindString("name", &name) != B_OK)
return;
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
return;
bool parentContained = false;
bool entryContained = _IsContained(entry);
if (entryContained)
parentContained = _IsContained(nodeRef);
bool notify = entryContained;
if (entry.IsDirectory()) {
// ignore the directory if it's already known
if (entry.GetNodeRef(&nodeRef) == B_OK
&& _HasDirectory(nodeRef)) {
printf(" WE ALREADY HAVE DIR %s, %ld:%Ld\n",
name, nodeRef.device, nodeRef.node);
return;
}
// a new directory to watch for us
if (!entryContained && !_CloserToPath(entry)
|| parentContained && !_WatchRecursively()
|| _AddDirectory(entry) != B_OK
|| _WatchFilesOnly())
notify = parentContained;
} else if (entryContained) {
printf(" NEW ENTRY PARENT CONTAINED: %d\n", parentContained);
_AddFile(entry);
}
if (notify && entryContained) {
message->AddBool("added", true);
_NotifyTarget(message);
}
}
void
PathHandler::_EntryRemoved(BMessage* message)
{
node_ref nodeRef;
uint64 directoryNode;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("directory", (int64 *)&directoryNode) != B_OK
|| message->FindInt64("node", &nodeRef.node) != B_OK)
return;
bool notify = false;
if (_HasDirectory(nodeRef, &notify)) {
// the directory has been removed, so we remove it as well
_RemoveDirectory(nodeRef, directoryNode);
if (_WatchFilesOnly())
notify = false;
} else if (_HasFile(nodeRef)) {
_RemoveFile(nodeRef);
notify = true;
}
if (notify) {
message->AddBool("removed", true);
_NotifyTarget(message);
}
}
void
PathHandler::_EntryMoved(BMessage* message)
{
// has the entry been moved into a monitored directory or has
// it been removed from one?
const char* name;
node_ref nodeRef;
uint64 fromNode;
uint64 node;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("to directory", &nodeRef.node) != B_OK
|| message->FindInt64("from directory", (int64 *)&fromNode) != B_OK
|| message->FindInt64("node", (int64 *)&node) != B_OK
|| message->FindString("name", &name) != B_OK)
return;
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
return;
bool entryContained = _IsContained(entry);
bool wasAdded = false;
bool wasRemoved = false;
bool notify = false;
bool parentContained;
if (_HasDirectory(nodeRef, &parentContained)) {
// something has been added to our watched directories
nodeRef.node = node;
printf(" ADDED TO PARENT (%d), has entry %d/%d, entry %d %d\n",
parentContained, _HasDirectory(nodeRef), _HasFile(nodeRef),
entryContained, _CloserToPath(entry));
if (entry.IsDirectory()) {
if (!_HasDirectory(nodeRef)
&& (entryContained || _CloserToPath(entry))) {
// there is a new directory to watch for us
if (entryContained
|| parentContained && !_WatchRecursively())
_AddDirectory(entry);
else if (_GetClosest(fPath.Path(), false,
nodeRef) == B_OK) {
// the new directory might put us even
// closer to the path we are after
_AddDirectory(nodeRef);
}
wasAdded = true;
notify = entryContained;
}
if (_WatchFilesOnly())
notify = false;
} else if (!_HasFile(nodeRef) && entryContained) {
// file has been added
wasAdded = true;
notify = true;
_AddFile(entry);
}
} else {
// and entry has been removed from our directories
wasRemoved = true;
nodeRef.node = node;
if (entry.IsDirectory()) {
if (_HasDirectory(nodeRef, &notify))
_RemoveDirectory(entry, fromNode);
if (_WatchFilesOnly())
notify = false;
} else {
_RemoveFile(entry);
notify = true;
}
}
if (notify) {
if (wasAdded)
message->AddBool("added", true);
if (wasRemoved)
message->AddBool("removed", true);
_NotifyTarget(message);
}
}
void
PathHandler::MessageReceived(BMessage* message)
{
@@ -174,123 +432,16 @@ PathHandler::MessageReceived(BMessage* message)
switch (opcode) {
case B_ENTRY_CREATED:
{
const char* name;
node_ref nodeRef;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("directory", &nodeRef.node) != B_OK
|| message->FindString("name", &name) != B_OK)
break;
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
break;
bool notify = true;
if (entry.IsDirectory()) {
// a new directory to watch for us
if (_AddDirectory(entry) != B_OK
|| (fFlags & B_WATCH_FILES_ONLY) != 0)
notify = false;
}
if (notify && _IsContained(entry)) {
message->AddBool("added", true);
_NotifyTarget(message);
}
_EntryCreated(message);
break;
}
case B_ENTRY_MOVED:
{
// has the entry been moved into a monitored directory or has
// it been removed from one?
const char* name;
node_ref nodeRef;
uint64 fromNode;
uint64 node;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("to directory", &nodeRef.node) != B_OK
|| message->FindInt64("from directory", (int64 *)&fromNode) != B_OK
|| message->FindInt64("node", (int64 *)&node) != B_OK
|| message->FindString("name", &name) != B_OK)
break;
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
break;
bool wasAdded = false;
bool wasRemoved = false;
bool notify = true;
if (_HasDirectory(nodeRef)) {
// something has been added to our watched directories
// test, if the source directory is one of ours as well
nodeRef.node = fromNode;
bool hasFromDirectory = _HasDirectory(nodeRef);
if (entry.IsDirectory()) {
if (!hasFromDirectory) {
// there is a new directory to watch for us
_AddDirectory(entry);
wasAdded = true;
}
if ((fFlags & B_WATCH_FILES_ONLY) != 0)
notify = false;
} else if (!hasFromDirectory) {
// file has been added
wasAdded = true;
}
} else {
// and entry has been removed from our directories
wasRemoved = true;
if (entry.IsDirectory()) {
_RemoveDirectory(entry);
if ((fFlags & B_WATCH_FILES_ONLY) != 0)
notify = false;
}
}
if (notify && _IsContained(entry)) {
if (wasAdded)
message->AddBool("added", true);
if (wasRemoved)
message->AddBool("removed", true);
_NotifyTarget(message);
}
break;
}
case B_ENTRY_REMOVED:
{
node_ref nodeRef;
uint64 directoryNode;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("directory", (int64 *)&directoryNode) != B_OK
|| message->FindInt64("node", &nodeRef.node) != B_OK)
break;
bool notify = true;
if (_HasDirectory(nodeRef)) {
// the directory has been removed, so we remove it as well
_RemoveDirectory(nodeRef);
if ((fFlags & B_WATCH_FILES_ONLY) != 0)
notify = false;
}
nodeRef.node = directoryNode;
if (notify && _IsContained(nodeRef)) {
message->AddBool("removed", true);
_NotifyTarget(message);
}
_EntryRemoved(message);
break;
case B_ENTRY_MOVED:
_EntryMoved(message);
break;
}
default:
_NotifyTarget(message);
@@ -316,6 +467,8 @@ PathHandler::MessageReceived(BMessage* message)
BHandler::MessageReceived(message);
break;
}
Dump();
}
@@ -341,15 +494,42 @@ PathHandler::_IsContained(BEntry& entry) const
if (entry.GetPath(&path) != B_OK)
return false;
return strncmp(path.Path(), fPath.Path(), fPathLength) == 0;
bool contained = strncmp(path.Path(), fPath.Path(), fPathLength) == 0;
if (!contained)
return false;
const char* last = &path.Path()[fPathLength];
if (last[0] && last[0] != '/')
return false;
return true;
}
bool
PathHandler::_HasDirectory(const node_ref& nodeRef) const
PathHandler::_HasDirectory(const node_ref& nodeRef, bool* _contained = NULL) const
{
DirectorySet::const_iterator iterator = fDirectories.find(nodeRef);
return iterator != fDirectories.end();
watched_directory directory;
directory.node = nodeRef;
DirectorySet::const_iterator iterator = fDirectories.find(directory);
if (iterator == fDirectories.end())
return false;
if (_contained != NULL)
*_contained = iterator->contained;
return true;
}
bool
PathHandler::_CloserToPath(BEntry& entry) const
{
BPath path;
if (entry.GetPath(&path) != B_OK)
return false;
return strncmp(path.Path(), fPath.Path(), strlen(path.Path())) == 0;
}
@@ -365,27 +545,37 @@ PathHandler::_NotifyTarget(BMessage* message) const
status_t
PathHandler::_AddDirectory(BEntry& entry)
{
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
watched_directory directory;
status_t status = entry.GetNodeRef(&directory.node);
if (status != B_OK)
return status;
//#ifdef TRACE_MONITOR
{
BPath path(&entry);
printf(" ADD DIRECTORY %s, %ld:%Ld\n",
path.Path(), directory.node.device, directory.node.node);
}
//#endif
// check if we are already know this directory
if (_HasDirectory(nodeRef))
if (_HasDirectory(directory.node))
return B_OK;
directory.contained = _IsContained(entry);
uint32 flags;
if (_IsContained(entry))
flags = fFlags & WATCH_NODE_FLAG_MASK;
if (directory.contained)
flags = (fFlags & WATCH_NODE_FLAG_MASK) | B_WATCH_DIRECTORY;
else
flags = B_WATCH_DIRECTORY;
status = watch_node(&nodeRef, flags, this);
status = watch_node(&directory.node, flags, this);
if (status != B_OK)
return status;
fDirectories.insert(nodeRef);
fDirectories.insert(directory);
#if 0
BEntry parent;
@@ -399,26 +589,126 @@ PathHandler::_AddDirectory(BEntry& entry)
status_t
PathHandler::_RemoveDirectory(const node_ref& nodeRef)
PathHandler::_AddDirectory(node_ref& nodeRef)
{
DirectorySet::iterator iterator = fDirectories.find(nodeRef);
BDirectory directory(&nodeRef);
status_t status = directory.InitCheck();
if (status == B_OK) {
BEntry entry;
status = directory.GetEntry(&entry);
if (status == B_OK)
status = _AddDirectory(entry);
}
return status;
}
status_t
PathHandler::_RemoveDirectory(const node_ref& nodeRef, ino_t directoryNode)
{
printf(" REMOVE DIRECTORY %ld:%Ld\n", nodeRef.device, nodeRef.node);
watched_directory directory;
directory.node = nodeRef;
DirectorySet::iterator iterator = fDirectories.find(directory);
if (iterator == fDirectories.end())
return B_ENTRY_NOT_FOUND;
watch_node(&directory.node, B_STOP_WATCHING, this);
node_ref directoryRef;
directoryRef.device = nodeRef.device;
directoryRef.node = directoryNode;
if (!_HasDirectory(directoryRef)) {
// we don't have the parent directory now, but we'll need it in order
// to find this directory again in case it's added again
if (_AddDirectory(directoryRef) != B_OK
&& _GetClosest(fPath.Path(), false, directoryRef) == B_OK)
_AddDirectory(directoryRef);
}
fDirectories.erase(iterator);
return B_OK;
}
status_t
PathHandler::_RemoveDirectory(BEntry& entry)
PathHandler::_RemoveDirectory(BEntry& entry, ino_t directoryNode)
{
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
if (status != B_OK)
return status;
return _RemoveDirectory(nodeRef);
return _RemoveDirectory(nodeRef, directoryNode);
}
bool
PathHandler::_HasFile(const node_ref& nodeRef) const
{
FileSet::const_iterator iterator = fFiles.find(nodeRef);
return iterator != fFiles.end();
}
status_t
PathHandler::_AddFile(BEntry& entry)
{
if ((fFlags & (WATCH_NODE_FLAG_MASK & ~B_WATCH_DIRECTORY)) == 0)
return B_OK;
{
BPath path(&entry);
printf(" ADD FILE %s\n", path.Path());
}
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
if (status != B_OK)
return status;
// check if we are already know this file
if (_HasFile(nodeRef))
return B_OK;
status = watch_node(&nodeRef, (fFlags & WATCH_NODE_FLAG_MASK), this);
if (status != B_OK)
return status;
fFiles.insert(nodeRef);
return B_OK;
}
status_t
PathHandler::_RemoveFile(const node_ref& nodeRef)
{
printf(" REMOVE FILE %ld:%Ld\n", nodeRef.device, nodeRef.node);
FileSet::iterator iterator = fFiles.find(nodeRef);
if (iterator == fFiles.end())
return B_ENTRY_NOT_FOUND;
watch_node(&nodeRef, B_STOP_WATCHING, this);
fFiles.erase(iterator);
return B_OK;
}
status_t
PathHandler::_RemoveFile(BEntry& entry)
{
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
if (status != B_OK)
return status;
return _RemoveFile(nodeRef);
}
@@ -426,68 +716,116 @@ PathHandler::_RemoveDirectory(BEntry& entry)
BPathMonitor::BPathMonitor()
:
fHandler(NULL),
fStatus(B_NO_INIT)
{
}
BPathMonitor::BPathMonitor(const char* path, uint32 flags, BMessenger target)
:
fHandler(NULL),
fStatus(B_NO_INIT)
{
SetTo(path, flags, target);
}
BPathMonitor::~BPathMonitor()
{
Unset();
}
status_t
BPathMonitor::InitCheck() const
/*static*/ status_t
BPathMonitor::_InitIfNeeded()
{
return fStatus;
}
static vint32 lock = 0;
if (sLocker != NULL)
return B_OK;
while (sLocker == NULL) {
if (atomic_add(&lock, 1) == 0) {
sLocker = new BLocker("path monitor");
}
snooze(5000);
}
status_t
BPathMonitor::SetTo(const char* path, uint32 flags, BMessenger target)
{
Unset();
fHandler = new PathHandler(path, flags, target);
status_t status = fHandler->InitCheck();
if (status < B_OK)
Unset();
return fStatus = status;
}
status_t
BPathMonitor::SetTarget(BMessenger target)
{
if (fStatus < B_OK)
return B_NO_INIT;
fHandler->SetTarget(target);
return B_OK;
}
void
BPathMonitor::Unset()
/*static*/ status_t
BPathMonitor::StartWatching(const char* path, uint32 flags, BMessenger target)
{
if (fHandler != NULL) {
fHandler->Quit();
fHandler = NULL;
status_t status = _InitIfNeeded();
if (status != B_OK)
return status;
BAutolock _(sLocker);
WatcherMap::iterator iterator = sWatchers.find(target);
struct watcher* watcher = NULL;
if (iterator != sWatchers.end())
watcher = iterator->second;
PathHandler* handler = new PathHandler(path, flags, target);
status = handler->InitCheck();
if (status < B_OK)
return status;
if (watcher == NULL) {
watcher = new BPrivate::watcher;
sWatchers[target] = watcher;
}
fStatus = B_NO_INIT;
watcher->handlers[path] = handler;
return B_OK;
}
//} // namespace BPrivate
/*static*/ status_t
BPathMonitor::StopWatching(const char* path, BMessenger target)
{
BAutolock _(sLocker);
WatcherMap::iterator iterator = sWatchers.find(target);
if (iterator == sWatchers.end())
return B_BAD_VALUE;
struct watcher* watcher = iterator->second;
HandlerMap::iterator i = watcher->handlers.find(path);
if (i == watcher->handlers.end())
return B_BAD_VALUE;
PathHandler* handler = i->second;
watcher->handlers.erase(i);
if (handler->LockLooper())
handler->Quit();
if (watcher->handlers.empty()) {
sWatchers.erase(iterator);
delete watcher;
}
return B_OK;
}
/*static*/ status_t
BPathMonitor::StopWatching(BMessenger target)
{
BAutolock _(sLocker);
WatcherMap::iterator iterator = sWatchers.find(target);
if (iterator == sWatchers.end())
return B_BAD_VALUE;
struct watcher* watcher = iterator->second;
HandlerMap::iterator i = watcher->handlers.begin();
for (; i != watcher->handlers.end(); i++) {
PathHandler* handler = i->second;
watcher->handlers.erase(i);
if (handler->LockLooper())
handler->Quit();
}
sWatchers.erase(iterator);
delete watcher;
return B_OK;
}
} // namespace BPrivate
+9
View File
@@ -1,8 +1,12 @@
SubDir HAIKU_TOP src tests kits storage testapps ;
UsePrivateHeaders shared storage ;
SetSubDirSupportedPlatformsBeOSCompatible ;
AddSubDirSupportedPlatforms libbe_test ;
SEARCH_SOURCE += [ FDirName $(TOP) src kits storage ] ;
SimpleTest <test>clipboard
: clipboard.cpp : be ;
@@ -11,3 +15,8 @@ SimpleTest dump_mime_types
SimpleTest NodeMonitorTest
: NodeMonitorTest.cpp : be ;
SimpleTest PathMonitorTest
: PathMonitorTest.cpp PathMonitor.cpp
: be $(TARGET_LIBSTDC++)
;
@@ -0,0 +1,188 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Looper.h>
#include <Path.h>
#include <PathMonitor.h>
#include <stdio.h>
#include <string.h>
using BPrivate::BPathMonitor;
class Looper : public BLooper {
public:
Looper(const char* path);
virtual ~Looper();
virtual void MessageReceived(BMessage* message);
private:
BPath fPath;
};
Looper::Looper(const char* path)
: BLooper("path monitor test"),
fPath(path)
{
status_t status = BPathMonitor::StartWatching(path, B_WATCH_ALL, this);
if (status != B_OK) {
fprintf(stderr, "Could not watch path \"%s\": %s.\n", path, strerror(status));
PostMessage(B_QUIT_REQUESTED);
}
}
Looper::~Looper()
{
status_t status = BPathMonitor::StopWatching(fPath.Path(), this);
if (status != B_OK)
fprintf(stderr, "Could not stop watching: %s\n", strerror(status));
}
void
Looper::MessageReceived(BMessage* message)
{
if (message->what == B_PATH_MONITOR)
message->PrintToStream();
}
// #pragma mark -
void
create_file(const char* path)
{
printf("******* create file %s *******\n", path);
BFile file;
status_t status = file.SetTo(path, B_CREATE_FILE | B_READ_WRITE);
if (status != B_OK)
fprintf(stderr, "could not create watch test.\n");
file.Write("test", 4);
}
void
remove_file(const char* path)
{
printf("******* remove file %s *******\n", path);
remove(path);
}
void
create_directory(const char* path)
{
printf("******* create directory %s *******\n", path);
create_directory(path, 0755);
}
void
remove_directory(const char* path)
{
printf("******* remove directory %s *******\n", path);
rmdir(path);
}
// #pragma mark -
void
test_a()
{
puts("******************* test A ********************");
create_directory("/tmp/a");
create_directory("/tmp/ab");
create_directory("/tmp/a/b");
create_directory("/tmp/a/bc");
create_directory("/tmp/a/b/c");
create_directory("/tmp/a/b/cd");
create_file("/tmp/a/b/c/d");
snooze(100000);
remove_file("/tmp/a/b/c/d");
remove_directory("/tmp/a/b/cd");
remove_directory("/tmp/a/bc");
remove_directory("/tmp/ab");
snooze(100000);
}
void
test_b()
{
puts("******************* test B ********************");
remove_directory("/tmp/a/b/c");
snooze(100000);
create_file("/tmp/a/b/c");
snooze(100000);
remove_file("/tmp/a/b/c");
}
void
test_c()
{
puts("******************* test C ********************");
create_directory("/tmp/a/b/c");
create_directory("/tmp/a/b/c/d");
snooze(100000);
remove_directory("/tmp/a/b/c/d");
remove_directory("/tmp/a/b/c");
}
void
test_d()
{
puts("******************* test D ********************");
remove_directory("/tmp/a/b");
remove_directory("/tmp/a");
}
int
main()
{
// start looper
Looper& looper = *new Looper("/tmp/a/b/c");
looper.Run();
// run tests
test_a();
test_b();
test_c();
test_d();
#if 0
char b[2100];
gets(b);
#endif
snooze(500000LL);
// quit looper
looper.PostMessage(B_QUIT_REQUESTED);
status_t status;
wait_for_thread(looper.Thread(), &status);
return 0;
}