* 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:
@@ -17,22 +17,18 @@
|
|||||||
|
|
||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
|
|
||||||
class PathHandler;
|
|
||||||
|
|
||||||
class BPathMonitor {
|
class BPathMonitor {
|
||||||
public:
|
public:
|
||||||
BPathMonitor();
|
static status_t StartWatching(const char* path, uint32 flags, BMessenger target);
|
||||||
BPathMonitor(const char* path, uint32 flags, BMessenger target);
|
|
||||||
~BPathMonitor();
|
|
||||||
|
|
||||||
status_t InitCheck() const;
|
static status_t StopWatching(const char* path, BMessenger target);
|
||||||
status_t SetTo(const char* path, uint32 flags, BMessenger target);
|
static status_t StopWatching(BMessenger target);
|
||||||
status_t SetTarget(BMessenger target);
|
|
||||||
void Unset();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathHandler* fHandler;
|
BPathMonitor();
|
||||||
status_t fStatus;
|
~BPathMonitor();
|
||||||
|
|
||||||
|
static status_t _InitIfNeeded();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace BPrivate
|
} // namespace BPrivate
|
||||||
|
|||||||
+547
-209
@@ -9,13 +9,19 @@
|
|||||||
|
|
||||||
#include <PathMonitor.h>
|
#include <PathMonitor.h>
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
#include <Autolock.h>
|
||||||
#include <Directory.h>
|
#include <Directory.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <Handler.h>
|
#include <Handler.h>
|
||||||
|
#include <Locker.h>
|
||||||
#include <Looper.h>
|
#include <Looper.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
@@ -24,10 +30,23 @@ using namespace std;
|
|||||||
|
|
||||||
#define WATCH_NODE_FLAG_MASK 0x00ff
|
#define WATCH_NODE_FLAG_MASK 0x00ff
|
||||||
|
|
||||||
typedef set<node_ref> DirectorySet;
|
|
||||||
|
|
||||||
namespace BPrivate {
|
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 {
|
class PathHandler : public BHandler {
|
||||||
public:
|
public:
|
||||||
PathHandler(const char* path, uint32 flags, BMessenger target);
|
PathHandler(const char* path, uint32 flags, BMessenger target);
|
||||||
@@ -38,15 +57,30 @@ class PathHandler : public BHandler {
|
|||||||
void Quit();
|
void Quit();
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
void Dump();
|
||||||
|
|
||||||
private:
|
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(const node_ref& nodeRef) const;
|
||||||
bool _IsContained(BEntry& entry) 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;
|
void _NotifyTarget(BMessage* message) const;
|
||||||
status_t _AddDirectory(BEntry& entry);
|
status_t _AddDirectory(BEntry& entry);
|
||||||
status_t _RemoveDirectory(const node_ref& nodeRef);
|
status_t _AddDirectory(node_ref& nodeRef);
|
||||||
status_t _RemoveDirectory(BEntry& entry);
|
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;
|
BPath fPath;
|
||||||
int32 fPathLength;
|
int32 fPathLength;
|
||||||
@@ -55,9 +89,12 @@ class PathHandler : public BHandler {
|
|||||||
status_t fStatus;
|
status_t fStatus;
|
||||||
bool fOwnsLooper;
|
bool fOwnsLooper;
|
||||||
DirectorySet fDirectories;
|
DirectorySet fDirectories;
|
||||||
|
FileSet fFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
static WatcherMap sWatchers;
|
||||||
|
static BLocker* sLocker;
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target)
|
PathHandler::PathHandler(const char* path, uint32 flags, BMessenger target)
|
||||||
: BHandler(path),
|
: BHandler(path),
|
||||||
fPath(path, NULL, true),
|
|
||||||
fTarget(target),
|
fTarget(target),
|
||||||
fFlags(flags),
|
fFlags(flags),
|
||||||
fOwnsLooper(false)
|
fOwnsLooper(false)
|
||||||
{
|
{
|
||||||
fPathLength = strlen(fPath.Path());
|
if (path == NULL || !path[0]) {
|
||||||
|
fStatus = B_BAD_VALUE;
|
||||||
BPath first(path);
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support watching not-yet-mounted volumes as well!
|
||||||
|
node_ref nodeRef;
|
||||||
|
fStatus = _GetClosest(path, true, nodeRef);
|
||||||
if (fStatus < B_OK)
|
if (fStatus < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
BLooper* looper;
|
||||||
if (be_app != NULL) {
|
if (be_app != NULL) {
|
||||||
be_app->AddHandler(this);
|
looper = be_app;
|
||||||
} else {
|
} else {
|
||||||
// TODO: only have a single global looper!
|
// TODO: only have a single global looper!
|
||||||
BLooper* looper = new BLooper("PathMonitor looper");
|
looper = new BLooper("PathMonitor looper");
|
||||||
looper->Run();
|
looper->Run();
|
||||||
looper->AddHandler(this);
|
|
||||||
fOwnsLooper = true;
|
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
|
void
|
||||||
PathHandler::Quit()
|
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, ¬ify)) {
|
||||||
|
// 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, ¬ify))
|
||||||
|
_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
|
void
|
||||||
PathHandler::MessageReceived(BMessage* message)
|
PathHandler::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
@@ -174,123 +432,16 @@ PathHandler::MessageReceived(BMessage* message)
|
|||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case B_ENTRY_CREATED:
|
case B_ENTRY_CREATED:
|
||||||
{
|
_EntryCreated(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)
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
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:
|
case B_ENTRY_REMOVED:
|
||||||
{
|
_EntryRemoved(message);
|
||||||
node_ref nodeRef;
|
break;
|
||||||
uint64 directoryNode;
|
|
||||||
if (message->FindInt32("device", &nodeRef.device) != B_OK
|
case B_ENTRY_MOVED:
|
||||||
|| message->FindInt64("directory", (int64 *)&directoryNode) != B_OK
|
_EntryMoved(message);
|
||||||
|| 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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_NotifyTarget(message);
|
_NotifyTarget(message);
|
||||||
@@ -316,6 +467,8 @@ PathHandler::MessageReceived(BMessage* message)
|
|||||||
BHandler::MessageReceived(message);
|
BHandler::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -341,15 +494,42 @@ PathHandler::_IsContained(BEntry& entry) const
|
|||||||
if (entry.GetPath(&path) != B_OK)
|
if (entry.GetPath(&path) != B_OK)
|
||||||
return false;
|
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
|
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);
|
watched_directory directory;
|
||||||
return iterator != fDirectories.end();
|
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
|
status_t
|
||||||
PathHandler::_AddDirectory(BEntry& entry)
|
PathHandler::_AddDirectory(BEntry& entry)
|
||||||
{
|
{
|
||||||
node_ref nodeRef;
|
watched_directory directory;
|
||||||
status_t status = entry.GetNodeRef(&nodeRef);
|
status_t status = entry.GetNodeRef(&directory.node);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
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
|
// check if we are already know this directory
|
||||||
|
|
||||||
if (_HasDirectory(nodeRef))
|
if (_HasDirectory(directory.node))
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
|
directory.contained = _IsContained(entry);
|
||||||
|
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
if (_IsContained(entry))
|
if (directory.contained)
|
||||||
flags = fFlags & WATCH_NODE_FLAG_MASK;
|
flags = (fFlags & WATCH_NODE_FLAG_MASK) | B_WATCH_DIRECTORY;
|
||||||
else
|
else
|
||||||
flags = B_WATCH_DIRECTORY;
|
flags = B_WATCH_DIRECTORY;
|
||||||
|
|
||||||
status = watch_node(&nodeRef, flags, this);
|
status = watch_node(&directory.node, flags, this);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
fDirectories.insert(nodeRef);
|
fDirectories.insert(directory);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
BEntry parent;
|
BEntry parent;
|
||||||
@@ -399,26 +589,126 @@ PathHandler::_AddDirectory(BEntry& entry)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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())
|
if (iterator == fDirectories.end())
|
||||||
return B_ENTRY_NOT_FOUND;
|
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);
|
fDirectories.erase(iterator);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PathHandler::_RemoveDirectory(BEntry& entry)
|
PathHandler::_RemoveDirectory(BEntry& entry, ino_t directoryNode)
|
||||||
{
|
{
|
||||||
node_ref nodeRef;
|
node_ref nodeRef;
|
||||||
status_t status = entry.GetNodeRef(&nodeRef);
|
status_t status = entry.GetNodeRef(&nodeRef);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
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()
|
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()
|
BPathMonitor::~BPathMonitor()
|
||||||
{
|
{
|
||||||
Unset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
/*static*/ status_t
|
||||||
BPathMonitor::InitCheck() const
|
BPathMonitor::_InitIfNeeded()
|
||||||
{
|
{
|
||||||
return fStatus;
|
static vint32 lock = 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
if (sLocker != NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
status_t
|
while (sLocker == NULL) {
|
||||||
BPathMonitor::SetTo(const char* path, uint32 flags, BMessenger target)
|
if (atomic_add(&lock, 1) == 0) {
|
||||||
{
|
sLocker = new BLocker("path monitor");
|
||||||
Unset();
|
}
|
||||||
|
snooze(5000);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
/*static*/ status_t
|
||||||
BPathMonitor::Unset()
|
BPathMonitor::StartWatching(const char* path, uint32 flags, BMessenger target)
|
||||||
{
|
{
|
||||||
if (fHandler != NULL) {
|
status_t status = _InitIfNeeded();
|
||||||
fHandler->Quit();
|
if (status != B_OK)
|
||||||
fHandler = NULL;
|
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
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
SubDir HAIKU_TOP src tests kits storage testapps ;
|
SubDir HAIKU_TOP src tests kits storage testapps ;
|
||||||
|
|
||||||
|
UsePrivateHeaders shared storage ;
|
||||||
|
|
||||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
AddSubDirSupportedPlatforms libbe_test ;
|
AddSubDirSupportedPlatforms libbe_test ;
|
||||||
|
|
||||||
|
SEARCH_SOURCE += [ FDirName $(TOP) src kits storage ] ;
|
||||||
|
|
||||||
SimpleTest <test>clipboard
|
SimpleTest <test>clipboard
|
||||||
: clipboard.cpp : be ;
|
: clipboard.cpp : be ;
|
||||||
|
|
||||||
@@ -11,3 +15,8 @@ SimpleTest dump_mime_types
|
|||||||
|
|
||||||
SimpleTest NodeMonitorTest
|
SimpleTest NodeMonitorTest
|
||||||
: NodeMonitorTest.cpp : be ;
|
: 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user