From 778144f0b5bc14fe55d79854d0a67124ceaa4b22 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 18 Sep 2012 00:38:40 +0400 Subject: [PATCH] darwin: emit relative path in fsevents --- include/uv-private/uv-darwin.h | 3 ++ include/uv.h | 9 +++++- src/unix/fsevents.c | 56 +++++++++++++++++++++++++++++++--- src/unix/kqueue.c | 6 ++-- src/unix/linux/inotify.c | 3 -- src/unix/sunos.c | 2 -- src/win/fs-event.c | 3 -- test/test-fs-event.c | 3 +- 8 files changed, 67 insertions(+), 18 deletions(-) diff --git a/include/uv-private/uv-darwin.h b/include/uv-private/uv-darwin.h index 397c6a97..4d68d013 100644 --- a/include/uv-private/uv-darwin.h +++ b/include/uv-private/uv-darwin.h @@ -41,6 +41,9 @@ ev_io event_watcher; \ int fflags; \ int fd; \ + char* realpath; \ + int realpath_len; \ + int cf_flags; \ void* cf_eventstream; \ uv_async_t* cf_cb; \ ngx_queue_t cf_events; \ diff --git a/include/uv.h b/include/uv.h index d2d16292..72da68d6 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1675,7 +1675,14 @@ enum uv_fs_event_flags { * regular interval. * This flag is currently not implemented yet on any backend. */ - UV_FS_EVENT_STAT = 2 + UV_FS_EVENT_STAT = 2, + + /* + * By default, event watcher, when watching directory, is not registering + * (is ignoring) changes in it's subdirectories. + * This flag will override this behaviour on platforms that support it. + */ + UV_FS_EVENT_RECURSIVE = 3 }; diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 1a7e06e4..17dd11af 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -66,8 +66,13 @@ void uv__fsevents_cb(uv_async_t* cb, int status) { handle = cb->data; UV__FSEVENTS_WALK(handle, { - if (handle->fd != -1) + if (handle->fd != -1) { +#ifdef MAC_OS_X_VERSION_10_7 handle->cb(handle, event->path, event->events, 0); +#else + handle->cb(handle, NULL, event->events, 0); +#endif /* MAC_OS_X_VERSION_10_7 */ + } }) if ((handle->flags & (UV_CLOSING | UV_CLOSED)) == 0 && handle->fd == -1) @@ -84,6 +89,8 @@ void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, size_t i; int len; char** paths; + char* path; + char* pos; uv_fs_event_t* handle; uv__fsevents_event_t* event; ngx_queue_t add_list; @@ -99,17 +106,50 @@ void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone | kFSEventStreamEventFlagMount | - kFSEventStreamEventFlagUnmount)) { + kFSEventStreamEventFlagUnmount | + kFSEventStreamEventFlagRootChanged)) { continue; } /* TODO: Report errors */ - len = strlen(paths[i]); + path = paths[i]; + len = strlen(path); + + /* Remove absolute path prefix */ + if (strstr(path, handle->realpath) == path) { + path += handle->realpath_len; + len -= handle->realpath_len; + + /* Skip back slash */ + if (*path != 0) { + path++; + len--; + } + } + +#ifdef MAC_OS_X_VERSION_10_7 + /* Ignore events with path equal to directory itself */ + if (len == 0) + continue; +#endif /* MAC_OS_X_VERSION_10_7 */ + + /* Do not emit events from subdirectories (without option set) */ + pos = strchr(path, '/'); + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && + pos != NULL && + pos != path + 1) + continue; + +#ifndef MAC_OS_X_VERSION_10_7 + path = ""; + len = 0; +#endif /* MAC_OS_X_VERSION_10_7 */ + event = malloc(sizeof(*event) + len); if (event == NULL) break; - memcpy(event->path, paths[i], len + 1); + memcpy(event->path, path, len + 1); if (eventFlags[i] & kFSEventStreamEventFlagItemModified) event->events = UV_CHANGE; @@ -153,6 +193,11 @@ int uv__fsevents_init(uv_fs_event_t* handle) { ctx.release = NULL; ctx.copyDescription = NULL; + /* Get absolute path to file */ + handle->realpath = realpath(handle->filename, NULL); + if (handle->realpath != NULL) + handle->realpath_len = strlen(handle->realpath); + /* Initialize paths array */ path = CFStringCreateWithCString(NULL, handle->filename, @@ -220,6 +265,9 @@ int uv__fsevents_close(uv_fs_event_t* handle) { uv_mutex_destroy(&handle->cf_mutex); uv_sem_destroy(&handle->cf_sem); + free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; return 0; } diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index b79dce3c..46b9da2a 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -93,9 +93,6 @@ int uv_fs_event_init(uv_loop_t* loop, struct stat statbuf; #endif /* defined(__APPLE__) */ - /* We don't support any flags yet. */ - assert(!flags); - /* TODO open asynchronously - but how do we report back errors? */ if ((fd = open(filename, O_RDONLY)) == -1) { uv__set_sys_error(loop, errno); @@ -112,6 +109,9 @@ int uv_fs_event_init(uv_loop_t* loop, #if defined(__APPLE__) /* Nullify field to perform checks later */ handle->cf_eventstream = NULL; + handle->realpath = NULL; + handle->realpath_len = 0; + handle->cf_flags = flags; if (fstat(fd, &statbuf)) goto fallback; diff --git a/src/unix/linux/inotify.c b/src/unix/linux/inotify.c index 3c290883..97231db9 100644 --- a/src/unix/linux/inotify.c +++ b/src/unix/linux/inotify.c @@ -176,9 +176,6 @@ int uv_fs_event_init(uv_loop_t* loop, int events; int wd; - /* We don't support any flags yet. */ - assert(!flags); - if (init_inotify(loop)) return -1; events = UV__IN_ATTRIB diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 18412b8d..bf135248 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -196,8 +196,6 @@ int uv_fs_event_init(uv_loop_t* loop, int portfd; int first_run = 0; - /* We don't support any flags yet. */ - assert(!flags); if (loop->fs_fd == -1) { if ((portfd = port_create()) == -1) { uv__set_sys_error(loop, errno); diff --git a/src/win/fs-event.c b/src/win/fs-event.c index c20c0730..1954cb09 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -138,9 +138,6 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL; WCHAR short_path[MAX_PATH]; - /* We don't support any flags yet. */ - assert(!flags); - uv_fs_event_init_handle(loop, handle, filename, cb); /* Convert name to UTF16. */ diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 257d64ca..4d4cfbc3 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -98,8 +98,7 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_RENAME); - ASSERT(filename == NULL || strcmp(filename, "file1") == 0 || - strstr(filename, "watch_dir") != NULL); + ASSERT(filename == NULL || strcmp(filename, "file1") == 0); uv_close((uv_handle_t*)handle, close_cb); }