]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
inotify: register fix and add support for multiple files, fixes #3416
authorJaroslav Kysela <perex@perex.cz>
Sat, 12 Dec 2015 20:12:42 +0000 (21:12 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 12 Dec 2015 20:12:42 +0000 (21:12 +0100)
src/dvr/dvr.h
src/dvr/dvr_inotify.c

index 8dd4d2344d4206ffa776e8837b2681923838c484..f4ec7dec391405b533a095386caebc06e1749364 100644 (file)
@@ -265,13 +265,6 @@ typedef struct dvr_entry {
    */
   profile_chain_t *de_chain;
 
-  /**
-   * Inotify
-   */
-#if ENABLE_INOTIFY
-  LIST_ENTRY(dvr_entry) de_inotify_link;
-#endif
-
   /**
    * Entry change notification timer
    */
index 87ed4b0a4b4039ffadf0fb1db2cee52a0f83b92d..c9ad3682fe77f8160917dfe3f7f9069bcb7bef4b 100644 (file)
@@ -16,7 +16,8 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
+#include "tvheadend.h"
+
 #include <unistd.h>
 #include <assert.h>
 #include <poll.h>
@@ -25,7 +26,6 @@
 #include <sys/inotify.h>
 #include <sys/stat.h>
 
-#include "tvheadend.h"
 #include "redblack.h"
 #include "dvr/dvr.h"
 #include "htsp_server.h"
 static int                         _inot_fd;
 static RB_HEAD(,dvr_inotify_entry) _inot_tree;
 
+typedef struct dvr_inotify_filename
+{
+  dvr_entry_t *de;
+  LIST_ENTRY(dvr_inotify_filename) link;
+} dvr_inotify_filename_t;
+
 typedef struct dvr_inotify_entry
 {
   RB_ENTRY(dvr_inotify_entry) link;
-  char                        *path;
-  int                          fd;
-  struct dvr_entry_list        entries;
+  char *path;
+  int fd;
+  LIST_HEAD(, dvr_inotify_filename) entries;
 } dvr_inotify_entry_t;
 
 static SKEL_DECLARE(dvr_inotify_entry_skel, dvr_inotify_entry_t);
@@ -87,46 +93,73 @@ void dvr_inotify_done ( void )
   SKEL_FREE(dvr_inotify_entry_skel);
 }
 
+/**
+ *
+ */
+static int dvr_inotify_exists ( dvr_inotify_entry_t *die, dvr_entry_t *de )
+{
+  dvr_inotify_filename_t *dif;
+
+  LIST_FOREACH(dif, &die->entries, link)
+    if (dif->de == de)
+      return 1;
+  return 0;
+}
+
 /**
  * Add an entry for monitoring
  */
-void dvr_inotify_add ( dvr_entry_t *de )
+static void dvr_inotify_add_one ( dvr_entry_t *de, htsmsg_t *m )
 {
+  dvr_inotify_filename_t *dif;
   dvr_inotify_entry_t *e;
-  const char *filename = dvr_get_filename(de);
+  const char *filename;
   char *path;
 
-  if (_inot_fd < 0)
-    return;
-
+  filename = htsmsg_get_str(m, "filename");
   if (filename == NULL)
     return;
 
-  path = strdup(filename);
+  path = strdupa(filename);
 
   SKEL_ALLOC(dvr_inotify_entry_skel);
   dvr_inotify_entry_skel->path = dirname(path);
   
   e = RB_INSERT_SORTED(&_inot_tree, dvr_inotify_entry_skel, link, _str_cmp);
-  if (e) {
-    free(path);
-    return;
+  if (!e) {
+    e       = dvr_inotify_entry_skel;
+    SKEL_USED(dvr_inotify_entry_skel);
+    e->path = strdup(e->path);
+    e->fd   = inotify_add_watch(_inot_fd, e->path, EVENT_MASK);
   }
 
-  e       = dvr_inotify_entry_skel;
-  SKEL_USED(dvr_inotify_entry_skel);
-  e->path = strdup(e->path);
-  e->fd   = inotify_add_watch(_inot_fd, e->path, EVENT_MASK);
+  if (!dvr_inotify_exists(e, de)) {
 
-  LIST_INSERT_HEAD(&e->entries, de, de_inotify_link);
+    dif = malloc(sizeof(*dif));
+    dif->de = de;
+
+    LIST_INSERT_HEAD(&e->entries, dif, link);
+
+    if (e->fd < 0) {
+      tvhlog(LOG_ERR, "dvr", "failed to add inotify watch to %s (err=%s)",
+             e->path, strerror(errno));
+      dvr_inotify_del(de);
+    }
 
-  if (e->fd < 0) {
-    tvhlog(LOG_ERR, "dvr", "failed to add inotify watch to %s (err=%s)",
-           e->path, strerror(errno));
-    dvr_inotify_del(de);
   }
+}
+
+void dvr_inotify_add ( dvr_entry_t *de )
+{
+  htsmsg_field_t *f;
+  htsmsg_t *m;
 
-  free(path);
+  if (_inot_fd < 0)
+    return;
+
+  HTSMSG_FOREACH(f, de->de_files)
+    if ((m = htsmsg_field_get_map(f)) != NULL)
+      dvr_inotify_add_one(de, m);
 }
 
 /*
@@ -134,23 +167,25 @@ void dvr_inotify_add ( dvr_entry_t *de )
  */
 void dvr_inotify_del ( dvr_entry_t *de )
 {
-  dvr_entry_t *det = NULL;
-  dvr_inotify_entry_t *e;
+  dvr_inotify_filename_t *f = NULL, *f_next;
+  dvr_inotify_entry_t *e, *e_next;
   lock_assert(&global_lock);
-  RB_FOREACH(e, &_inot_tree, link) {
-    LIST_FOREACH(det, &e->entries, de_inotify_link)
-      if (det == de) break;
-    if (det) break;
-  }
 
-  if (e && det) {
-    LIST_REMOVE(det, de_inotify_link);
-    if (LIST_FIRST(&e->entries) == NULL) {
-      RB_REMOVE(&_inot_tree, e, link);
-      if (e->fd >= 0)
-        inotify_rm_watch(_inot_fd, e->fd);
-      free(e->path);
-      free(e);
+  for (e = RB_FIRST(&_inot_tree); e; e = e_next) {
+    e_next = RB_NEXT(e, link);
+    for (f = LIST_FIRST(&e->entries); f; f = f_next) {
+      f_next = LIST_NEXT(f, link);
+      if (f->de == de) {
+        LIST_REMOVE(f, link);
+        free(f);
+        if (LIST_FIRST(&e->entries) == NULL) {
+          RB_REMOVE(&_inot_tree, e, link);
+          if (e->fd >= 0)
+            inotify_rm_watch(_inot_fd, e->fd);
+          free(e->path);
+          free(e);
+        }
+      }
     }
   }
 }
@@ -160,12 +195,12 @@ void dvr_inotify_del ( dvr_entry_t *de )
  */
 int dvr_inotify_count ( void )
 {
-  dvr_entry_t *det = NULL;
+  dvr_inotify_filename_t *f;
   dvr_inotify_entry_t *e;
   int count = 0;
   lock_assert(&global_lock);
   RB_FOREACH(e, &_inot_tree, link)
-    LIST_FOREACH(det, &e->entries, de_inotify_link)
+    LIST_FOREACH(f, &e->entries, link)
       count++;
   return count;
 }
@@ -191,6 +226,7 @@ static void
 _dvr_inotify_moved
   ( int fd, const char *from, const char *to )
 {
+  dvr_inotify_filename_t *dif;
   dvr_inotify_entry_t *die;
   dvr_entry_t *de;
   char path[PATH_MAX];
@@ -203,7 +239,8 @@ _dvr_inotify_moved
 
   snprintf(path, sizeof(path), "%s/%s", die->path, from);
 
-  LIST_FOREACH(de, &die->entries, de_inotify_link) {
+  LIST_FOREACH(dif, &die->entries, link) {
+    de = dif->de;
     if (de->de_files == NULL)
       continue;
     HTSMSG_FOREACH(f, de->de_files)
@@ -216,7 +253,7 @@ _dvr_inotify_moved
       break;
   }
 
-  if (!de)
+  if (!dif)
     return;
 
   if (f && m) {
@@ -253,13 +290,15 @@ static void
 _dvr_inotify_moved_all
   ( int fd, const char *to )
 {
-  dvr_entry_t *de;
+  dvr_inotify_filename_t *f;
   dvr_inotify_entry_t *die;
+  dvr_entry_t *de;
   
   if (!(die = _dvr_inotify_find(fd)))
     return;
 
-  while ((de = LIST_FIRST(&die->entries))) {
+  while ((f = LIST_FIRST(&die->entries))) {
+    de = f->de;
     htsp_dvr_entry_update(de);
     idnode_notify_changed(&de->de_id);
     dvr_inotify_del(de);