diff options
Diffstat (limited to 'deps/uv/src/unix/aix.c')
-rw-r--r-- | deps/uv/src/unix/aix.c | 878 |
1 files changed, 856 insertions, 22 deletions
diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 2521681305..eb90111345 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -39,12 +39,235 @@ #include <unistd.h> #include <fcntl.h> #include <utmp.h> +#include <libgen.h> #include <sys/protosw.h> #include <libperfstat.h> #include <sys/proc.h> #include <sys/procfs.h> +#include <sys/poll.h> + +#include <sys/pollset.h> +#include <ctype.h> +#include <sys/ahafs_evProds.h> + +#include <sys/mntctl.h> +#include <sys/vmount.h> +#include <limits.h> +#include <strings.h> +#include <sys/vnode.h> + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + loop->fs_fd = -1; + + /* Passing maxfd of -1 should mean the limit is determined + * by the user's ulimit or the global limit as per the doc */ + loop->backend_fd = pollset_create(-1); + + if (loop->backend_fd == -1) + return -1; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + pollset_destroy(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct pollfd events[1024]; + struct pollfd pqry; + struct pollfd* pe; + struct poll_ctl pc; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + int nevents; + int count; + int nfds; + int i; + int rc; + int add_failed; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + pc.events = w->pevents; + pc.fd = w->fd; + + add_failed = 0; + if (w->events == 0) { + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + if (errno != EINVAL) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + /* Check if the fd is already in the pollset */ + pqry.fd = pc.fd; + rc = pollset_query(loop->backend_fd, &pqry); + switch (rc) { + case -1: + assert(0 && "Failed to query pollset for file descriptor"); + abort(); + case 0: + assert(0 && "Pollset does not contain file descriptor"); + abort(); + } + /* If we got here then the pollset already contained the file descriptor even though + * we didn't think it should. This probably shouldn't happen, but we can continue. */ + add_failed = 1; + } + } + if (w->events != 0 || add_failed) { + /* Modify, potentially removing events -- need to delete then add. + * Could maybe mod if we knew for sure no events are removed, but + * content of w->events is handled above as not reliable (falls back) + * so may require a pollset_query() which would have to be pretty cheap + * compared to a PS_DELETE to be worth optimising. Alternatively, could + * lazily remove events, squelching them in the mean time. */ + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to delete file descriptor (pc.fd) from pollset"); + abort(); + } + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + nfds = pollset_poll(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) { + abort(); + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + + for (i = 0; i < nfds; i++) { + pe = events + i; + pc.cmd = PS_DELETE; + pc.fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (pc.fd == -1) + continue; + + assert(pc.fd >= 0); + assert((unsigned) pc.fd < loop->nwatchers); + + w = loop->watchers[pc.fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + pollset_ctl(loop->backend_fd, &pc, 1); + continue; + } + + w->cb(loop, w, pe->revents); + nevents++; + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + uint64_t uv__hrtime(uv_clocktype_t type) { uint64_t G = 1000000000; timebasestruct_t t; @@ -58,28 +281,24 @@ uint64_t uv__hrtime(uv_clocktype_t type) { * We could use a static buffer for the path manipulations that we need outside * of the function, but this function could be called by multiple consumers and * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in AIX - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. */ int uv_exepath(char* buffer, size_t* size) { ssize_t res; - char pp[64], cwdl[PATH_MAX]; + char cwd[PATH_MAX], cwdl[PATH_MAX]; + char symlink[PATH_MAX], temp_buffer[PATH_MAX]; + char pp[64]; struct psinfo ps; int fd; + char **argv; - if (buffer == NULL) - return (-1); - - if (size == NULL) - return (-1); - - (void) snprintf(pp, sizeof(pp), "/proc/%lu/cwd", (unsigned long) getpid()); - - res = readlink(pp, cwdl, sizeof(cwdl) - 1); - if (res < 0) - return res; + if ((buffer == NULL) || (size == NULL)) + return -EINVAL; - cwdl[res] = '\0'; + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); - (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); fd = open(pp, O_RDONLY); if (fd < 0) return fd; @@ -89,9 +308,163 @@ int uv_exepath(char* buffer, size_t* size) { if (res < 0) return res; - (void) snprintf(buffer, *size, "%s%s", cwdl, ps.pr_fname); - *size = strlen(buffer); - return 0; + if (ps.pr_argv == 0) + return -EINVAL; + + argv = (char **) *((char ***) (intptr_t) ps.pr_argv); + + if ((argv == NULL) || (argv[0] == NULL)) + return -EINVAL; + + /* + * Three possibilities for argv[0]: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ./myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* case #1, absolute path. */ + if (argv[0][0] == '/') { + snprintf(symlink, PATH_MAX-1, "%s", argv[0]); + + /* This could or could not be a symlink. */ + res = readlink(symlink, temp_buffer, PATH_MAX-1); + + /* if readlink fails, it is a normal file just copy symlink to the + * outbut buffer. + */ + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + + /* If it is a link, the resolved filename is again a relative path, + * make it absolute. + */ + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + + /* case #2, relative path with usage of '.' */ + } else if (argv[0][0] == '.') { + char *relative = strchr(argv[0], '/'); + if (relative == NULL) + return -EINVAL; + + /* Get the current working directory to resolve the relative path. */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + + /* This is always a symlink, resolve it. */ + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1); + + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + + /* case #3, relative path without usage of '.', such as invocations in Node test suite. */ + } else if (strchr(argv[0], '/') != NULL) { + /* Get the current working directory to resolve the relative path. */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + + /* This is always a symlink, resolve it. */ + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]); + + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + /* Usage of absolute filename with location exported in PATH */ + } else { + char clonedpath[8192]; /* assume 8k buffer will fit PATH */ + char *token = NULL; + struct stat statstruct; + + /* Get the paths. */ + char *path = getenv("PATH"); + if(sizeof(clonedpath) <= strlen(path)) + return -EINVAL; + + /* Get a local copy. */ + strcpy(clonedpath, path); + + /* Tokenize. */ + token = strtok(clonedpath, ":"); + + /* Get current working directory. (may be required in the loop). */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + /* Run through the tokens, append our executable file name with each, + * and see which one succeeds. Exit on first match. */ + while(token != NULL) { + if (token[0] == '.') { + /* Path contains a token relative to current directory. */ + char *relative = strchr(token, '/'); + if (relative != NULL) + /* A path which is not current directory. */ + snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname); + else + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname); + if (stat(symlink, &statstruct) != -1) { + /* File exists. Resolve if it is a link. */ + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + } + + /* Absolute path names. */ + } else { + snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname); + if (stat(symlink, &statstruct) != -1) { + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + } + } + token = strtok(NULL, ":"); + } + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } } @@ -128,8 +501,369 @@ void uv_loadavg(double avg[3]) { } +static char *uv__rawname(char *cp) { + static char rawbuf[FILENAME_MAX+1]; + char *dp = rindex(cp, '/'); + + if (dp == 0) + return 0; + + *dp = 0; + strcpy(rawbuf, cp); + *dp = '/'; + strcat(rawbuf, "/r"); + strcat(rawbuf, dp+1); + return rawbuf; +} + + +/* + * Determine whether given pathname is a directory + * Returns 0 if the path is a directory, -1 if not + * + * Note: Opportunity here for more detailed error information but + * that requires changing callers of this function as well + */ +static int uv__path_is_a_directory(char* filename) { + struct stat statbuf; + + if (stat(filename, &statbuf) < 0) + return -1; /* failed: not a directory, assume it is a file */ + + if (statbuf.st_type == VDIR) + return 0; + + return -1; +} + + +/* + * Check whether AHAFS is mounted. + * Returns 0 if AHAFS is mounted, or an error code < 0 on failure + */ +static int uv__is_ahafs_mounted(void){ + int rv, i = 2; + struct vmount *p; + int size_multiplier = 10; + size_t siz = sizeof(struct vmount)*size_multiplier; + struct vmount *vmt; + const char *dev = "/aha"; + char *obj, *stub; + + p = malloc(siz); + if (p == NULL) + return -errno; + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + if (rv == 0) { + /* buffer was not large enough, reallocate to correct size */ + siz = *(int*)p; + free(p); + p = malloc(siz); + if (p == NULL) + return -errno; + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + } + + /* Look for dev in filesystems mount info */ + for(vmt = p, i = 0; i < rv; i++) { + obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ + stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ + + if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + free(p); /* Found a match */ + return 0; + } + vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length); + } + + /* /aha is required for monitoring filesystem changes */ + return -1; +} + +/* + * Recursive call to mkdir() to create intermediate folders, if any + * Returns code from mkdir call + */ +static int uv__makedir_p(const char *dir) { + char tmp[256]; + char *p = NULL; + size_t len; + int err; + + snprintf(tmp, sizeof(tmp),"%s",dir); + len = strlen(tmp); + if (tmp[len - 1] == '/') + tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if(err != 0) + return err; + *p = '/'; + } + } + return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} + +/* + * Creates necessary subdirectories in the AIX Event Infrastructure + * file system for monitoring the object specified. + * Returns code from mkdir call + */ +static int uv__make_subdirs_p(const char *filename) { + char cmd[2048]; + char *p; + int rc = 0; + + /* Strip off the monitor file name */ + p = strrchr(filename, '/'); + + if (p == NULL) + return 0; + + if (uv__path_is_a_directory((char*)filename) == 0) { + sprintf(cmd, "/aha/fs/modDir.monFactory"); + } else { + sprintf(cmd, "/aha/fs/modFile.monFactory"); + } + + strncat(cmd, filename, (p - filename)); + rc = uv__makedir_p(cmd); + + if (rc == -1 && errno != EEXIST){ + return -errno; + } + + return rc; +} + + +/* + * Checks if /aha is mounted, then proceeds to set up the monitoring + * objects for the specified file. + * Returns 0 on success, or an error code < 0 on failure + */ +static int uv__setup_ahafs(const char* filename, int *fd) { + int rc = 0; + char mon_file_write_string[RDWR_BUF_SIZE]; + char mon_file[PATH_MAX]; + int file_is_directory = 0; /* -1 == NO, 0 == YES */ + + /* Create monitor file name for object */ + file_is_directory = uv__path_is_a_directory((char*)filename); + + if (file_is_directory == 0) + sprintf(mon_file, "/aha/fs/modDir.monFactory"); + else + sprintf(mon_file, "/aha/fs/modFile.monFactory"); + + if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) + return -ENAMETOOLONG; + + /* Make the necessary subdirectories for the monitor file */ + rc = uv__make_subdirs_p(filename); + if (rc == -1 && errno != EEXIST) + return rc; + + strcat(mon_file, filename); + strcat(mon_file, ".mon"); + + *fd = 0; errno = 0; + + /* Open the monitor file, creating it if necessary */ + *fd = open(mon_file, O_CREAT|O_RDWR); + if (*fd < 0) + return -errno; + + /* Write out the monitoring specifications. + * In this case, we are monitoring for a state change event type + * CHANGED=YES + * We will be waiting in select call, rather than a read: + * WAIT_TYPE=WAIT_IN_SELECT + * We only want minimal information for files: + * INFO_LVL=1 + * For directories, we want more information to track what file + * caused the change + * INFO_LVL=2 + */ + + if (file_is_directory == 0) + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2"); + else + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); + + rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); + if (rc < 0) + return -errno; + + return 0; +} + +/* + * Skips a specified number of lines in the buffer passed in. + * Walks the buffer pointed to by p and attempts to skip n lines. + * Returns the total number of lines skipped + */ +static int uv__skip_lines(char **p, int n) { + int lines = 0; + + while(n > 0) { + *p = strchr(*p, '\n'); + if (!p) + return lines; + + (*p)++; + n--; + lines++; + } + return lines; +} + + +/* + * Parse the event occurrence data to figure out what event just occurred + * and take proper action. + * + * The buf is a pointer to the buffer containing the event occurrence data + * Returns 0 on success, -1 if unrecoverable error in parsing + * + */ +static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) { + int evp_rc, i; + char *p; + char filename[PATH_MAX]; /* To be used when handling directories */ + + p = buf; + *events = 0; + + /* Clean the filename buffer*/ + for(i = 0; i < PATH_MAX; i++) { + filename[i] = 0; + } + i = 0; + + /* Check for BUF_WRAP */ + if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) { + assert(0 && "Buffer wrap detected, Some event occurrences lost!"); + return 0; + } + + /* Since we are using the default buffer size (4K), and have specified + * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications + * should check for this keyword if they are using an INFO_LVL of 2 or + * higher, and have a buffer size of <= 4K + */ + + /* Skip to RC_FROM_EVPROD */ + if (uv__skip_lines(&p, 9) != 9) + return -1; + + if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) { + if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */ + if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) { + /* The directory is no longer available for monitoring */ + *events = UV_RENAME; + handle->dir_filename = NULL; + } else { + /* A file was added/removed inside the directory */ + *events = UV_CHANGE; + + /* Get the EVPROD_INFO */ + if (uv__skip_lines(&p, 1) != 1) + return -1; + + /* Scan out the name of the file that triggered the event*/ + if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) { + handle->dir_filename = strdup((const char*)&filename); + } else + return -1; + } + } else { /* Regular File */ + if (evp_rc == AHAFS_MODFILE_RENAME) + *events = UV_RENAME; + else + *events = UV_CHANGE; + } + } + else + return -1; + + return 0; +} + + +/* This is the internal callback */ +static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { + char result_data[RDWR_BUF_SIZE]; + int bytes, rc = 0; + uv_fs_event_t* handle; + int events = 0; + int i = 0; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* Clean all the buffers*/ + for(i = 0; i < PATH_MAX; i++) { + fname[i] = 0; + } + i = 0; + + /* At this point, we assume that polling has been done on the + * file descriptor, so we can just read the AHAFS event occurrence + * data and parse its results without having to block anything + */ + bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); + + assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file"); + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* For directory changes, the name of the files that triggered the change + * are never absolute pathnames + */ + if (uv__path_is_a_directory(handle->path) == 0) { + p = handle->dir_filename; + while(*p != NULL){ + fname[i]= *p; + i++; + p++; + } + } else { + /* For file changes, figure out whether filename is absolute or not */ + if (handle->path[0] == '/') { + p = strrchr(handle->path, '/'); + p++; + + while(*p != NULL) { + fname[i]= *p; + i++; + p++; + } + } + } + + /* Unrecoverable error */ + if (rc == -1) + return; + else /* Call the actual JavaScript callback function */ + handle->cb(handle, (const char*)&fname, events, 0); +} + + int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; } @@ -137,17 +871,99 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + int fd, rc, i = 0, res = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char fname[PATH_MAX]; + char *p; + + /* Clean all the buffers*/ + for(i = 0; i < PATH_MAX; i++) { + cwd[i] = 0; + absolute_path[i] = 0; + fname[i] = 0; + } + i = 0; + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname, create the relative pathname*/ + sprintf(absolute_path, filename); + p = strrchr(filename, '/'); + p++; + } else { + if (filename[0] == '.' && filename[1] == '/') { + /* We have a relative pathname, compose the absolute pathname */ + sprintf(fname, filename); + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); + if (res < 0) + return res; + p = strrchr(absolute_path, '/'); + p++; + p++; + } else { + /* We have a relative pathname, compose the absolute pathname */ + sprintf(fname, filename); + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); + if (res < 0) + return res; + p = strrchr(absolute_path, '/'); + p++; + } + /* Copy to filename buffer */ + while(filename[i] != NULL) { + *p = filename[i]; + i++; + p++; + } + } + + if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ + return UV_ENOSYS; + + /* Setup ahafs */ + rc = uv__setup_ahafs((const char *)absolute_path, &fd); + if (rc != 0) + return rc; + + /* Setup/Initialize all the libuv routines */ + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); + handle->path = strdup((const char*)&absolute_path); + handle->cb = cb; + + uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + + return 0; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + + if (!uv__is_active(handle)) + return 0; + + uv__io_close(handle->loop, &handle->event_watcher); + uv__handle_stop(handle); + + if (uv__path_is_a_directory(handle->path) == 0) { + free(handle->dir_filename); + handle->dir_filename = NULL; + } + + free(handle->path); + handle->path = NULL; + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + + return 0; } void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); + uv_fs_event_stop(handle); } @@ -175,7 +991,7 @@ int uv_resident_set_memory(size_t* rss) { int err; int fd; - (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); fd = open(pp, O_RDONLY); if (fd == -1) @@ -397,3 +1213,21 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, free(addresses); } + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct pollfd* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct pollfd*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].fd == fd) + events[i].fd = -1; +} |