]> code.delx.au - gnu-emacs/blobdiff - src/gfilenotify.c
Handle NULL pointers in w32heap.c allocation routines
[gnu-emacs] / src / gfilenotify.c
index 4ccc430d815d1459d80fa2821941036c1d043725..08713a8fce3dc50385502b30daec63ed5676fd86 100644 (file)
@@ -1,5 +1,5 @@
 /* Filesystem notifications support with glib API.
-   Copyright (C) 2013 Free Software Foundation, Inc.
+   Copyright (C) 2013-2015 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,37 +29,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "process.h"
 
 \f
-/* Subroutines.  */
-static Lisp_Object Qgfile_add_watch;
-static Lisp_Object Qgfile_rm_watch;
-
-/* Filter objects.  */
-static Lisp_Object Qwatch_mounts;      /* G_FILE_MONITOR_WATCH_MOUNTS  */
-static Lisp_Object Qsend_moved;        /* G_FILE_MONITOR_SEND_MOVED  */
-
-/* Event types.  */
-static Lisp_Object Qchanged;           /* G_FILE_MONITOR_EVENT_CHANGED  */
-static Lisp_Object Qchanges_done_hint; /* G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT  */
-static Lisp_Object Qdeleted;           /* G_FILE_MONITOR_EVENT_DELETED  */
-static Lisp_Object Qcreated;           /* G_FILE_MONITOR_EVENT_CREATED  */
-static Lisp_Object Qattribute_changed; /* G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED  */
-static Lisp_Object Qpre_unmount;       /* G_FILE_MONITOR_EVENT_PRE_UNMOUNT  */
-static Lisp_Object Qunmounted;         /* G_FILE_MONITOR_EVENT_UNMOUNTED  */
-static Lisp_Object Qmoved;             /* G_FILE_MONITOR_EVENT_MOVED  */
-
 static Lisp_Object watch_list;
 
 /* This is the callback function for arriving signals from
    g_file_monitor.  It shall create a Lisp event, and put it into
    Emacs input queue.  */
 static gboolean
-dir_monitor_callback (GFileMonitormonitor,
-                     GFilefile,
-                     GFileother_file,
+dir_monitor_callback (GFileMonitor *monitor,
+                     GFile *file,
+                     GFile *other_file,
                      GFileMonitorEvent event_type,
                      gpointer user_data)
 {
-  Lisp_Object symbol, watch_object;
+  Lisp_Object symbol, monitor_object, watch_object;
   char *name = g_file_get_parse_name (file);
   char *oname = other_file ? g_file_get_parse_name (other_file) : NULL;
 
@@ -95,21 +77,23 @@ dir_monitor_callback (GFileMonitor* monitor,
     }
 
   /* Determine callback function.  */
-  watch_object = Fassoc (XIL ((EMACS_INT) monitor), watch_list);
+  monitor_object = make_pointer_integer (monitor);
+  eassert (INTEGERP (monitor_object));
+  watch_object = assq_no_quit (monitor_object, watch_list);
 
-  if (FUNCTIONP (CDR_SAFE (watch_object)))
+  if (CONSP (watch_object))
     {
       /* Construct an event.  */
       struct input_event event;
+      Lisp_Object otail = oname ? list1 (build_string (oname)) : Qnil;
       EVENT_INIT (event);
       event.kind = FILE_NOTIFY_EVENT;
       event.frame_or_window = Qnil;
-      event.arg = oname
-       ? list2 (list4 (XIL ((EMACS_INT) monitor), symbol,
-                       build_string (name), build_string (oname)),
-                CDR_SAFE (watch_object))
-       : list2 (list3 (XIL ((EMACS_INT) monitor), symbol, build_string (name)),
-                CDR_SAFE (watch_object));
+      event.arg = list2 (Fcons (monitor_object,
+                               Fcons (symbol,
+                                      Fcons (build_string (name),
+                                             otail))),
+                        XCDR (watch_object));
 
       /* Store it into the input event queue.  */
       kbd_buffer_store_event (&event);
@@ -130,15 +114,14 @@ This arranges for filesystem events pertaining to FILE to be reported
 to Emacs.  Use `gfile-rm-watch' to cancel the watch.
 
 Value is a descriptor for the added watch.  If the file cannot be
-watched for some reason, this function signals a `file-error' error.
+watched for some reason, this function signals a `file-notify-error' error.
 
 FLAGS is a list of conditions to set what will be watched for.  It can
 include the following symbols:
 
   'watch-mounts' -- watch for mount events
   'send-moved'   -- pair 'deleted' and 'created' events caused by file
-                    renames (moves) and send a single 'event-moved'
-                    event instead
+                    renames and send a single 'renamed' event instead
 
 When any event happens, Emacs will call the CALLBACK function passing
 it a single argument EVENT, which is of the form
@@ -163,16 +146,16 @@ FILE is the name of the file whose event is being reported.  FILE1
 will be reported only in case of the 'moved' event.  */)
   (Lisp_Object file, Lisp_Object flags, Lisp_Object callback)
 {
-  Lisp_Object watch_descriptor, watch_object;
+  Lisp_Object watch_object;
   GFile *gfile;
-  GFileMonitormonitor;
+  GFileMonitor *monitor;
   GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
 
   /* Check parameters.  */
   CHECK_STRING (file);
   file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
   if (NILP (Ffile_exists_p (file)))
-    report_file_error ("File does not exists", Fcons (file, Qnil));
+    report_file_error ("File does not exist", file);
 
   CHECK_LIST (flags);
 
@@ -190,14 +173,23 @@ will be reported only in case of the 'moved' event.  */)
 
   /* Enable watch.  */
   monitor = g_file_monitor (gfile, gflags, NULL, NULL);
-  if (monitor != NULL)
-    g_signal_connect (monitor, "changed",
-                     (GCallback) dir_monitor_callback, NULL);
-  else
-    report_file_error ("Cannot watch file", Fcons (file, Qnil));
+  if (! monitor)
+    xsignal2 (Qfile_notify_error, build_string ("Cannot watch file"), file);
+
+  Lisp_Object watch_descriptor = make_pointer_integer (monitor);
+
+  /* Check the dicey assumption that make_pointer_integer is safe.  */
+  if (! INTEGERP (watch_descriptor))
+    {
+      g_object_unref (monitor);
+      xsignal2 (Qfile_notify_error, build_string ("Unsupported file watcher"),
+               file);
+    }
+
+  g_signal_connect (monitor, "changed",
+                   (GCallback) dir_monitor_callback, NULL);
 
   /* Store watch object in watch list.  */
-  watch_descriptor = XIL ((EMACS_INT) monitor);
   watch_object = Fcons (watch_descriptor, callback);
   watch_list = Fcons (watch_object, watch_list);
 
@@ -210,20 +202,20 @@ DEFUN ("gfile-rm-watch", Fgfile_rm_watch, Sgfile_rm_watch, 1, 1, 0,
 WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.  */)
      (Lisp_Object watch_descriptor)
 {
-  Lisp_Object watch_object;
-  GFileMonitor *monitor = (GFileMonitor *) XLI (watch_descriptor);
+  Lisp_Object watch_object = assq_no_quit (watch_descriptor, watch_list);
 
-  watch_object = Fassoc (watch_descriptor, watch_list);
-  if (NILP (watch_object))
-    report_file_error ("Not a watch descriptor",
-                      Fcons (watch_descriptor, Qnil));
+  if (! CONSP (watch_object))
+    xsignal2 (Qfile_notify_error, build_string ("Not a watch descriptor"),
+             watch_descriptor);
 
+  eassert (INTEGERP (watch_descriptor));
+  GFileMonitor *monitor = XINTPTR (watch_descriptor);
   if (!g_file_monitor_cancel (monitor))
-    report_file_error ("Could not rm watch",
-                      Fcons (watch_descriptor, Qnil));
+    xsignal2 (Qfile_notify_error, build_string ("Could not rm watch"),
+             watch_descriptor);
 
   /* Remove watch descriptor from watch list. */
-  watch_list = Fdelete (watch_object, watch_list);
+  watch_list = Fdelq (watch_object, watch_list);
 
   /* Cleanup.  */
   g_object_unref (monitor);
@@ -233,30 +225,36 @@ WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.  */)
 
 \f
 void
-syms_of_gfilenotify (void)
+globals_of_gfilenotify (void)
 {
-
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
   g_type_init ();
+#endif
+  watch_list = Qnil;
+}
 
-  DEFSYM (Qgfile_add_watch, "gfile-add-watch");
+void
+syms_of_gfilenotify (void)
+{
   defsubr (&Sgfile_add_watch);
-
-  DEFSYM (Qgfile_rm_watch, "gfile-rm-watch");
   defsubr (&Sgfile_rm_watch);
 
-  DEFSYM (Qwatch_mounts, "watch-mounts");
-  DEFSYM (Qsend_moved, "send-moved");
-  DEFSYM (Qchanged, "changed");
+  /* Filter objects.  */
+  DEFSYM (Qwatch_mounts, "watch-mounts"); /* G_FILE_MONITOR_WATCH_MOUNTS  */
+  DEFSYM (Qsend_moved, "send-moved");  /* G_FILE_MONITOR_SEND_MOVED  */
+
+  /* Event types.  */
+  DEFSYM (Qchanged, "changed");        /* G_FILE_MONITOR_EVENT_CHANGED  */
   DEFSYM (Qchanges_done_hint, "changes-done-hint");
-  DEFSYM (Qdeleted, "deleted");
-  DEFSYM (Qcreated, "created");
+                               /* G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT  */
+  DEFSYM (Qdeleted, "deleted");        /* G_FILE_MONITOR_EVENT_DELETED  */
+  DEFSYM (Qcreated, "created");        /* G_FILE_MONITOR_EVENT_CREATED  */
   DEFSYM (Qattribute_changed, "attribute-changed");
-  DEFSYM (Qpre_unmount, "pre-unmount");
-  DEFSYM (Qunmounted, "unmounted");
-  DEFSYM (Qmoved, "moved");
+                               /* G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED  */
+  DEFSYM (Qpre_unmount, "pre-unmount");        /* G_FILE_MONITOR_EVENT_PRE_UNMOUNT  */
+  DEFSYM (Qunmounted, "unmounted");    /* G_FILE_MONITOR_EVENT_UNMOUNTED  */
+  DEFSYM (Qmoved, "moved");    /* G_FILE_MONITOR_EVENT_MOVED  */
 
-  /* Initialize internal objects.  */
-  watch_list = Qnil;
   staticpro (&watch_list);
 
   Fprovide (intern_c_string ("gfilenotify"), Qnil);