1
0
Files
irix-657m-src/eoe/cmd/fam/Interest.c++
2022-09-29 17:59:04 +03:00

254 lines
5.7 KiB
C++

#include "Interest.h"
#include <bstring.h>
#include <string.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include "Boolean.h"
#include "ChangeFlags.h"
#include "Event.h"
#include "FileSystem.h"
#include "IMon.h"
#include "Log.h"
#include "Pollster.h"
#include "timeval.h"
Interest *Interest::hashtable[];
IMon Interest::imon(imon_handler);
Interest::Interest(const char *name, FileSystem *fs)
: myname(strcpy(new char[strlen(name) + 1], name)),
scan_state(OK),
cur_exec_state(NOT_EXECUTING),
old_exec_state(NOT_EXECUTING)
{
bzero(&old_stat, sizeof old_stat);
struct stat status;
bzero(&status, sizeof status);
IMon::Status s = imon.express(name, &status);
if (s != IMon::OK)
{ int rc = lstat(name, &status);
if (rc < 0)
{ Log::info("can't lstat %s", name);
bzero(&status, sizeof status);
}
}
dev = status.st_dev;
ino = status.st_ino;
if (dev || ino)
{
// Insert on new chain.
Interest **ipp = hashchain();
hashlink = *ipp;
*ipp = this;
}
else
hashlink = NULL;
(void) update_stat(status);
// Enable low-level monitoring.
// The NetWare filesystem is too slow to monitor, so
// don't even try.
if ( strcmp( (char *) &status.st_fstype, "nwfs"))
fs->ll_monitor(this, s == IMon::OK);
}
Interest::~Interest()
{
Pollster::forget(this);
revoke();
delete myname;
}
void
Interest::revoke()
{
// Traverse our hash chain. Delete this entry when we find it.
// Also check for other entries with same dev/ino.
if (dev || ino)
{
Boolean found_same = false;
for (Interest *p, **pp = hashchain(); p = *pp; )
if (p == this)
*pp = p->hashlink; // remove this from list
else
{ if (p->ino == ino && p->dev == dev)
found_same = true;
pp = &p->hashlink; // move to next element
}
if (!found_same)
(void) imon.revoke(name(), dev, ino);
}
}
void
Interest::dev_ino(dev_t newdev, ino_t newino)
{
// Remove from hash chain and revoke imon's interest.
revoke();
dev = newdev;
ino = newino;
if (newdev || newino)
{
// Insert on new chain.
Interest **ipp = hashchain();
hashlink = *ipp;
*ipp = this;
// Express interest.
imon.express(name(), NULL);
}
else
hashlink = NULL;
}
ChangeFlags
Interest::update_stat(struct stat& new_stat)
{
ChangeFlags changes;
if (dev != new_stat.st_dev)
changes.set(ChangeFlags::DEV);
if (ino != new_stat.st_ino)
changes.set(ChangeFlags::INO);
if (old_stat.mode != new_stat.st_mode)
old_stat.mode = new_stat.st_mode;
if (old_stat.uid != new_stat.st_uid)
{ old_stat.uid = new_stat.st_uid;
changes.set(ChangeFlags::UID);
}
if (old_stat.gid != new_stat.st_gid)
{ old_stat.gid = new_stat.st_gid;
changes.set(ChangeFlags::GID);
}
if (old_stat.size != new_stat.st_size)
{ old_stat.size = new_stat.st_size;
changes.set(ChangeFlags::SIZE);
}
if (old_stat.mtime != * (timeval *) &new_stat.st_mtim)
{ old_stat.mtime = * (timeval *) &new_stat.st_mtim;
changes.set(ChangeFlags::MTIME);
}
if (old_stat.ctime != * (timeval *) &new_stat.st_ctim)
{ old_stat.ctime = * (timeval *) &new_stat.st_ctim;
changes.set(ChangeFlags::CTIME);
}
return changes;
}
ChangeFlags
Interest::do_stat()
{
struct stat status;
int rc = lstat(name(), &status);
if (rc < 0) {
if (oserror() == ETIMEDOUT) {
return ChangeFlags();
}
bzero(&status, sizeof status);
}
Boolean exists = status.st_mode != 0;
Boolean did_exist = old_stat.mode != 0;
Boolean wasdir = (old_stat.mode & S_IFMT) == S_IFDIR;
ChangeFlags changes = update_stat(status);
if (exists && !did_exist)
{
post_event(Event::Created);
notify_created(this);
}
else if (did_exist && !exists)
{
post_event(Event::Deleted);
notify_deleted(this);
}
#if 0
else if (exists && did_exist)
{
// This extra exists event was causing all kinds of grief for
// the desktop. With this code in place, if you replace a
// directory with a file of the same name, the desktop gets a
// created event and a changed event. This forces the desktop
// to have to check each created event to see if it already
// knows about the file.
//
// With this code removed, the desktop simply gets a changed
// event, which seems perfectly appropriate.
// --rogerc 08/21/97
Boolean isdir = (status.st_mode & S_IFMT) == S_IFDIR;
if (wasdir != isdir)
post_event(Event::Exists);
}
#endif
// If dev/ino changed, move this interest to the right hash chain.
if (status.st_dev != dev || status.st_ino != ino)
dev_ino(status.st_dev, status.st_ino);
return changes;
}
void
Interest::do_scan()
{
if (needs_scan() && active())
{ needs_scan(false);
Boolean did_exist = exists();
ChangeFlags changes = do_stat();
if (changes && did_exist && exists())
post_event(Event(changes));
report_exec_state();
}
}
void
Interest::report_exec_state()
{
if (old_exec_state != cur_exec_state && active())
{ post_event(cur_exec_state == EXECUTING ?
Event::Executing : Event::Exited);
old_exec_state = cur_exec_state;
}
}
void
Interest::imon_handler(dev_t device, ino_t inumber, int event)
{
assert(device || inumber);
for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
{ next = p->hashlink;
if (p->ino == inumber && p->dev == device)
{ if (event == IMon::EXEC)
{ p->cur_exec_state = EXECUTING;
(void) p->report_exec_state();
}
else if (event == IMon::EXIT)
{ p->cur_exec_state = NOT_EXECUTING;
(void) p->report_exec_state();
}
else
{ assert(event == IMon::CHANGE);
p->scan();
}
}
}
}