]> code.delx.au - gnu-emacs/blobdiff - src/inotify.c
Remove buggy non-native image scrolling
[gnu-emacs] / src / inotify.c
index 4efef9e55b7c0399e63edff86abf5e8ebb4983b2..38c8df5a29a29531bace4e98f07c54b950228a6d 100644 (file)
@@ -1,13 +1,13 @@
 /* Inotify support for Emacs
 
-Copyright (C) 2012-2013 Free Software Foundation, Inc.
+Copyright (C) 2012-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,38 +25,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "process.h"
 #include "keyboard.h"
-#include "character.h"
-#include "frame.h" /* Required for termhooks.h.  */
 #include "termhooks.h"
 
-static Lisp_Object Qaccess;        /* IN_ACCESS */
-static Lisp_Object Qattrib;        /* IN_ATTRIB */
-static Lisp_Object Qclose_write;   /* IN_CLOSE_WRITE */
-static Lisp_Object Qclose_nowrite; /* IN_CLOSE_NOWRITE */
-static Lisp_Object Qcreate;        /* IN_CREATE */
-static Lisp_Object Qdelete;        /* IN_DELETE */
-static Lisp_Object Qdelete_self;   /* IN_DELETE_SELF */
-static Lisp_Object Qmodify;        /* IN_MODIFY */
-static Lisp_Object Qmove_self;     /* IN_MOVE_SELF */
-static Lisp_Object Qmoved_from;    /* IN_MOVED_FROM */
-static Lisp_Object Qmoved_to;      /* IN_MOVED_TO */
-static Lisp_Object Qopen;          /* IN_OPEN */
-
-static Lisp_Object Qall_events;    /* IN_ALL_EVENTS */
-static Lisp_Object Qmove;          /* IN_MOVE */
-static Lisp_Object Qclose;         /* IN_CLOSE */
-
-static Lisp_Object Qdont_follow;   /* IN_DONT_FOLLOW */
-static Lisp_Object Qexcl_unlink;   /* IN_EXCL_UNLINK */
-static Lisp_Object Qmask_add;      /* IN_MASK_ADD */
-static Lisp_Object Qoneshot;       /* IN_ONESHOT */
-static Lisp_Object Qonlydir;       /* IN_ONLYDIR */
-
-static Lisp_Object Qignored;       /* IN_IGNORED */
-static Lisp_Object Qisdir;         /* IN_ISDIR */
-static Lisp_Object Qq_overflow;    /* IN_Q_OVERFLOW */
-static Lisp_Object Qunmount;       /* IN_UNMOUNT */
-
+#include <errno.h>
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 
@@ -71,13 +42,11 @@ static Lisp_Object Qunmount;       /* IN_UNMOUNT */
 # define IN_ONLYDIR 0
 #endif
 
-enum { uninitialized = -100 };
 /* File handle for inotify.  */
-static int inotifyfd = uninitialized;
+static int inotifyfd = -1;
 
 /* Assoc list of files being watched.
-   Format:
-   (watch-descriptor . callback)
+   Format: (watch-descriptor name callback)
  */
 static Lisp_Object watch_list;
 
@@ -136,12 +105,14 @@ inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev)
       name = make_unibyte_string (ev->name, min (len, ev->len));
       name = DECODE_FILE (name);
     }
+  else
+    name = XCAR (XCDR (watch_object));
 
   return list2 (list4 (make_watch_descriptor (ev->wd),
                        mask_to_aspects (ev->mask),
-                       make_number (ev->cookie),
-                       name),
-                XCDR (watch_object));
+                       name,
+                       make_number (ev->cookie)),
+               Fnth (make_number (2), watch_object));
 }
 
 /* This callback is called when the FD is available for read.  The inotify
@@ -158,15 +129,14 @@ inotify_callback (int fd, void *_)
 
   to_read = 0;
   if (ioctl (fd, FIONREAD, &to_read) == -1)
-    report_file_error ("Error while trying to retrieve file system events",
-                       Qnil);
+    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_error ("Error while trying to read file system events",
-                         Qnil);
+      report_file_notify_error ("Error while reading file system events", Qnil);
     }
 
   EVENT_INIT (event);
@@ -242,7 +212,10 @@ symbol_to_inotifymask (Lisp_Object symb)
   else if (EQ (symb, Qt) || EQ (symb, Qall_events))
     return IN_ALL_EVENTS;
   else
-    signal_error ("Unknown aspect", symb);
+    {
+      errno = EINVAL;
+      report_file_notify_error ("Unknown aspect", symb);
+    }
 }
 
 static uint32_t
@@ -266,8 +239,10 @@ aspect_to_inotifymask (Lisp_Object aspect)
 DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0,
        doc: /* Add a watch for FILE-NAME to inotify.
 
-A WATCH-DESCRIPTOR is returned on success.  ASPECT might be one of the following
-symbols or a list of those symbols:
+Return a watch descriptor.  The watch will look for ASPECT events and
+invoke CALLBACK when an event occurs.
+
+ASPECT might be one of the following symbols or a list of those symbols:
 
 access
 attrib
@@ -286,7 +261,7 @@ all-events or t
 move
 close
 
-The following symbols can also be added to a list of aspects
+The following symbols can also be added to a list of aspects:
 
 dont-follow
 excl-unlink
@@ -294,11 +269,10 @@ mask-add
 oneshot
 onlydir
 
-Watching a directory is not recursive.  CALLBACK gets called in case of an
-event.  It gets passed a single argument EVENT which contains an event structure
-of the format
+Watching a directory is not recursive.  CALLBACK is passed a single argument
+EVENT which contains an event structure of the format
 
-(WATCH-DESCRIPTOR ASPECTS COOKIE NAME)
+\(WATCH-DESCRIPTOR ASPECTS NAME COOKIE)
 
 WATCH-DESCRIPTOR is the same object that was returned by this function.  It can
 be tested for equality using `equal'.  ASPECTS describes the event.  It is a
@@ -310,11 +284,11 @@ isdir
 q-overflow
 unmount
 
+If a directory is watched then NAME is the name of file that caused the event.
+
 COOKIE is an object that can be compared using `equal' to identify two matching
 renames (moved-from and moved-to).
 
-If a directory is watched then NAME is the name of file that caused the event.
-
 See inotify(7) and inotify_add_watch(2) for further information.  The inotify fd
 is managed internally and there is no corresponding inotify_init.  Use
 `inotify-rm-watch' to remove a watch.
@@ -329,15 +303,11 @@ is managed internally and there is no corresponding inotify_init.  Use
 
   CHECK_STRING (file_name);
 
-  if (inotifyfd == uninitialized)
+  if (inotifyfd < 0)
     {
       inotifyfd = inotify_init1 (IN_NONBLOCK|IN_CLOEXEC);
-      if (inotifyfd == -1)
-        {
-          inotifyfd = uninitialized;
-          report_file_error ("File watching feature (inotify) is not available",
-                             Qnil);
-        }
+      if (inotifyfd < 0)
+       report_file_notify_error ("File watching is not available", Qnil);
       watch_list = Qnil;
       add_read_fd (inotifyfd, &inotify_callback, NULL);
     }
@@ -346,17 +316,17 @@ is managed internally and there is no corresponding inotify_init.  Use
   encoded_file_name = ENCODE_FILE (file_name);
   watchdesc = inotify_add_watch (inotifyfd, SSDATA (encoded_file_name), mask);
   if (watchdesc == -1)
-    report_file_error ("Could not add watch for file", Fcons (file_name, Qnil));
+    report_file_notify_error ("Could not add watch for file", file_name);
 
   watch_descriptor = make_watch_descriptor (watchdesc);
 
-  /* Delete existing watch object. */
+  /* Delete existing watch object.  */
   watch_object = Fassoc (watch_descriptor, watch_list);
   if (!NILP (watch_object))
       watch_list = Fdelete (watch_object, watch_list);
 
-  /* Store watch object in watch list. */
-  watch_object = Fcons (watch_descriptor, callback);
+  /* Store watch object in watch list.  */
+  watch_object = list3 (watch_descriptor, encoded_file_name, callback);
   watch_list = Fcons (watch_object, watch_list);
 
   return watch_descriptor;
@@ -375,58 +345,74 @@ See inotify_rm_watch(2) for more information.
   int wd = XINT (watch_descriptor);
 
   if (inotify_rm_watch (inotifyfd, wd) == -1)
-    report_file_error ("Could not rm watch", Fcons (watch_descriptor,
-                                                    Qnil));
+    report_file_notify_error ("Could not rm watch", watch_descriptor);
 
-  /* Remove watch descriptor from watch list. */
+  /* Remove watch descriptor from watch list.  */
   watch_object = Fassoc (watch_descriptor, watch_list);
   if (!NILP (watch_object))
     watch_list = Fdelete (watch_object, watch_list);
 
-  /* Cleanup if no more files are watched. */
+  /* Cleanup if no more files are watched.  */
   if (NILP (watch_list))
     {
-      close (inotifyfd);
+      emacs_close (inotifyfd);
       delete_read_fd (inotifyfd);
-      inotifyfd = uninitialized;
+      inotifyfd = -1;
     }
 
   return Qt;
 }
 
+DEFUN ("inotify-valid-p", Finotify_valid_p, Sinotify_valid_p, 1, 1, 0,
+       doc: /* "Check a watch specified by its WATCH-DESCRIPTOR.
+
+WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'.
+
+A watch can become invalid if the file or directory it watches is
+deleted, or if the watcher thread exits abnormally for any other
+reason.  Removing the watch by calling `inotify-rm-watch' also makes
+it invalid.  */)
+     (Lisp_Object watch_descriptor)
+{
+  Lisp_Object watch_object = Fassoc (watch_descriptor, watch_list);
+  return NILP (watch_object) ? Qnil : Qt;
+}
+
 void
 syms_of_inotify (void)
 {
-  DEFSYM (Qaccess, "access");
-  DEFSYM (Qattrib, "attrib");
-  DEFSYM (Qclose_write, "close-write");
+  DEFSYM (Qaccess, "access");          /* IN_ACCESS */
+  DEFSYM (Qattrib, "attrib");          /* IN_ATTRIB */
+  DEFSYM (Qclose_write, "close-write");        /* IN_CLOSE_WRITE */
   DEFSYM (Qclose_nowrite, "close-nowrite");
-  DEFSYM (Qcreate, "create");
-  DEFSYM (Qdelete, "delete");
-  DEFSYM (Qdelete_self, "delete-self");
-  DEFSYM (Qmodify, "modify");
-  DEFSYM (Qmove_self, "move-self");
-  DEFSYM (Qmoved_from, "moved-from");
-  DEFSYM (Qmoved_to, "moved-to");
-  DEFSYM (Qopen, "open");
-
-  DEFSYM (Qall_events, "all-events");
-  DEFSYM (Qmove, "move");
-  DEFSYM (Qclose, "close");
-
-  DEFSYM (Qdont_follow, "dont-follow");
-  DEFSYM (Qexcl_unlink, "excl-unlink");
-  DEFSYM (Qmask_add, "mask-add");
-  DEFSYM (Qoneshot, "oneshot");
-  DEFSYM (Qonlydir, "onlydir");
-
-  DEFSYM (Qignored, "ignored");
-  DEFSYM (Qisdir, "isdir");
-  DEFSYM (Qq_overflow, "q-overflow");
-  DEFSYM (Qunmount, "unmount");
+                                       /* IN_CLOSE_NOWRITE */
+  DEFSYM (Qcreate, "create");          /* IN_CREATE */
+  DEFSYM (Qdelete, "delete");          /* IN_DELETE */
+  DEFSYM (Qdelete_self, "delete-self");        /* IN_DELETE_SELF */
+  DEFSYM (Qmodify, "modify");          /* IN_MODIFY */
+  DEFSYM (Qmove_self, "move-self");    /* IN_MOVE_SELF */
+  DEFSYM (Qmoved_from, "moved-from");  /* IN_MOVED_FROM */
+  DEFSYM (Qmoved_to, "moved-to");      /* IN_MOVED_TO */
+  DEFSYM (Qopen, "open");              /* IN_OPEN */
+
+  DEFSYM (Qall_events, "all-events");  /* IN_ALL_EVENTS */
+  DEFSYM (Qmove, "move");              /* IN_MOVE */
+  DEFSYM (Qclose, "close");            /* IN_CLOSE */
+
+  DEFSYM (Qdont_follow, "dont-follow");        /* IN_DONT_FOLLOW */
+  DEFSYM (Qexcl_unlink, "excl-unlink");        /* IN_EXCL_UNLINK */
+  DEFSYM (Qmask_add, "mask-add");      /* IN_MASK_ADD */
+  DEFSYM (Qoneshot, "oneshot");                /* IN_ONESHOT */
+  DEFSYM (Qonlydir, "onlydir");                /* IN_ONLYDIR */
+
+  DEFSYM (Qignored, "ignored");                /* IN_IGNORED */
+  DEFSYM (Qisdir, "isdir");            /* IN_ISDIR */
+  DEFSYM (Qq_overflow, "q-overflow");  /* IN_Q_OVERFLOW */
+  DEFSYM (Qunmount, "unmount");                /* IN_UNMOUNT */
 
   defsubr (&Sinotify_add_watch);
   defsubr (&Sinotify_rm_watch);
+  defsubr (&Sinotify_valid_p);
 
   staticpro (&watch_list);