/* This callback is called when the FD is available for read. The inotify events are read from FD and converted into input_events. */ static void inotify_callback (int fd, void *_) { struct input_event event; Lisp_Object watch_object; int to_read; char *buffer; ssize_t n; size_t i; to_read = 0; if (ioctl (fd, FIONREAD, &to_read) == -1) report_file_notify_error ("Error while retrieving file system events", Qnil); buffer = xmalloc (to_read); n = read (fd, buffer, to_read); if (n < 0) { xfree (buffer); report_file_notify_error ("Error while reading file system events", Qnil); } EVENT_INIT (event); event.kind = FILE_NOTIFY_EVENT; i = 0; while (i < (size_t)n) { struct inotify_event *ev = (struct inotify_event*)&buffer[i]; watch_object = Fassoc (make_watch_descriptor (ev->wd), watch_list); if (!NILP (watch_object)) { event.arg = inotifyevent_to_event (watch_object, ev); /* If event was removed automatically: Drop it from watch list. */ if (ev->mask & IN_IGNORED) watch_list = Fdelete (watch_object, watch_list); if (!NILP (event.arg)) kbd_buffer_store_event (&event); } i += sizeof (*ev) + ev->len; } xfree (buffer); }
/* Remove all watches associated with the watch list element after PREVTAIL, or after the first element if PREVTAIL is t. If INVALID_P is true, the descriptor is already invalid, i.e., it received a IN_IGNORED event. In this case skip calling inotify_rm_watch. */ static void remove_descriptor (Lisp_Object prevtail, bool invalid_p) { Lisp_Object tail = CONSP (prevtail) ? XCDR (prevtail) : watch_list; int inotify_errno = 0; if (! invalid_p) { int wd; CONS_TO_INTEGER (XCAR (XCAR (tail)), int, wd); if (inotify_rm_watch (inotifyfd, wd) != 0) inotify_errno = errno; } if (CONSP (prevtail)) XSETCDR (prevtail, XCDR (tail)); else { watch_list = XCDR (tail); if (NILP (watch_list)) { delete_read_fd (inotifyfd); emacs_close (inotifyfd); inotifyfd = -1; } } if (inotify_errno != 0) { errno = inotify_errno; report_file_notify_error ("Could not rm watch", XCAR (tail)); } }
/* This callback is called when the FD is available for read. The inotify events are read from FD and converted into input_events. */ static void inotify_callback (int fd, void *_) { int to_read; if (ioctl (fd, FIONREAD, &to_read) < 0) report_file_notify_error ("Error while retrieving file system events", Qnil); USE_SAFE_ALLOCA; char *buffer = SAFE_ALLOCA (to_read); ssize_t n = read (fd, buffer, to_read); if (n < 0) report_file_notify_error ("Error while reading file system events", Qnil); struct input_event event; EVENT_INIT (event); event.kind = FILE_NOTIFY_EVENT; for (ssize_t i = 0; i < n; ) { struct inotify_event *ev = (struct inotify_event *) &buffer[i]; Lisp_Object descriptor = INTEGER_TO_CONS (ev->wd); Lisp_Object prevtail = find_descriptor (descriptor); if (! NILP (prevtail)) { Lisp_Object tail = CONSP (prevtail) ? XCDR (prevtail) : watch_list; for (Lisp_Object watches = XCDR (XCAR (tail)); ! NILP (watches); watches = XCDR (watches)) { event.arg = inotifyevent_to_event (XCAR (watches), ev); if (!NILP (event.arg)) kbd_buffer_store_event (&event); } /* If event was removed automatically: Drop it from watch list. */ if (ev->mask & IN_IGNORED) remove_descriptor (prevtail, true); } i += sizeof (*ev) + ev->len; } SAFE_FREE (); }
static uint32_t symbol_to_inotifymask (Lisp_Object symb) { if (EQ (symb, Qaccess)) return IN_ACCESS; else if (EQ (symb, Qattrib)) return IN_ATTRIB; else if (EQ (symb, Qclose_write)) return IN_CLOSE_WRITE; else if (EQ (symb, Qclose_nowrite)) return IN_CLOSE_NOWRITE; else if (EQ (symb, Qcreate)) return IN_CREATE; else if (EQ (symb, Qdelete)) return IN_DELETE; else if (EQ (symb, Qdelete_self)) return IN_DELETE_SELF; else if (EQ (symb, Qmodify)) return IN_MODIFY; else if (EQ (symb, Qmove_self)) return IN_MOVE_SELF; else if (EQ (symb, Qmoved_from)) return IN_MOVED_FROM; else if (EQ (symb, Qmoved_to)) return IN_MOVED_TO; else if (EQ (symb, Qopen)) return IN_OPEN; else if (EQ (symb, Qmove)) return IN_MOVE; else if (EQ (symb, Qclose)) return IN_CLOSE; else if (EQ (symb, Qdont_follow)) return IN_DONT_FOLLOW; else if (EQ (symb, Qexcl_unlink)) return IN_EXCL_UNLINK; else if (EQ (symb, Qmask_add)) return IN_MASK_ADD; else if (EQ (symb, Qoneshot)) return IN_ONESHOT; else if (EQ (symb, Qonlydir)) return IN_ONLYDIR; else if (EQ (symb, Qt) || EQ (symb, Qall_events)) return IN_ALL_EVENTS; else { errno = EINVAL; report_file_notify_error ("Unknown aspect", symb); } }