"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/monitor.c" (24 Nov 2020, 18786 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.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

    1 /* MiniDLNA media server
    2  * Copyright (C) 2008-2010  Justin Maggard
    3  *
    4  * This file is part of MiniDLNA.
    5  *
    6  * MiniDLNA is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License version 2 as
    8  * published by the Free Software Foundation.
    9  *
   10  * MiniDLNA is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
   17  */
   18 #include "config.h"
   19 
   20 #include <stdio.h>
   21 #include <string.h>
   22 #include <stdbool.h>
   23 #include <stdlib.h>
   24 #include <errno.h>
   25 #include <unistd.h>
   26 #include <dirent.h>
   27 #include <libgen.h>
   28 #include <signal.h>
   29 #include <errno.h>
   30 #include <sys/types.h>
   31 #include <sys/stat.h>
   32 #include <sys/time.h>
   33 #ifdef HAVE_INOTIFY
   34 #include <sys/resource.h>
   35 #include <poll.h>
   36 #ifdef HAVE_SYS_INOTIFY_H
   37 #include <sys/inotify.h>
   38 #else
   39 #include "linux/inotify.h"
   40 #include "linux/inotify-syscalls.h"
   41 #endif
   42 #endif
   43 #include "libav.h"
   44 
   45 #include "upnpglobalvars.h"
   46 #include "monitor.h"
   47 #include "utils.h"
   48 #include "sql.h"
   49 #include "scanner.h"
   50 #include "metadata.h"
   51 #include "albumart.h"
   52 #include "playlist.h"
   53 #include "log.h"
   54 
   55 static time_t next_pl_fill = 0;
   56 
   57 #ifdef HAVE_INOTIFY
   58 #define EVENT_SIZE  ( sizeof (struct inotify_event) )
   59 #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
   60 #define DESIRED_WATCH_LIMIT 65536
   61 
   62 #define PATH_BUF_SIZE PATH_MAX
   63 
   64 struct watch
   65 {
   66     int wd;     /* watch descriptor */
   67     char *path; /* watched path */
   68     struct watch *next;
   69 };
   70 
   71 static struct watch *watches;
   72 static struct watch *lastwatch = NULL;
   73 
   74 static char *
   75 get_path_from_wd(int wd)
   76 {
   77     struct watch *w = watches;
   78 
   79     while( w != NULL )
   80     {
   81         if( w->wd == wd )
   82             return w->path;
   83         w = w->next;
   84     }
   85 
   86     return NULL;
   87 }
   88 
   89 static unsigned int
   90 next_highest(unsigned int num)
   91 {
   92     num |= num >> 1;
   93     num |= num >> 2;
   94     num |= num >> 4;
   95     num |= num >> 8;
   96     num |= num >> 16;
   97     return ++num;
   98 }
   99 
  100 static void
  101 raise_watch_limit(unsigned int limit)
  102 {
  103     FILE *max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r+");
  104     if (!max_watches)
  105         return;
  106     if (!limit)
  107     {
  108         if (fscanf(max_watches, "%10u", &limit) < 1)
  109             limit = 8192;
  110         rewind(max_watches);
  111     }
  112     fprintf(max_watches, "%u", next_highest(limit));
  113     fclose(max_watches);
  114 }
  115 
  116 int
  117 add_watch(int fd, const char * path)
  118 {
  119     struct watch *nw;
  120     int wd;
  121 
  122     wd = inotify_add_watch(fd, path, IN_CREATE|IN_CLOSE_WRITE|IN_DELETE|IN_MOVE);
  123     if( wd < 0 && errno == ENOSPC)
  124     {
  125         raise_watch_limit(0);
  126         wd = inotify_add_watch(fd, path, IN_CREATE|IN_CLOSE_WRITE|IN_DELETE|IN_MOVE);
  127     }
  128     if( wd < 0 )
  129     {
  130         DPRINTF(E_ERROR, L_INOTIFY, "inotify_add_watch(%s) [%s]\n", path, strerror(errno));
  131         return (errno);
  132     }
  133 
  134     nw = malloc(sizeof(struct watch));
  135     if( nw == NULL )
  136     {
  137         DPRINTF(E_ERROR, L_INOTIFY, "malloc() error\n");
  138         return (ENOMEM);
  139     }
  140     nw->wd = wd;
  141     nw->next = NULL;
  142     nw->path = strdup(path);
  143 
  144     if( watches == NULL )
  145     {
  146         watches = nw;
  147     }
  148 
  149     if( lastwatch != NULL )
  150     {
  151         lastwatch->next = nw;
  152     }
  153     lastwatch = nw;
  154 
  155     DPRINTF(E_INFO, L_INOTIFY, "Added watch to %s [%d]\n", path, wd);
  156     return (0);
  157 }
  158 
  159 static int
  160 remove_watch(int fd, const char * path)
  161 {
  162     struct watch *w;
  163 
  164     for( w = watches; w; w = w->next )
  165     {
  166         if( strcmp(path, w->path) == 0 )
  167             return(inotify_rm_watch(fd, w->wd));
  168     }
  169 
  170     return 1;
  171 }
  172 
  173 static int
  174 inotify_create_watches(int fd)
  175 {
  176     FILE * max_watches;
  177     unsigned int num_watches = 0, watch_limit;
  178     char **result;
  179     int i, rows = 0;
  180     struct media_dir_s * media_path;
  181 
  182     for( media_path = media_dirs; media_path != NULL; media_path = media_path->next )
  183     {
  184         DPRINTF(E_DEBUG, L_INOTIFY, "Add watch to %s\n", media_path->path);
  185         add_watch(fd, media_path->path);
  186         num_watches++;
  187     }
  188     sql_get_table(db, "SELECT PATH from DETAILS where MIME is NULL and PATH is not NULL", &result, &rows, NULL);
  189     for( i=1; i <= rows; i++ )
  190     {
  191         DPRINTF(E_DEBUG, L_INOTIFY, "Add watch to %s\n", result[i]);
  192         add_watch(fd, result[i]);
  193         num_watches++;
  194     }
  195     sqlite3_free_table(result);
  196         
  197     max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r");
  198     if( max_watches )
  199     {
  200         if( fscanf(max_watches, "%10u", &watch_limit) < 1 )
  201             watch_limit = 8192;
  202         fclose(max_watches);
  203         if( (watch_limit < DESIRED_WATCH_LIMIT) || (watch_limit < (num_watches*4/3)) )
  204         {
  205             if (access("/proc/sys/fs/inotify/max_user_watches", W_OK) == 0)
  206             {
  207                 if( DESIRED_WATCH_LIMIT >= (num_watches*3/4) )
  208                 {
  209                     raise_watch_limit(8191U);
  210                 }
  211                 else if( next_highest(num_watches) >= (num_watches*3/4) )
  212                 {
  213                     raise_watch_limit(num_watches);
  214                 }
  215                 else
  216                 {
  217                     raise_watch_limit(next_highest(num_watches));
  218                 }
  219             }
  220             else
  221             {
  222                 DPRINTF(E_WARN, L_INOTIFY, "WARNING: Inotify max_user_watches [%u] is low or close to the number of used watches [%u] "
  223                                         "and I do not have permission to increase this limit.  Please do so manually by "
  224                                         "writing a higher value into /proc/sys/fs/inotify/max_user_watches.\n", watch_limit, num_watches);
  225             }
  226         }
  227     }
  228     else
  229     {
  230         DPRINTF(E_WARN, L_INOTIFY, "WARNING: Could not read inotify max_user_watches!  "
  231                                 "Hopefully it is enough to cover %u current directories plus any new ones added.\n", num_watches);
  232     }
  233 
  234     return rows;
  235 }
  236 
  237 static int
  238 inotify_remove_watches(int fd)
  239 {
  240     struct watch *w = watches;
  241     struct watch *last_w;
  242     int rm_watches = 0;
  243 
  244     while( w )
  245     {
  246         last_w = w;
  247         inotify_rm_watch(fd, w->wd);
  248         free(w->path);
  249         rm_watches++;
  250         w = w->next;
  251         free(last_w);
  252     }
  253 
  254     return rm_watches;
  255 }
  256 #endif
  257 
  258 int
  259 monitor_remove_file(const char * path)
  260 {
  261     char sql[128];
  262     char art_cache[PATH_MAX];
  263     char *id;
  264     char *ptr;
  265     char **result;
  266     int64_t detailID;
  267     int rows, playlist;
  268 
  269     if( is_caption(path) )
  270     {
  271         return sql_exec(db, "DELETE from CAPTIONS where PATH = '%q'", path);
  272     }
  273     /* Invalidate the scanner cache so we don't insert files into non-existent containers */
  274     valid_cache = 0;
  275     playlist = is_playlist(path);
  276     id = sql_get_text_field(db, "SELECT ID from %s where PATH = '%q'", playlist?"PLAYLISTS":"DETAILS", path);
  277     if( !id )
  278         return 1;
  279     detailID = strtoll(id, NULL, 10);
  280     sqlite3_free(id);
  281     if( playlist )
  282     {
  283         sql_exec(db, "DELETE from PLAYLISTS where ID = %lld", detailID);
  284         sql_exec(db, "DELETE from DETAILS where ID ="
  285                      " (SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s$%llX')",
  286                  MUSIC_PLIST_ID, detailID);
  287         sql_exec(db, "DELETE from OBJECTS where OBJECT_ID = '%s$%llX' or PARENT_ID = '%s$%llX'",
  288                  MUSIC_PLIST_ID, detailID, MUSIC_PLIST_ID, detailID);
  289     }
  290     else
  291     {
  292         /* Delete the parent containers if we are about to empty them. */
  293         snprintf(sql, sizeof(sql), "SELECT PARENT_ID from OBJECTS where DETAIL_ID = %lld"
  294                                    " and PARENT_ID not like '64$%%'",
  295                                    (long long int)detailID);
  296         if( (sql_get_table(db, sql, &result, &rows, NULL) == SQLITE_OK) )
  297         {
  298             int i, children;
  299             for( i = 1; i <= rows; i++ )
  300             {
  301                 /* If it's a playlist item, adjust the item count of the playlist */
  302                 if( strncmp(result[i], MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 )
  303                 {
  304                     sql_exec(db, "UPDATE PLAYLISTS set FOUND = (FOUND-1) where ID = %d",
  305                              atoi(strrchr(result[i], '$') + 1));
  306                 }
  307 
  308                 children = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]);
  309                 if( children < 0 )
  310                     continue;
  311                 if( children < 2 )
  312                 {
  313                     sql_exec(db, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]);
  314 
  315                     ptr = strrchr(result[i], '$');
  316                     if( ptr )
  317                         *ptr = '\0';
  318                     if( sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]) == 0 )
  319                     {
  320                         sql_exec(db, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]);
  321                     }
  322                 }
  323             }
  324             sqlite3_free_table(result);
  325         }
  326         /* Now delete the actual objects */
  327         sql_exec(db, "DELETE from DETAILS where ID = %lld", detailID);
  328         sql_exec(db, "DELETE from OBJECTS where DETAIL_ID = %lld", detailID);
  329     }
  330     snprintf(art_cache, sizeof(art_cache), "%s/art_cache%s", db_path, path);
  331     remove(art_cache);
  332 
  333     return 0;
  334 }
  335 
  336 static char *
  337 check_nfo(const char *path)
  338 {
  339     char file[PATH_MAX];
  340 
  341     strncpyt(file, path, sizeof(file));
  342     strip_ext(file);
  343 
  344     return sql_get_text_field(db, "SELECT PATH from DETAILS where (PATH > '%q.' and PATH <= '%q.z')"
  345                       " and MIME glob 'video/*' limit 1", file, file);
  346 }
  347 
  348 int
  349 monitor_insert_file(const char *name, const char *path)
  350 {
  351     int len;
  352     char *last_dir;
  353     char *path_buf;
  354     char *base_name;
  355     char *base_copy;
  356     char *parent_buf = NULL;
  357     char *id = NULL;
  358     char video[PATH_MAX];
  359     const char *tbl = "DETAILS";
  360     int depth = 1;
  361     int ts;
  362     media_types dir_types;
  363     media_types mtype = get_media_type(path);
  364     struct stat st;
  365 
  366     /* Is it cover art for another file? */
  367     if (mtype == TYPE_IMAGE)
  368         update_if_album_art(path);
  369     else if (mtype == TYPE_CAPTION)
  370         check_for_captions(path, 0);
  371     else if (mtype == TYPE_PLAYLIST)
  372         tbl = "PLAYLISTS";
  373     else if (mtype == TYPE_NFO)
  374     {
  375         char *vpath = check_nfo(path);
  376         if (!vpath)
  377             return -1;
  378         strncpyt(video, vpath, sizeof(video));
  379         sqlite3_free(vpath);
  380         DPRINTF(E_DEBUG, L_INOTIFY, "Found modified nfo %s\n", video);
  381         monitor_remove_file(video);
  382         name = strrchr(video, '/');
  383         if (!name)
  384             return -1;
  385         name++;
  386         path = video;
  387         mtype = TYPE_VIDEO;
  388     }
  389 
  390     /* Check if we're supposed to be scanning for this file type in this directory */
  391     dir_types = valid_media_types(path);
  392     if (!(mtype & dir_types))
  393         return -1;
  394     
  395     /* If it's already in the database and hasn't been modified, skip it. */
  396     if( stat(path, &st) != 0 )
  397         return -1;
  398 
  399     ts = sql_get_int_field(db, "SELECT TIMESTAMP from %s where PATH = '%q'", tbl, path);
  400     if( !ts )
  401     {
  402         DPRINTF(E_DEBUG, L_INOTIFY, "Adding: %s\n", path);
  403     }
  404     else if( ts != st.st_mtime )
  405     {
  406         DPRINTF(E_DEBUG, L_INOTIFY, "%s is %s than the last db entry.\n",
  407             path, (ts > st.st_mtime) ? "older" : "newer");
  408         monitor_remove_file(path);
  409     }
  410     else
  411     {
  412         if( ts == st.st_mtime && !GETFLAG(RESCAN_MASK) )
  413             DPRINTF(E_DEBUG, L_INOTIFY, "%s already exists\n", path);
  414         return 0;
  415     }
  416 
  417     /* Find the parentID. If it's not found, create all necessary parents. */
  418     len = strlen(path)+1;
  419     if( !(path_buf = malloc(len)) ||
  420         !(last_dir = malloc(len)) ||
  421         !(base_name = malloc(len)) )
  422         return -1;
  423     base_copy = base_name;
  424     while( depth )
  425     {
  426         depth = 0;
  427         strcpy(path_buf, path);
  428         parent_buf = dirname(path_buf);
  429 
  430         do
  431         {
  432             //DEBUG DPRINTF(E_DEBUG, L_INOTIFY, "Checking %s\n", parent_buf);
  433             id = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
  434                                         " where d.PATH = '%q' and REF_ID is NULL", parent_buf);
  435             if( id )
  436             {
  437                 if( !depth )
  438                     break;
  439                 DPRINTF(E_DEBUG, L_INOTIFY, "Found first known parentID: %s [%s]\n", id, parent_buf);
  440                 /* Insert newly-found directory */
  441                 strcpy(base_name, last_dir);
  442                 base_copy = basename(base_name);
  443                 insert_directory(base_copy, last_dir, BROWSEDIR_ID, id+2, get_next_available_id("OBJECTS", id));
  444                 sqlite3_free(id);
  445                 break;
  446             }
  447             depth++;
  448             strcpy(last_dir, parent_buf);
  449             parent_buf = dirname(parent_buf);
  450         }
  451         while( strcmp(parent_buf, "/") != 0 );
  452 
  453         if( strcmp(parent_buf, "/") == 0 )
  454         {
  455             id = sqlite3_mprintf("%s", BROWSEDIR_ID);
  456             depth = 0;
  457             break;
  458         }
  459         strcpy(path_buf, path);
  460     }
  461     free(last_dir);
  462     free(path_buf);
  463     free(base_name);
  464 
  465     if( !depth )
  466     {
  467         //DEBUG DPRINTF(E_DEBUG, L_INOTIFY, "Inserting %s\n", name);
  468         int ret = insert_file(name, path, id+2, get_next_available_id("OBJECTS", id), dir_types);
  469         if (ret == 1 && (mtype & TYPE_PLAYLIST))
  470         {
  471             next_pl_fill = time(NULL) + 120; // Schedule a playlist scan for 2 minutes from now.
  472             //DEBUG DPRINTF(E_MAXDEBUG, L_INOTIFY,  "Playlist scan scheduled for %s", ctime(&next_pl_fill));
  473         }
  474         sqlite3_free(id);
  475     }
  476     return depth;
  477 }
  478 
  479 static bool
  480 check_notsparse(const char *path)
  481 #if HAVE_DECL_SEEK_HOLE
  482 {
  483     int fd;
  484     bool rv;
  485 
  486     if ((fd = open(path, O_RDONLY)) == -1)
  487         return (false);
  488     if (lseek(fd, 0, SEEK_HOLE) == lseek(fd, 0, SEEK_END))
  489         rv = true;
  490     else
  491         rv = false;
  492     close(fd);
  493     return (rv);
  494 }
  495 #else
  496 {
  497     struct stat st;
  498 
  499     return (stat(path, &st) == 0 && (st.st_blocks << 9 >= st.st_size));
  500 }
  501 #endif
  502 
  503 int
  504 monitor_insert_directory(int fd, char *name, const char * path)
  505 {
  506     DIR * ds;
  507     struct dirent * e;
  508     char *id, *parent_buf, *esc_name;
  509     char path_buf[PATH_MAX];
  510     enum file_types type = TYPE_UNKNOWN;
  511     media_types dir_types;
  512 
  513     if( access(path, R_OK|X_OK) != 0 )
  514     {
  515         DPRINTF(E_WARN, L_INOTIFY, "Could not access %s [%s]\n", path, strerror(errno));
  516         return -1;
  517     }
  518     if( sql_get_int_field(db, "SELECT ID from DETAILS where PATH = '%q'", path) > 0 )
  519     {
  520         fd = 0;
  521         if (!GETFLAG(RESCAN_MASK))
  522             DPRINTF(E_DEBUG, L_INOTIFY, "%s already exists\n", path);
  523     }
  524     else
  525     {
  526         parent_buf = strdup(path);
  527         id = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
  528                         " WHERE d.PATH = '%q' and REF_ID is NULL", dirname(parent_buf));
  529         if( !id )
  530             id = sqlite3_mprintf("%s", BROWSEDIR_ID);
  531         insert_directory(name, path, BROWSEDIR_ID, id+2, get_next_available_id("OBJECTS", id));
  532         sqlite3_free(id);
  533         free(parent_buf);
  534     }
  535 
  536 #ifdef HAVE_WATCH
  537     if( fd > 0 )
  538         add_watch(fd, path);
  539 #endif
  540 
  541     dir_types = valid_media_types(path);
  542 
  543     ds = opendir(path);
  544     if( !ds )
  545     {
  546         DPRINTF(E_ERROR, L_INOTIFY, "opendir failed! [%s]\n", strerror(errno));
  547         return -1;
  548     }
  549     while( !quitting && (e = readdir(ds)) )
  550     {
  551         if( e->d_name[0] == '.' )
  552             continue;
  553         esc_name = escape_tag(e->d_name, 1);
  554         snprintf(path_buf, sizeof(path_buf), "%s/%s", path, e->d_name);
  555         switch( e->d_type )
  556         {
  557             case DT_DIR:
  558             case DT_REG:
  559             case DT_LNK:
  560             case DT_UNKNOWN:
  561                 type = resolve_unknown_type(path_buf, dir_types);
  562             default:
  563                 break;
  564         }
  565         if( type == TYPE_DIR )
  566         {
  567             monitor_insert_directory(fd, esc_name, path_buf);
  568         }
  569         else if( type == TYPE_FILE && check_notsparse(path_buf)) {
  570             monitor_insert_file(esc_name, path_buf);
  571         }
  572         free(esc_name);
  573     }
  574     closedir(ds);
  575 
  576     return 0;
  577 }
  578 
  579 int
  580 monitor_remove_directory(int fd, const char * path)
  581 {
  582     char * sql;
  583     char **result;
  584     int64_t detailID = 0;
  585     int rows, i, ret = 1;
  586 
  587     /* Invalidate the scanner cache so we don't insert files into non-existent containers */
  588     valid_cache = 0;
  589     #ifdef HAVE_INOTIFY
  590     if( fd > 0 )
  591     {
  592         remove_watch(fd, path);
  593     }
  594     #endif
  595     sql = sqlite3_mprintf("SELECT ID from DETAILS where (PATH > '%q/' and PATH <= '%q/%c')"
  596                           " or PATH = '%q'", path, path, 0xFF, path);
  597     if( (sql_get_table(db, sql, &result, &rows, NULL) == SQLITE_OK) )
  598     {
  599         if( rows )
  600         {
  601             for( i=1; i <= rows; i++ )
  602             {
  603                 detailID = strtoll(result[i], NULL, 10);
  604                 sql_exec(db, "DELETE from DETAILS where ID = %lld", detailID);
  605                 sql_exec(db, "DELETE from OBJECTS where DETAIL_ID = %lld", detailID);
  606             }
  607             ret = 0;
  608         }
  609         sqlite3_free_table(result);
  610     }
  611     sqlite3_free(sql);
  612     /* Clean up any album art entries in the deleted directory */
  613     sql_exec(db, "DELETE from ALBUM_ART where (PATH > '%q/' and PATH <= '%q/%c')", path, path, 0xFF);
  614 
  615     return ret;
  616 }
  617 
  618 #ifdef HAVE_INOTIFY
  619 void *
  620 start_inotify(void)
  621 {
  622     struct pollfd pollfds[1];
  623     char buffer[BUF_LEN];
  624     char path_buf[PATH_MAX];
  625     int length, i = 0;
  626     char * esc_name = NULL;
  627     struct stat st;
  628     sigset_t set;
  629 
  630     sigfillset(&set);
  631     sigdelset(&set, SIGCHLD);
  632     pthread_sigmask(SIG_BLOCK, &set, NULL);
  633 
  634     pollfds[0].fd = inotify_init();
  635     pollfds[0].events = POLLIN;
  636 
  637     if ( pollfds[0].fd < 0 )
  638         DPRINTF(E_ERROR, L_INOTIFY, "inotify_init() failed!\n");
  639 
  640     while( GETFLAG(SCANNING_MASK) )
  641     {
  642         if( quitting )
  643             goto quitting;
  644         sleep(1);
  645     }
  646     inotify_create_watches(pollfds[0].fd);
  647     if (setpriority(PRIO_PROCESS, 0, 19) == -1)
  648         DPRINTF(E_WARN, L_INOTIFY,  "Failed to reduce inotify thread priority\n");
  649     sqlite3_release_memory(1<<31);
  650     lav_register_all();
  651 
  652     while( !quitting )
  653     {
  654         int timeout = -1;
  655         if (next_pl_fill)
  656         {
  657             time_t diff = next_pl_fill - time(NULL);
  658             if (diff < 0)
  659                 timeout = 0;
  660             else
  661                 timeout = diff * 1000;
  662         }
  663         length = poll(pollfds, 1, timeout);
  664         if( !length )
  665         {
  666             if( next_pl_fill && (time(NULL) >= next_pl_fill) )
  667             {
  668                 fill_playlists();
  669                 next_pl_fill = 0;
  670             }
  671             continue;
  672         }
  673         else if( length < 0 )
  674         {
  675             if( (errno == EINTR) || (errno == EAGAIN) )
  676                 continue;
  677             else
  678                 DPRINTF(E_ERROR, L_INOTIFY, "read failed!\n");
  679         }
  680         else
  681         {
  682             length = read(pollfds[0].fd, buffer, BUF_LEN);
  683             buffer[BUF_LEN-1] = '\0';
  684         }
  685 
  686         i = 0;
  687         while( !quitting && i < length )
  688         {
  689             struct inotify_event * event = (struct inotify_event *) &buffer[i];
  690             if( event->len )
  691             {
  692                 if( *(event->name) == '.' )
  693                 {
  694                     i += EVENT_SIZE + event->len;
  695                     continue;
  696                 }
  697                 esc_name = modifyString(strdup(event->name), "&", "&amp;amp;", 0);
  698                 snprintf(path_buf, sizeof(path_buf), "%s/%s", get_path_from_wd(event->wd), event->name);
  699                 if ( event->mask & IN_ISDIR && (event->mask & (IN_CREATE|IN_MOVED_TO)) )
  700                 {
  701                     DPRINTF(E_DEBUG, L_INOTIFY,  "The directory %s was %s.\n",
  702                         path_buf, (event->mask & IN_MOVED_TO ? "moved here" : "created"));
  703                     monitor_insert_directory(pollfds[0].fd, esc_name, path_buf);
  704                 }
  705                 else if ( (event->mask & (IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE)) &&
  706                           (lstat(path_buf, &st) == 0) )
  707                 {
  708                     if( (event->mask & (IN_MOVED_TO|IN_CREATE)) && (S_ISLNK(st.st_mode) || st.st_nlink > 1) )
  709                     {
  710                         DPRINTF(E_DEBUG, L_INOTIFY, "The %s link %s was %s.\n",
  711                             (S_ISLNK(st.st_mode) ? "symbolic" : "hard"),
  712                             path_buf, (event->mask & IN_MOVED_TO ? "moved here" : "created"));
  713                         if( stat(path_buf, &st) == 0 && S_ISDIR(st.st_mode) )
  714                             monitor_insert_directory(pollfds[0].fd, esc_name, path_buf);
  715                         else
  716                             monitor_insert_file(esc_name, path_buf);
  717                     }
  718                     else if( event->mask & (IN_CLOSE_WRITE|IN_MOVED_TO) && st.st_size > 0 )
  719                     {
  720                         if( (event->mask & IN_MOVED_TO) ||
  721                             (sql_get_int_field(db, "SELECT TIMESTAMP from DETAILS where PATH = '%q'", path_buf) != st.st_mtime) )
  722                         {
  723                             DPRINTF(E_DEBUG, L_INOTIFY, "The file %s was %s.\n",
  724                                 path_buf, (event->mask & IN_MOVED_TO ? "moved here" : "changed"));
  725                             monitor_insert_file(esc_name, path_buf);
  726                         }
  727                     }
  728                 }
  729                 else if ( event->mask & (IN_DELETE|IN_MOVED_FROM) )
  730                 {
  731                     DPRINTF(E_DEBUG, L_INOTIFY, "The %s %s was %s.\n",
  732                         (event->mask & IN_ISDIR ? "directory" : "file"),
  733                         path_buf, (event->mask & IN_MOVED_FROM ? "moved away" : "deleted"));
  734                     if ( event->mask & IN_ISDIR )
  735                         monitor_remove_directory(pollfds[0].fd, path_buf);
  736                     else
  737                         monitor_remove_file(path_buf);
  738                 }
  739                 free(esc_name);
  740             }
  741             i += EVENT_SIZE + event->len;
  742         }
  743     }
  744     inotify_remove_watches(pollfds[0].fd);
  745 quitting:
  746     close(pollfds[0].fd);
  747 
  748     return 0;
  749 }
  750 #endif