Browse files

upgrade libuv

  • Loading branch information...
1 parent 74c0206 commit 8d37b6c92b61d9ab66b48ca67fd3e42751f5cf43 @ry ry committed Sep 22, 2011
View
2 deps/uv/config-unix.mk
@@ -22,7 +22,7 @@ CC = $(PREFIX)gcc
AR = $(PREFIX)ar
E=
CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter
-CFLAGS=-g
+CFLAGS += -g
CPPFLAGS += -Isrc/unix/ev
LINKFLAGS=-lm
View
29 deps/uv/include/uv-private/uv-linux.h
@@ -0,0 +1,29 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_H
+#define UV_LINUX_H
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ ev_io read_watcher; \
+ uv_fs_event_cb cb; \
+
+#endif /* UV_LINUX_H */
View
9 deps/uv/include/uv-private/uv-unix.h
@@ -27,6 +27,10 @@
#include "ev.h"
#include "eio.h"
+#if defined(__linux__)
+#include "uv-private/uv-linux.h"
+#endif
+
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -42,6 +46,11 @@ typedef struct {
typedef int uv_file;
+/* Stub. Remove it once all platforms support the file watcher API. */
+#ifndef UV_FS_EVENT_PRIVATE_FIELDS
+#define UV_FS_EVENT_PRIVATE_FIELDS /* empty */
+#endif
+
#define UV_LOOP_PRIVATE_FIELDS \
ares_channel channel; \
/* \
View
13 deps/uv/include/uv-private/uv-win.h
@@ -86,7 +86,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
UV_GETADDRINFO_REQ, \
UV_PROCESS_EXIT, \
UV_PROCESS_CLOSE, \
- UV_UDP_RECV
+ UV_UDP_RECV, \
+ UV_FS_EVENT_REQ
#define UV_REQ_PRIVATE_FIELDS \
union { \
@@ -261,6 +262,16 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define UV_WORK_PRIVATE_FIELDS \
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ struct uv_fs_event_req_s { \
+ UV_REQ_FIELDS \
+ } req; \
+ HANDLE dir_handle; \
+ int req_pending; \
+ uv_fs_event_cb cb; \
+ wchar_t* filew; \
+ int is_path_dir; \
+ char* buffer;
#define UV_TTY_PRIVATE_FIELDS /* empty */
View
49 deps/uv/include/uv.h
@@ -65,6 +65,8 @@ typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
typedef struct uv_udp_send_s uv_udp_send_t;
typedef struct uv_fs_s uv_fs_t;
+/* uv_fs_event_t is a subclass of uv_handle_t. */
+typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_work_s uv_work_t;
#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
@@ -137,6 +139,15 @@ typedef void (*uv_fs_cb)(uv_fs_t* req);
typedef void (*uv_work_cb)(uv_work_t* req);
typedef void (*uv_after_work_cb)(uv_work_t* req);
+/*
+* This will be called repeatedly after the uv_fs_event_t is initialized.
+* If uv_fs_event_t was initialized with a directory the filename parameter
+* will be a relative path to a file contained in the directory.
+* The events paramenter is an ORed mask of enum uv_fs_event elements.
+*/
+typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename,
+ int events, int status);
+
/* Expand this list if necessary. */
typedef enum {
@@ -201,7 +212,8 @@ typedef enum {
UV_ASYNC,
UV_ARES_TASK,
UV_ARES_EVENT,
- UV_PROCESS
+ UV_PROCESS,
+ UV_FS_EVENT
} uv_handle_type;
typedef enum {
@@ -612,6 +624,17 @@ int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd);
*/
int uv_tty_set_mode(uv_tty_t*, int mode);
+/*
+ * Gets the current Window size. On success zero is returned.
+ */
+int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
+
+/*
+ * Used to detect what type of stream should be used with a given file
+ * descriptor. Usually this will be used during initialization to guess the
+ * type of the stdio streams.
+ */
+uv_handle_type uv_guess_handle(uv_file file);
/*
* uv_pipe_t is a subclass of uv_stream_t
@@ -1002,6 +1025,27 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid,
int gid, uv_fs_cb cb);
+enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+};
+
+
+struct uv_fs_event_s {
+ UV_HANDLE_FIELDS
+ char* filename;
+ UV_FS_EVENT_PRIVATE_FIELDS
+};
+
+
+/*
+* If filename is a directory then we will watch for all events in that
+* directory. If filename is a file - we will only get events from that
+* file. Subdirectories are not watched.
+*/
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
+ const char* filename, uv_fs_event_cb cb);
+
/* Utility */
/* Convert string ip addresses to binary structures */
@@ -1037,6 +1081,7 @@ union uv_any_handle {
uv_async_t async;
uv_timer_t timer;
uv_getaddrinfo_t getaddrinfo;
+ uv_fs_event_t fs_event;
};
union uv_any_req {
@@ -1064,6 +1109,7 @@ struct uv_counters_s {
uint64_t async_init;
uint64_t timer_init;
uint64_t process_init;
+ uint64_t fs_event_init;
};
@@ -1097,6 +1143,7 @@ struct uv_loop_s {
#undef UV_GETADDRINFO_PRIVATE_FIELDS
#undef UV_FS_REQ_PRIVATE_FIELDS
#undef UV_WORK_PRIVATE_FIELDS
+#undef UV_FS_EVENT_PRIVATE_FIELDS
#ifdef __cplusplus
}
View
7 deps/uv/src/unix/core.c
@@ -137,6 +137,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
ev_child_stop(process->loop->ev, &process->child_watcher);
break;
+ case UV_FS_EVENT:
+ uv__fs_event_destroy((uv_fs_event_t*)handle);
+ break;
+
default:
assert(0);
}
@@ -250,6 +254,9 @@ void uv__finish_close(uv_handle_t* handle) {
assert(!ev_is_active(&((uv_process_t*)handle)->child_watcher));
break;
+ case UV_FS_EVENT:
+ break;
+
default:
assert(0);
break;
View
16 deps/uv/src/unix/cygwin.c
@@ -20,8 +20,10 @@
#include "uv.h"
+#include <assert.h>
#include <stdint.h>
#include <stddef.h>
+#include <errno.h>
#include <time.h>
#undef NANOSEC
@@ -50,3 +52,17 @@ int uv_exepath(char* buffer, size_t* size) {
buffer[*size] = '\0';
return 0;
}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ uv_err_new(loop, ENOSYS);
+ return -1;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ assert(0 && "implement me");
+}
View
17 deps/uv/src/unix/darwin.c
@@ -20,7 +20,10 @@
#include "uv.h"
+#include <assert.h>
#include <stdint.h>
+#include <errno.h>
+
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
@@ -63,3 +66,17 @@ int uv_exepath(char* buffer, size_t* size) {
*size = strlen(buffer);
return 0;
}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ uv_err_new(loop, ENOSYS);
+ return -1;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ assert(0 && "implement me");
+}
View
19 deps/uv/src/unix/freebsd.c
@@ -20,15 +20,18 @@
#include "uv.h"
+#include <assert.h>
#include <string.h>
-#include <time.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/sysctl.h>
+#include <time.h>
#undef NANOSEC
#define NANOSEC 1000000000
+
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -63,3 +66,17 @@ int uv_exepath(char* buffer, size_t* size) {
return 0;
}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ uv_err_new(loop, ENOSYS);
+ return -1;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ assert(0 && "implement me");
+}
View
16 deps/uv/src/unix/internal.h
@@ -25,6 +25,8 @@
#include "uv-common.h"
#include "uv-eio.h"
+#include <stddef.h> /* offsetof */
+
#if defined(__linux__)
#include <linux/version.h>
@@ -59,6 +61,17 @@
# define HAVE_FUTIMES
#endif
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#define SAVE_ERRNO(block) \
+ do { \
+ int _saved_errno = errno; \
+ do { block; } while (0); \
+ errno = _saved_errno; \
+ } \
+ while (0);
+
/* flags */
enum {
UV_CLOSING = 0x00000001, /* uv_close() called but not finished. */
@@ -110,4 +123,7 @@ int uv_pipe_cleanup(uv_pipe_t* handle);
void uv__udp_destroy(uv_udp_t* handle);
void uv__udp_watcher_stop(uv_udp_t* handle, ev_io* w);
+/* fs */
+void uv__fs_event_destroy(uv_fs_event_t* handle);
+
#endif /* UV_UNIX_INTERNAL_H_ */
View
134 deps/uv/src/unix/linux.c
@@ -19,15 +19,29 @@
*/
#include "uv.h"
+#include "internal.h"
#include <stdint.h>
-#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/inotify.h>
#include <unistd.h>
#include <time.h>
#undef NANOSEC
#define NANOSEC 1000000000
+
+/* Don't look aghast, this is exactly how glibc's basename() works. */
+static char* basename_r(const char* path) {
+ char* s = strrchr(path, '/');
+ return s ? (s + 1) : (char*)path;
+}
+
+
/*
* There's probably some way to get time from Linux than gettimeofday(). What
* it is, I don't know.
@@ -49,3 +63,121 @@ int uv_exepath(char* buffer, size_t* size) {
buffer[*size] = '\0';
return 0;
}
+
+
+static int new_inotify_fd(void) {
+#if defined(IN_NONBLOCK) && defined(IN_CLOEXEC)
+ return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+#else
+ int fd;
+
+ if ((fd = inotify_init()) == -1)
+ return -1;
+
+ if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) {
+ SAVE_ERRNO(uv__close(fd));
+ fd = -1;
+ }
+
+ return fd;
+#endif
+}
+
+
+static void uv__inotify_read(EV_P_ ev_io* w, int revents) {
+ struct inotify_event* e;
+ uv_fs_event_t* handle;
+ const char* filename;
+ ssize_t size;
+ int events;
+ char *p;
+ /* needs to be large enough for sizeof(inotify_event) + strlen(filename) */
+ char buf[4096];
+
+ handle = container_of(w, uv_fs_event_t, read_watcher);
+
+ do {
+ do {
+ size = read(handle->fd, buf, sizeof buf);
+ }
+ while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ break;
+ }
+
+ assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
+
+ /* Now we have one or more inotify_event structs. */
+ for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
+ e = (void*)p;
+
+ events = 0;
+ if (e->mask & (IN_ATTRIB|IN_MODIFY))
+ events |= UV_CHANGE;
+ if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
+ events |= UV_RENAME;
+
+ /* inotify does not return the filename when monitoring a single file
+ * for modifications. Repurpose the filename for API compatibility.
+ * I'm not convinced this is a good thing, maybe it should go.
+ */
+ filename = e->len ? e->name : basename_r(handle->filename);
+
+ handle->cb(handle, filename, events, 0);
+ }
+ }
+ while (handle->fd != -1); /* handle might've been closed by callback */
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ int flags;
+ int fd;
+
+ /*
+ * TODO share a single inotify fd across the event loop?
+ * We'll run into fs.inotify.max_user_instances if we
+ * keep creating new inotify fds.
+ */
+ if ((fd = new_inotify_fd()) == -1) {
+ uv_err_new(loop, errno);
+ return -1;
+ }
+
+ flags = IN_ATTRIB
+ | IN_CREATE
+ | IN_MODIFY
+ | IN_DELETE
+ | IN_DELETE_SELF
+ | IN_MOVED_FROM
+ | IN_MOVED_TO;
+
+ if (inotify_add_watch(fd, filename, flags) == -1) {
+ uv_err_new(loop, errno);
+ uv__close(fd);
+ return -1;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ handle->filename = strdup(filename); /* this should go! */
+ handle->cb = cb;
+ handle->fd = fd;
+
+ ev_io_init(&handle->read_watcher, uv__inotify_read, fd, EV_READ);
+ ev_io_start(loop->ev, &handle->read_watcher);
+
+ return 0;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ ev_io_stop(handle->loop->ev, &handle->read_watcher);
+ uv__close(handle->fd);
+ handle->fd = -1;
+ free(handle->filename);
+}
View
19 deps/uv/src/unix/netbsd.c
@@ -20,17 +20,20 @@
#include "uv.h"
+#include <assert.h>
#include <string.h>
-#include <time.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <unistd.h>
+#include <time.h>
#undef NANOSEC
#define NANOSEC 1000000000
+
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -66,3 +69,17 @@ int uv_exepath(char* buffer, size_t* size) {
return 0;
}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ uv_err_new(loop, ENOSYS);
+ return -1;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ assert(0 && "implement me");
+}
View
19 deps/uv/src/unix/sunos.c
@@ -22,8 +22,11 @@
#include <stdio.h>
#include <stdint.h>
-#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
#include <sys/time.h>
+#include <unistd.h>
uint64_t uv_hrtime() {
@@ -58,3 +61,17 @@ int uv_exepath(char* buffer, size_t* size) {
*size = res;
return (0);
}
+
+
+int uv_fs_event_init(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ const char* filename,
+ uv_fs_event_cb cb) {
+ uv_err_new(loop, ENOSYS);
+ return -1;
+}
+
+
+void uv__fs_event_destroy(uv_fs_event_t* handle) {
+ assert(0 && "implement me");
+}
View
41 deps/uv/src/unix/tty.c
@@ -23,6 +23,7 @@
#include "internal.h"
#include <assert.h>
+#include <unistd.h>
#include <termios.h>
#include <errno.h>
@@ -71,3 +72,43 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
int uv_is_tty(uv_file file) {
return isatty(file);
}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ struct winsize ws;
+
+ if (ioctl(tty->fd, TIOCGWINSZ, &ws) < 0) {
+ uv_err_new(tty->loop, errno);
+ return -1;
+ }
+
+ *width = ws.ws_col;
+ *height = ws.ws_row;
+
+ return 0;
+}
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ struct stat s;
+
+ if (file < 0) {
+ uv_err_new(NULL, EINVAL); /* XXX Need loop? */
+ return -1;
+ }
+
+ if (isatty(file)) {
+ return UV_TTY;
+ }
+
+ if (fstat(file, &s)) {
+ uv_err_new(NULL, errno); /* XXX Need loop? */
+ return -1;
+ }
+
+ if (!S_ISSOCK(s.st_mode) && !S_ISFIFO(s.st_mode)) {
+ return UV_FILE;
+ }
+
+ return UV_NAMED_PIPE;
+}
View
384 deps/uv/src/win/fs-event.c
@@ -0,0 +1,384 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <malloc.h>
+#include <errno.h>
+#include <string.h>
+#include "uv.h"
+#include "internal.h"
+
+
+const unsigned int uv_directory_watcher_buffer_size = 4096;
+
+
+static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
+ const char* filename, uv_fs_event_cb cb) {
+ handle->type = UV_FS_EVENT;
+ handle->loop = loop;
+ handle->flags = 0;
+ handle->cb = cb;
+ handle->is_path_dir = 0;
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ handle->buffer = NULL;
+ handle->req_pending = 0;
+ handle->filew = NULL;
+
+ uv_req_init(loop, (uv_req_t*)&handle->req);
+ handle->req.type = UV_FS_EVENT_REQ;
+ handle->req.data = (void*)handle;
+
+ handle->filename = strdup(filename);
+ if (!handle->filename) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ loop->counters.handle_init++;
+ loop->counters.fs_event_init++;
+
+ uv_ref(loop);
+}
+
+
+static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+ uv_fs_event_t* handle) {
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
+ assert(!handle->req_pending);
+
+ memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.overlapped,
+ NULL)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(&handle->req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+ }
+
+ handle->req_pending = 1;
+}
+
+
+static int uv_split_path(const wchar_t* filename, wchar_t** dir,
+ wchar_t** file) {
+ int len = wcslen(filename);
+ int i = len;
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
+
+ if (i == 0) {
+ *dir = (wchar_t*)malloc((MAX_PATH + 1) * sizeof(wchar_t));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
+ free(*dir);
+ *dir = NULL;
+ return -1;
+ }
+
+ *file = wcsdup(filename);
+ } else {
+ *dir = (wchar_t*)malloc((i + 1) * sizeof(wchar_t));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+ wcsncpy(*dir, filename, i);
+ (*dir)[i] = L'\0';
+
+ *file = (wchar_t*)malloc((len - i) * sizeof(wchar_t));
+ if (!*file) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+ wcsncpy(*file, filename + i + 1, len - i - 1);
+ (*file)[len - i - 1] = L'\0';
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
+ const char* filename, uv_fs_event_cb cb) {
+ int name_size;
+ DWORD attr, last_error;
+ wchar_t* dir = NULL, *dir_to_watch, *filenamew;
+
+ uv_fs_event_init_handle(loop, handle, filename, cb);
+
+ /* Convert name to UTF16. */
+ name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(wchar_t);
+ filenamew = (wchar_t*)malloc(name_size);
+ if (!filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ if (!uv_utf8_to_utf16(filename, filenamew,
+ name_size / sizeof(wchar_t))) {
+ uv_set_sys_error(loop, GetLastError());
+ return -1;
+ }
+
+ /* Determine whether filename is a file or a directory. */
+ attr = GetFileAttributesW(filenamew);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+
+ if (handle->is_path_dir) {
+ /* filename is a directory, so that's the directory that we will watch. */
+ dir_to_watch = filenamew;
+ } else {
+ /*
+ * filename is a file. So we split filename into dir & file parts, and
+ * watch the dir directory.
+ */
+ if (uv_split_path(filenamew, &dir, &handle->filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ dir_to_watch = dir;
+ }
+
+ handle->dir_handle = CreateFileW(dir_to_watch,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (dir) {
+ free(dir);
+ dir = NULL;
+ }
+
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (CreateIoCompletionPort(handle->dir_handle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size,
+ sizeof(DWORD));
+ if (!handle->buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped));
+
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.overlapped,
+ NULL)) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->req_pending = 1;
+ return 0;
+
+error:
+ if (handle->filename) {
+ free(handle->filename);
+ handle->filename = NULL;
+ }
+
+ if (handle->filew) {
+ free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->buffer) {
+ _aligned_free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ uv_set_sys_error(loop, last_error);
+ return -1;
+}
+
+
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle) {
+ FILE_NOTIFY_INFORMATION* file_info;
+ char* filename = NULL;
+ int utf8size;
+ DWORD offset = 0;
+
+ assert(req->type == UV_FS_EVENT_REQ);
+ assert(handle->req_pending);
+ handle->req_pending = 0;
+
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
+
+ if (REQ_SUCCESS(req)) {
+ if (req->overlapped.InternalHigh > 0) {
+ do {
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
+
+ /*
+ * Fire the event only if we were asked to watch a directory,
+ * or if the filename filter matches.
+ */
+ if (handle->is_path_dir || _wcsnicmp(handle->filew, file_info->FileName,
+ file_info->FileNameLength / sizeof(wchar_t)) == 0) {
+
+ /* Convert the filename to utf8. */
+ utf8size = uv_utf16_to_utf8(file_info->FileName,
+ file_info->FileNameLength /
+ sizeof(wchar_t),
+ NULL,
+ 0);
+ if (utf8size) {
+ filename = (char*)malloc(utf8size + 1);
+ if (!filename) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ utf8size = uv_utf16_to_utf8(file_info->FileName,
+ file_info->FileNameLength /
+ sizeof(wchar_t),
+ filename,
+ utf8size);
+ if (utf8size) {
+ filename[utf8size] = L'\0';
+ } else {
+ free(filename);
+ filename = NULL;
+ }
+ }
+
+ switch (file_info->Action) {
+ case FILE_ACTION_ADDED:
+ case FILE_ACTION_REMOVED:
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ handle->cb(handle, filename, UV_RENAME, 0);
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ handle->cb(handle, filename, UV_CHANGE, 0);
+ break;
+ }
+
+ free(filename);
+ filename = NULL;
+ }
+
+ offset = file_info->NextEntryOffset;
+ } while(offset);
+ } else {
+ handle->cb(handle, NULL, UV_CHANGE, 0);
+ }
+ } else {
+ loop->last_error = GET_REQ_UV_ERROR(req);
+ handle->cb(handle, NULL, 0, -1);
+ }
+
+ if (!(handle->flags & UV_HANDLE_CLOSING)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
+ } else {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (!handle->req_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if (handle->flags & UV_HANDLE_CLOSING &&
+ !handle->req_pending) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ if (handle->buffer) {
+ _aligned_free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ if (handle->filew) {
+ free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->filename) {
+ free(handle->filename);
+ handle->filename = NULL;
+ }
+
+ if (handle->close_cb) {
+ handle->close_cb((uv_handle_t*)handle);
+ }
+
+ uv_unref(loop);
+ }
+}
View
8 deps/uv/src/win/handle.c
@@ -120,6 +120,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_process_close(loop, process);
return;
+ case UV_FS_EVENT:
+ uv_fs_event_close(loop, (uv_fs_event_t*)handle);
+ return;
+
default:
/* Not supported */
abort();
@@ -177,6 +181,10 @@ void uv_process_endgames(uv_loop_t* loop) {
uv_process_endgame(loop, (uv_process_t*) handle);
break;
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
default:
assert(0);
break;
View
8 deps/uv/src/win/internal.h
@@ -232,6 +232,14 @@ void uv_process_work_req(uv_loop_t* loop, uv_work_t* req);
/*
+ * FS Event
+ */
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle);
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
+
+
+/*
* Error handling
*/
extern const uv_err_t uv_ok_;
View
4 deps/uv/src/win/req.c
@@ -165,6 +165,10 @@ void uv_process_reqs(uv_loop_t* loop) {
uv_process_work_req(loop, (uv_work_t*) req);
break;
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
default:
assert(0);
}
View
12 deps/uv/src/win/tty.c
@@ -42,3 +42,15 @@ int uv_is_tty(uv_file file) {
int r = GetConsoleMode((HANDLE)_get_osfhandle(file), &result);
return r ? 1 : 0;
}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ assert(0 && "implement me");
+ return -1;
+}
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ assert(0 && "implement me");
+ return UV_UNKNOWN_HANDLE;
+}
View
217 deps/uv/test/test-fs-event.c
@@ -0,0 +1,217 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <fcntl.h>
+
+uv_fs_event_t fs_event;
+uv_timer_t timer;
+int timer_cb_called;
+int close_cb_called;
+int fs_event_cb_called;
+
+static void create_dir(uv_loop_t* loop, const char* name) {
+ int r;
+ uv_fs_t req;
+ r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void create_file(uv_loop_t* loop, const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+
+ r = uv_fs_open(loop, &req, name, O_WRONLY | O_CREAT,
+ S_IWRITE | S_IREAD, NULL);
+ ASSERT(r != -1);
+ file = r;
+ uv_fs_req_cleanup(&req);
+ r = uv_fs_close(loop, &req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void touch_file(uv_loop_t* loop, const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+
+ r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL);
+ ASSERT(r != -1);
+ file = r;
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_write(loop, &req, file, "foo", 4, -1, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_close(loop, &req, file, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&req);
+}
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_RENAME);
+ ASSERT(strcmp(filename, "file1") == 0);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ ASSERT(strcmp(filename, "file2") == 0);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
+ const char* filename, int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ ASSERT(strcmp(filename, "watch_file") == 0);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void timer_cb_dir(uv_timer_t* handle, int status) {
+ ++timer_cb_called;
+ create_file(handle->loop, "watch_dir/file1");
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void timer_cb_file(uv_timer_t* handle, int status) {
+ ++timer_cb_called;
+
+ if (timer_cb_called == 1) {
+ touch_file(handle->loop, "watch_dir/file1");
+ } else {
+ touch_file(handle->loop, "watch_dir/file2");
+ uv_close((uv_handle_t*)handle, close_cb);
+ }
+}
+
+TEST_IMPL(fs_event_watch_dir) {
+ uv_fs_t fs_req;
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
+ uv_fs_unlink(loop, &fs_req, "watch_dir/file2", NULL);
+ uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
+ create_dir(loop, "watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_dir);
+ ASSERT(r != -1);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r != -1);
+ r = uv_timer_start(&timer, timer_cb_dir, 100, 0);
+ ASSERT(r != -1);
+
+ uv_run(loop);
+
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ r = uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
+ r = uv_fs_unlink(loop, &fs_req, "watch_dir/file2", NULL);
+ r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
+
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file) {
+ uv_fs_t fs_req;
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
+ uv_fs_unlink(loop, &fs_req, "watch_dir/file2", NULL);
+ uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
+ create_dir(loop, "watch_dir");
+ create_file(loop, "watch_dir/file1");
+ create_file(loop, "watch_dir/file2");
+
+ r = uv_fs_event_init(loop, &fs_event, "watch_dir/file2", fs_event_cb_file);
+ ASSERT(r != -1);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r != -1);
+ r = uv_timer_start(&timer, timer_cb_file, 100, 100);
+ ASSERT(r != -1);
+
+ uv_run(loop);
+
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(timer_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ r = uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
+ r = uv_fs_unlink(loop, &fs_req, "watch_dir/file2", NULL);
+ r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
+
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file_current_dir) {
+ uv_fs_t fs_req;
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ uv_fs_unlink(loop, &fs_req, "watch_file", NULL);
+ create_file(loop, "watch_file");
+
+ r = uv_fs_event_init(loop, &fs_event, "watch_file",
+ fs_event_cb_file_current_dir);
+ ASSERT(r != -1);
+
+ touch_file(loop, "watch_file");
+
+ uv_run(loop);
+
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ r = uv_fs_unlink(loop, &fs_req, "watch_file", NULL);
+ return 0;
+}
View
6 deps/uv/test/test-list.h
@@ -87,6 +87,9 @@ TEST_DECLARE (fs_link)
TEST_DECLARE (fs_symlink)
TEST_DECLARE (fs_utime)
TEST_DECLARE (fs_futime)
+TEST_DECLARE (fs_event_watch_dir)
+TEST_DECLARE (fs_event_watch_file)
+TEST_DECLARE (fs_event_watch_file_current_dir)
TEST_DECLARE (threadpool_queue_work_simple)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
@@ -201,6 +204,9 @@ TASK_LIST_START
TEST_ENTRY (fs_utime)
TEST_ENTRY (fs_futime)
TEST_ENTRY (fs_symlink)
+ TEST_ENTRY (fs_event_watch_dir)
+ TEST_ENTRY (fs_event_watch_file)
+ TEST_ENTRY (fs_event_watch_file_current_dir)
TEST_ENTRY (threadpool_queue_work_simple)
View
25 deps/uv/test/test-tty.c
@@ -23,10 +23,35 @@
#include "task.h"
TEST_IMPL(tty) {
+ int r, width, height;
+ uv_tty_t tty;
uv_loop_t* loop = uv_default_loop();
+ /*
+ * Not necessarally a problem if this assert goes off. E.G you are piping
+ * this test to a file. 0 == stdin.
+ */
ASSERT(uv_is_tty(0) == 1);
+ r = uv_tty_init(uv_default_loop(), &tty, 0);
+ ASSERT(r == 0);
+
+ ASSERT(UV_TTY == uv_guess_handle(0));
+
+ r = uv_tty_get_winsize(&tty, &width, &height);
+ ASSERT(r == 0);
+
+ printf("width=%d height=%d\n", width, height);
+
+ /*
+ * Is it a safe assumption that most people have terminals larger than
+ * 10x10?
+ */
+ ASSERT(width > 10);
+ ASSERT(height > 10);
+
+ uv_close((uv_handle_t*)&tty, NULL);
+
uv_run(loop);
return 0;
View
3 deps/uv/uv.gyp
@@ -103,6 +103,7 @@
'src/win/core.c',
'src/win/error.c',
'src/win/fs.c',
+ 'src/win/fs-event.c',
'src/win/getaddrinfo.c',
'src/win/handle.c',
'src/win/internal.h',
@@ -238,6 +239,7 @@
'test/test-delayed-accept.c',
'test/test-fail-always.c',
'test/test-fs.c',
+ 'test/test-fs-event.c',
'test/test-get-currentexe.c',
'test/test-getaddrinfo.c',
'test/test-gethostbyname.c',
@@ -334,3 +336,4 @@
]
}
+

0 comments on commit 8d37b6c

Please sign in to comment.