mirror of
https://github.com/octoleo/lsyncd.git
synced 2024-12-13 14:43:09 +00:00
working on fsevents, fixed some warnings.
This commit is contained in:
parent
29348c4d93
commit
eda08c2f4e
214
fsevents.c
214
fsevents.c
@ -1,5 +1,4 @@
|
|||||||
/**
|
/** fsevents.c from Lsyncd - Live (Mirror) Syncing Demon
|
||||||
* fsevents.c from Lsyncd - Live (Mirror) Syncing Demon
|
|
||||||
*
|
*
|
||||||
* License: GPLv2 (see COPYING) or any later version
|
* License: GPLv2 (see COPYING) or any later version
|
||||||
*
|
*
|
||||||
@ -7,30 +6,175 @@
|
|||||||
*
|
*
|
||||||
* -----------------------------------------------------------------------
|
* -----------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Event interface for MacOS 10(.5) /dev/fsevents interface.
|
* Event interface for MacOS 10.5 (Leopard) /dev/fsevents interface.
|
||||||
*
|
*
|
||||||
* WARNING! AFAIK this interface is not strictly considered "public" API
|
* Special thanks go to Amit Singh and his fslogger demonstration that showed
|
||||||
* by Apple. Thus it might easily change between versions. Also its said,
|
* how apples /dev/fsevents can be used. http://osxbook.com/software/fslogger/
|
||||||
* altough every event receiver has its own message queue, the OS X kernel
|
|
||||||
* only deletes a message after *all* registered receivers handled it. So
|
|
||||||
* one receiver blocking overflows all receivers. So spotlight might have
|
|
||||||
* to do more stuff, when Lsyncd might cause an overflow. Use at own risk.
|
|
||||||
*
|
*
|
||||||
* Special thanks go to Amit Singh and his fslogger demonstration that
|
* -- WARNING -- Quoting http://www.osxbook.com/software/fslogger/ --
|
||||||
* showed how apples /dev/fsevents can be used.
|
*
|
||||||
* http://osxbook.com/software/fslogger/
|
* The interface that fslogger [and thus Lsyncd] uses is private to Apple.
|
||||||
|
* Currently, there is a caveat regarding the use of this interface by third
|
||||||
|
* parties (including fslogger [and thus Lsyncd]). While the change
|
||||||
|
* notification interface supports multiple clients, there is a single kernel
|
||||||
|
* buffer for holding events that are to be delivered to one or more
|
||||||
|
* subscribers, with the primary subscriber being Spotlight. Now, the kernel
|
||||||
|
* must hold events until it has notified all subscribers that are interested
|
||||||
|
* in them. Since there is a single buffer, a slow subscriber can cause it to
|
||||||
|
* overflow. If this happens, events will be dropped — for all subscribers,
|
||||||
|
* including Spotlight. Consequently, Spotlight may need to look at the entire
|
||||||
|
* volume to determine "what changed".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lsyncd.h"
|
#include "lsyncd.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "bsd/sys/fsevents.h"
|
||||||
|
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* the fsevents pseudo-device */
|
||||||
|
#define DEV_FSEVENTS "/dev/fsevents"
|
||||||
|
|
||||||
|
/* buffer for reading from the device */
|
||||||
|
#define FSEVENT_BUFSIZ 131072
|
||||||
|
/* limited by MAX_KFS_EVENTS */
|
||||||
|
#define EVENT_QUEUE_SIZE 4096
|
||||||
|
#define KFS_NUM_ARGS FSE_MAX_ARGS
|
||||||
|
|
||||||
|
/* OS 10.5 structuce */
|
||||||
|
/* an event argument */
|
||||||
|
struct kfs_event_arg {
|
||||||
|
/* argument type */
|
||||||
|
u_int16_t type;
|
||||||
|
|
||||||
|
/* size of argument data that follows this field */
|
||||||
|
u_int16_t len;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct vnode *vp;
|
||||||
|
char *str;
|
||||||
|
void *ptr;
|
||||||
|
int32_t int32;
|
||||||
|
dev_t dev;
|
||||||
|
ino_t ino;
|
||||||
|
int32_t mode;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
uint64_t timestamp;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* OS 10.5 structuce */
|
||||||
|
/* an event */
|
||||||
|
struct kfs_event {
|
||||||
|
|
||||||
|
/* event type */
|
||||||
|
int32_t type;
|
||||||
|
|
||||||
|
/* pid of the process that performed the operation */
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
/* event arguments */
|
||||||
|
struct kfs_event_arg args[KFS_NUM_ARGS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fsevents (cloned) filedescriptor
|
||||||
|
*/
|
||||||
|
static int fsevents_fd = -1;
|
||||||
|
|
||||||
static const luaL_reg lfseventslib[] = {
|
static const luaL_reg lfseventslib[] = {
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static size_t const readbuf_size = 131072;
|
||||||
|
static char * readbuf = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when fsevents has something to read
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
fsevents_ready(lua_State *L, struct observance *obs)
|
||||||
|
{
|
||||||
|
if (obs->fd != fsevents_fd) {
|
||||||
|
logstring("Error", "Internal, fsevents_fd != ob->fd");
|
||||||
|
exit(-1); // ERRNO
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
ptrdiff_t len;
|
||||||
|
int err;
|
||||||
|
len = read (fsevents_fd, readbuf, readbuf_size);
|
||||||
|
err = errno;
|
||||||
|
if (len == 0) {
|
||||||
|
/* nothing more */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len < 0) {
|
||||||
|
if (err == EAGAIN) {
|
||||||
|
/* nothing more inotify */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
printlogf(L, "Error", "Read fail on fsevents");
|
||||||
|
exit(-1); // ERRNO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int off = 0;
|
||||||
|
int32_t atype;
|
||||||
|
uint32_t aflags;
|
||||||
|
|
||||||
|
while (off < len && !hup && !term) {
|
||||||
|
struct kfs_event *event = (struct kfs_event *) &readbuf[off];
|
||||||
|
off += sizeof(int32_t) + sizeof(pid_t);
|
||||||
|
|
||||||
|
if (event->type == FSE_EVENTS_DROPPED) {
|
||||||
|
logstring("Fsevents", "Events dropped!");
|
||||||
|
load_runner_func(L, "overflow");
|
||||||
|
if (lua_pcall(L, 0, 0, -2)) {
|
||||||
|
exit(-1); // ERRNO
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
hup = 1;
|
||||||
|
off += sizeof(u_int16_t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
atype = event->type & FSE_TYPE_MASK;
|
||||||
|
aflags = FSE_GET_FLAGS(event->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to close/tidy fsevents
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
fsevents_tidy(struct observance *obs)
|
||||||
|
{
|
||||||
|
if (obs->fd != fsevents_fd) {
|
||||||
|
logstring("Error", "Internal, fsevents_fd != ob->fd");
|
||||||
|
exit(-1); // ERRNO
|
||||||
|
}
|
||||||
|
close(fsevents_fd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* registers fsevents functions.
|
* registers fsevents functions.
|
||||||
*/
|
*/
|
||||||
@ -45,14 +189,46 @@ register_fsevents(lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
open_fsevents(lua_State *L) {
|
open_fsevents(lua_State *L) {
|
||||||
// TODO
|
|
||||||
|
int8_t event_list[] = { // action to take for each event
|
||||||
|
FSE_REPORT, /* FSE_CREATE_FILE */
|
||||||
|
FSE_REPORT, /* FSE_DELETE */
|
||||||
|
FSE_REPORT, /* FSE_STAT_CHANGED */
|
||||||
|
FSE_REPORT, /* FSE_RENAME */
|
||||||
|
FSE_REPORT, /* FSE_CONTENT_MODIFIED */
|
||||||
|
FSE_REPORT, /* FSE_EXCHANGE */
|
||||||
|
FSE_REPORT, /* FSE_FINDER_INFO_CHANGED */
|
||||||
|
FSE_REPORT, /* FSE_CREATE_DIR */
|
||||||
|
FSE_REPORT, /* FSE_CHOWN */
|
||||||
|
FSE_REPORT, /* FSE_XATTR_MODIFIED */
|
||||||
|
FSE_REPORT, /* FSE_XATTR_REMOVED */
|
||||||
|
};
|
||||||
|
struct fsevent_clone_args fca = {
|
||||||
|
.event_list = (int8_t *) event_list,
|
||||||
|
.num_events = sizeof(event_list)/sizeof(int8_t),
|
||||||
|
.event_queue_depth = EVENT_QUEUE_SIZE,
|
||||||
|
.fd = &fsevents_fd,
|
||||||
|
};
|
||||||
|
int fd = open(DEV_FSEVENTS, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
printlogf(L, "Error",
|
||||||
|
"Cannot access %s monitor! (%d:%s)",
|
||||||
|
DEV_FSEVENTS, errno, strerror(errno));
|
||||||
|
exit(-1); // ERRNO
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if (ioctl(fd, FSEVENTS_CLONE, (char *)&fca) < 0) {
|
||||||
* closes fsevents
|
printlogf(L, "Error",
|
||||||
*/
|
"Cannot control %s monitor! (%d:%s)",
|
||||||
extern void
|
DEV_FSEVENTS, errno, strerror(errno));
|
||||||
close_fsevents() {
|
exit(-1); // ERRNO
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fd has been cloned, closes access fd */
|
||||||
|
close(fd);
|
||||||
|
close_exec_fd(fsevents_fd);
|
||||||
|
non_block_fd(fsevents_fd);
|
||||||
|
observe_fd(fsevents_fd, fsevents_ready, NULL, fsevents_tidy, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ static int
|
|||||||
l_addwatch(lua_State *L)
|
l_addwatch(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *path = luaL_checkstring(L, 1);
|
const char *path = luaL_checkstring(L, 1);
|
||||||
lua_Integer wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
|
int wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
|
||||||
printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd);
|
printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd);
|
||||||
lua_pushinteger(L, wd);
|
lua_pushinteger(L, wd);
|
||||||
return 1;
|
return 1;
|
||||||
@ -86,7 +86,7 @@ l_addwatch(lua_State *L)
|
|||||||
static int
|
static int
|
||||||
l_rmwatch(lua_State *L)
|
l_rmwatch(lua_State *L)
|
||||||
{
|
{
|
||||||
lua_Integer wd = luaL_checkinteger(L, 1);
|
int wd = luaL_checkinteger(L, 1);
|
||||||
inotify_rm_watch(inotify_fd, wd);
|
inotify_rm_watch(inotify_fd, wd);
|
||||||
printlogf(L, "Inotify", "rmwatch()<-%d", wd);
|
printlogf(L, "Inotify", "rmwatch()<-%d", wd);
|
||||||
return 0;
|
return 0;
|
||||||
@ -352,7 +352,7 @@ open_inotify(lua_State *L) {
|
|||||||
readbuf = s_malloc(readbuf_size);
|
readbuf = s_malloc(readbuf_size);
|
||||||
|
|
||||||
inotify_fd = inotify_init();
|
inotify_fd = inotify_init();
|
||||||
if (inotify_fd == -1) {
|
if (inotify_fd < 0) {
|
||||||
printlogf(L, "Error",
|
printlogf(L, "Error",
|
||||||
"Cannot access inotify monitor! (%d:%s)",
|
"Cannot access inotify monitor! (%d:%s)",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
|
8
lsyncd.c
8
lsyncd.c
@ -1213,6 +1213,7 @@ masterloop(lua_State *L)
|
|||||||
{
|
{
|
||||||
while(true) {
|
while(true) {
|
||||||
bool have_alarm;
|
bool have_alarm;
|
||||||
|
bool force_alarm;
|
||||||
clock_t now = times(NULL);
|
clock_t now = times(NULL);
|
||||||
clock_t alarm_time;
|
clock_t alarm_time;
|
||||||
|
|
||||||
@ -1223,7 +1224,8 @@ masterloop(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lua_type(L, -1) == LUA_TBOOLEAN) {
|
if (lua_type(L, -1) == LUA_TBOOLEAN) {
|
||||||
have_alarm = lua_toboolean(L, -1);
|
have_alarm = false;
|
||||||
|
force_alarm = lua_toboolean(L, -1);
|
||||||
} else {
|
} else {
|
||||||
have_alarm = true;
|
have_alarm = true;
|
||||||
alarm_time =
|
alarm_time =
|
||||||
@ -1231,7 +1233,9 @@ masterloop(lua_State *L)
|
|||||||
}
|
}
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
|
|
||||||
if (have_alarm && time_before_eq(alarm_time, now)) {
|
if (force_alarm ||
|
||||||
|
(have_alarm && time_before_eq(alarm_time, now))
|
||||||
|
) {
|
||||||
/* there is a delay that wants to be handled already thus instead
|
/* there is a delay that wants to be handled already thus instead
|
||||||
* of reading/writing from observances it jumps directly to
|
* of reading/writing from observances it jumps directly to
|
||||||
* handling */
|
* handling */
|
||||||
|
Loading…
Reference in New Issue
Block a user