"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/monitor_kqueue.c" (24 Nov 2020, 7639 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "monitor_kqueue.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2017 Gleb Smirnoff <glebius@FreeBSD.org>
    3  * Copyright (c) 2013 Bernard Spil <brnrd@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/stat.h>
   29 #include <sys/event.h>
   30 #include <limits.h>
   31 #include <dirent.h>
   32 #include <errno.h>
   33 #include <stdlib.h>
   34 #include <stdio.h>
   35 #include <stdbool.h>
   36 #include <string.h>
   37 #include <unistd.h>
   38 
   39 #include "event.h"
   40 #include "log.h"
   41 #include "monitor.h"
   42 #include "minidlnatypes.h"
   43 #include "upnpglobalvars.h"
   44 #include "sql.h"
   45 #include "utils.h"
   46 
   47 struct watch {
   48     struct event    ev;
   49     const char  *path;
   50     bool        isdir;
   51 };
   52 
   53 static void
   54 dir_vnode_process(struct event *ev, u_int fflags)
   55 {
   56     struct watch *wt;
   57     const char *path;
   58     char *sql, **result, tmp_path[PATH_MAX], *esc_name;
   59     int rows, result_path_len, i;
   60     DIR* d;
   61     struct dirent *entry;
   62     bool found_flag;
   63 
   64     wt = (struct watch *)ev->data;
   65     path = wt->path;
   66 
   67     if (fflags & NOTE_DELETE) {
   68         DPRINTF(E_DEBUG, L_INOTIFY, "Path [%s] deleted.\n", path);
   69         close(ev->fd);
   70         free(wt);
   71         monitor_remove_directory(0, path);
   72         return;
   73     } else if ((fflags & (NOTE_WRITE | NOTE_LINK)) ==
   74         (NOTE_WRITE | NOTE_LINK)) {
   75 
   76         DPRINTF(E_DEBUG, L_INOTIFY, "Directory [%s] content updated\n",
   77             path);
   78         sql = sqlite3_mprintf("SELECT PATH from DETAILS where "
   79             "(PATH > '%q/' and PATH <= '%q/%c') and SIZE IS NULL",
   80             path, path, 0xFF);
   81         DPRINTF(E_DEBUG, L_INOTIFY, "SQL: %s\n", sql);
   82         if ((sql_get_table(db, sql, &result, &rows, NULL) !=
   83             SQLITE_OK)) {
   84             DPRINTF(E_WARN, L_INOTIFY,
   85                 "Read state [%s]: Query failed\n", path);
   86             goto err1;
   87         }
   88 
   89         for (i = 1; i <= rows; i++) {
   90             DPRINTF(E_DEBUG, L_INOTIFY,
   91                 "Indexed content: %s\n", result[i]);
   92             if (access(result[i], R_OK) == -1)
   93                 monitor_remove_directory(0, result[i]);
   94         }
   95 
   96         if ((d = opendir(path)) == NULL) {
   97             DPRINTF(E_ERROR, L_INOTIFY, "Can't list [%s] (%s)\n",
   98                 path, strerror(errno));
   99             goto err2;
  100         }
  101 
  102         for (entry = readdir(d); entry != NULL; entry = readdir(d)) {
  103             if ((entry->d_type != DT_DIR) ||
  104                 (strcmp(entry->d_name, "..") == 0) ||
  105                 (strcmp(entry->d_name, ".") == 0))
  106                 continue;
  107 
  108             result_path_len = snprintf(tmp_path, PATH_MAX,
  109                 "%s/%s", path, entry->d_name);
  110             if (result_path_len >= PATH_MAX) {
  111                 DPRINTF(E_ERROR, L_INOTIFY,
  112                     "File path too long for %s!",
  113                     entry->d_name);
  114                 continue;
  115             }
  116 
  117             DPRINTF(E_DEBUG, L_INOTIFY, "Walking %s\n", tmp_path);
  118             found_flag = false;
  119             for (i = 1; i <= rows; i++) {
  120                 if (strcmp(result[i], tmp_path) == 0) {
  121                     found_flag = true;
  122                     break;
  123                 }
  124             }
  125             if (!found_flag) {
  126                 esc_name = strdup(entry->d_name);
  127                 if (esc_name == NULL) {
  128                     DPRINTF(E_ERROR, L_INOTIFY,
  129                         "strdup error");
  130                     continue;
  131                 }
  132                 esc_name = modifyString(esc_name, "&", "&amp;amp;", 0);
  133                 monitor_insert_directory(1, esc_name, tmp_path);
  134                 free(esc_name);
  135             }
  136         }
  137     } else if (fflags & NOTE_WRITE) {
  138 
  139         DPRINTF(E_DEBUG, L_INOTIFY, "File [%s] content updated\n",
  140             path);
  141         sql = sqlite3_mprintf("SELECT PATH from DETAILS where "
  142             "(PATH > '%q/' and PATH <= '%q/%c') and SIZE IS NOT NULL",
  143             path, path, 0xFF);
  144         if (sql_get_table(db, sql, &result, &rows, NULL) != SQLITE_OK) {
  145             DPRINTF(E_WARN, L_INOTIFY,
  146                 "Read state [%s]: Query failed\n", path);
  147             goto err1;
  148         }
  149 
  150         for (i = 1; i <= rows; i++) {
  151             DPRINTF(E_DEBUG, L_INOTIFY,
  152                 "Indexed content: %s\n", result[i]);
  153             if (access(result[i], R_OK) == -1)
  154                 monitor_remove_file(result[i]);
  155         }
  156 
  157         if ((d = opendir(path)) == NULL) {
  158             DPRINTF(E_ERROR, L_INOTIFY,
  159                 "Can't list [%s] (%s)\n", path, strerror(errno));
  160             goto err2;
  161         }
  162 
  163         for (entry = readdir(d); entry != NULL; entry = readdir(d)) {
  164             if ((entry->d_type != DT_REG) &&
  165                 (entry->d_type != DT_LNK))
  166                 continue;
  167 
  168             result_path_len = snprintf(tmp_path, PATH_MAX, "%s/%s",
  169                 path, entry->d_name);
  170             if (result_path_len >= PATH_MAX) {
  171                 DPRINTF(E_ERROR, L_INOTIFY,
  172                     "File path too long for %s!",
  173                     entry->d_name);
  174                 continue;
  175             }
  176             DPRINTF(E_DEBUG, L_INOTIFY, "Walking %s\n", tmp_path);
  177             found_flag = false;
  178             for (i = 1; i <= rows; i++)
  179                 if (strcmp(result[i], tmp_path) == 0) {
  180                     found_flag = true;
  181                     break;
  182                 }
  183             if (!found_flag ) {
  184                 struct stat st;
  185 
  186                 if (stat(tmp_path, &st) != 0) {
  187                     DPRINTF(E_ERROR, L_INOTIFY,
  188                         "stat(%s): %s\n", tmp_path,
  189                         strerror(errno));
  190                     continue;
  191                 }
  192                 esc_name = strdup(entry->d_name);
  193                 if (esc_name == NULL) {
  194                     DPRINTF(E_ERROR, L_INOTIFY,
  195                         "strdup error");
  196                     continue;
  197                 }
  198                 esc_name = modifyString(esc_name, "&", "&amp;amp;", 0);
  199                 if (S_ISDIR(st.st_mode))
  200                     monitor_insert_directory(1, esc_name, tmp_path);
  201                 else
  202                     monitor_insert_file(esc_name, tmp_path);
  203                 free(esc_name);
  204             }
  205         }
  206     } else
  207         return;
  208 
  209     closedir(d);
  210 err2:
  211     sqlite3_free_table(result);
  212 err1:
  213     sqlite3_free(sql);
  214 }
  215 
  216 int
  217 add_watch(int fd __unused, const char *path)
  218 {
  219     struct watch *wt;
  220     struct event *ev;
  221     int wd;
  222 
  223     wd = open(path, O_RDONLY);
  224     if (wd < 0) {
  225         DPRINTF(E_ERROR, L_INOTIFY, "open(%s) [%s]\n",
  226             path, strerror(errno));
  227         return (errno);
  228     }
  229 
  230     if ((wt = malloc(sizeof(struct watch))) == NULL) {
  231         DPRINTF(E_ERROR, L_INOTIFY, "malloc() error\n");
  232         close(wd);
  233         return (ENOMEM);
  234     }
  235     if ((wt->path = strdup(path)) == NULL) {
  236         DPRINTF(E_ERROR, L_INOTIFY, "strdup() error\n");
  237         close(wd);
  238         free(wt);
  239         return (ENOMEM);
  240     }
  241     wt->isdir = true;
  242     ev = &wt->ev;
  243     ev->data = wt;
  244     ev->fd = wd;
  245     ev->rdwr = EVENT_VNODE;
  246     ev->process_vnode = dir_vnode_process;
  247 
  248     DPRINTF(E_DEBUG, L_INOTIFY, "kqueue add_watch [%s]\n", path);
  249     event_module.add(ev);
  250 
  251     return (0);
  252 }
  253 
  254 /*
  255  * XXXGL: this function has too much copypaste of inotify_create_watches().
  256  * We need to split out inotify stuff from monitor.c into monitor_inotify.c,
  257  * compile the latter on Linux and this file on FreeBSD, and keep monitor.c
  258  * itself platform independent.
  259  */
  260 void
  261 kqueue_monitor_start()
  262 {
  263     struct media_dir_s *media_path;
  264     char **result;
  265     int rows, i;
  266 
  267     DPRINTF(E_DEBUG, L_INOTIFY, "kqueue monitoring starting\n");
  268     for (media_path = media_dirs; media_path != NULL;
  269         media_path = media_path->next)
  270         add_watch(0, media_path->path);
  271     sql_get_table(db, "SELECT PATH from DETAILS where MIME is NULL and PATH is not NULL", &result, &rows, NULL);
  272     for (i = 1; i <= rows; i++ )
  273         add_watch(0, result[i]);
  274     sqlite3_free_table(result);
  275 }