/* Thread: scan */ static void process_directory(char *path, int flags) { struct stacked_dir *bulkstack; DIR *dirp; struct dirent buf; struct dirent *de; char entry[PATH_MAX]; char *deref; struct stat sb; struct watch_info wi; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) struct kevent kev; #endif int compilation; int ret; if (flags & F_SCAN_BULK) { /* Save our directory stack so it won't get handled inside * the event loop - not its business, we're in bulk mode here. */ bulkstack = dirstack; dirstack = NULL; /* Run the event loop */ event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK); /* Restore our directory stack */ dirstack = bulkstack; if (scan_exit) return; } DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags); dirp = opendir(path); if (!dirp) { DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno)); return; } /* Check for a compilation directory */ compilation = check_compilation(path); for (;;) { ret = readdir_r(dirp, &buf, &de); if (ret != 0) { DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno)); break; } if (de == NULL) break; if (buf.d_name[0] == '.') continue; ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name); continue; } ret = lstat(entry, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno)); continue; } if (S_ISLNK(sb.st_mode)) { deref = m_realpath(entry); if (!deref) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno)); continue; } ret = stat(deref, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno)); free(deref); continue; } ret = snprintf(entry, sizeof(entry), "%s", deref); free(deref); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref); continue; } } if (S_ISREG(sb.st_mode)) process_file(entry, sb.st_mtime, sb.st_size, compilation, flags); else if (S_ISDIR(sb.st_mode)) push_dir(&dirstack, entry); else DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink nor regular file\n", entry); } closedir(dirp); memset(&wi, 0, sizeof(struct watch_info)); #if defined(__linux__) /* Add inotify watch */ wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF); if (wi.wd < 0) { DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno)); return; } if (!(flags & F_SCAN_RESCAN)) { wi.cookie = 0; wi.path = path; db_watch_add(&wi); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) memset(&kev, 0, sizeof(struct kevent)); wi.wd = open(path, O_RDONLY | O_NONBLOCK); if (wi.wd < 0) { DPRINTF(E_WARN, L_SCAN, "Could not open directory %s for watching: %s\n", path, strerror(errno)); return; } /* Add kevent */ EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL); ret = kevent(inofd, &kev, 1, NULL, 0, NULL); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno)); close(wi.wd); return; } wi.cookie = 0; wi.path = path; db_watch_add(&wi); #endif }
/* Thread: scan */ static void process_directory(char *path, int flags) { DIR *dirp; struct dirent buf; struct dirent *de; char entry[PATH_MAX]; char *deref; struct stat sb; struct watch_info wi; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) struct kevent kev; #endif int type; int ret; DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags); dirp = opendir(path); if (!dirp) { DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno)); return; } /* Check if compilation and/or podcast directory */ type = 0; if (check_speciallib(path, "compilations")) type |= F_SCAN_TYPE_COMPILATION; if (check_speciallib(path, "podcasts")) type |= F_SCAN_TYPE_PODCAST; if (check_speciallib(path, "audiobooks")) type |= F_SCAN_TYPE_AUDIOBOOK; for (;;) { if (scan_exit) break; ret = readdir_r(dirp, &buf, &de); if (ret != 0) { DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno)); break; } if (de == NULL) break; if (buf.d_name[0] == '.') continue; ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name); continue; } ret = lstat(entry, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno)); continue; } if (S_ISLNK(sb.st_mode)) { deref = m_realpath(entry); if (!deref) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno)); continue; } ret = stat(deref, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno)); free(deref); continue; } ret = snprintf(entry, sizeof(entry), "%s", deref); free(deref); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref); continue; } } if (S_ISREG(sb.st_mode)) { if (!(flags & F_SCAN_FAST)) process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, flags); } else if (S_ISFIFO(sb.st_mode)) { if (!(flags & F_SCAN_FAST)) process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, flags); } else if (S_ISDIR(sb.st_mode)) push_dir(&dirstack, entry); else DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry); } closedir(dirp); memset(&wi, 0, sizeof(struct watch_info)); #if defined(__linux__) /* Add inotify watch */ wi.wd = inotify_add_watch(inofd, path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF); if (wi.wd < 0) { DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno)); return; } if (!(flags & F_SCAN_MOVED)) { wi.cookie = 0; wi.path = path; db_watch_add(&wi); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) memset(&kev, 0, sizeof(struct kevent)); wi.wd = open(path, O_RDONLY | O_NONBLOCK); if (wi.wd < 0) { DPRINTF(E_WARN, L_SCAN, "Could not open directory %s for watching: %s\n", path, strerror(errno)); return; } /* Add kevent */ EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL); ret = kevent(inofd, &kev, 1, NULL, 0, NULL); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno)); close(wi.wd); return; } wi.cookie = 0; wi.path = path; db_watch_add(&wi); #endif }
static void process_directory(char *path, int parent_id, int flags) { DIR *dirp; struct dirent buf; struct dirent *de; char entry[PATH_MAX]; char *deref; struct stat sb; struct watch_info wi; int type; char virtual_path[PATH_MAX]; int dir_id; int ret; DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags); dirp = opendir(path); if (!dirp) { DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno)); return; } /* Add/update directories table */ ret = create_virtual_path(path, virtual_path, sizeof(virtual_path)); if (ret < 0) return; dir_id = db_directory_addorupdate(virtual_path, 0, parent_id); if (dir_id <= 0) { DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path); } /* Check if compilation and/or podcast directory */ type = 0; if (check_speciallib(path, "compilations")) type |= F_SCAN_TYPE_COMPILATION; if (check_speciallib(path, "podcasts")) type |= F_SCAN_TYPE_PODCAST; if (check_speciallib(path, "audiobooks")) type |= F_SCAN_TYPE_AUDIOBOOK; for (;;) { if (scan_exit) break; ret = readdir_r(dirp, &buf, &de); if (ret != 0) { DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno)); break; } if (de == NULL) break; if (buf.d_name[0] == '.') continue; ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name); continue; } ret = lstat(entry, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno)); continue; } if (S_ISLNK(sb.st_mode)) { deref = m_realpath(entry); if (!deref) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno)); continue; } ret = stat(deref, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno)); free(deref); continue; } ret = snprintf(entry, sizeof(entry), "%s", deref); free(deref); if ((ret < 0) || (ret >= sizeof(entry))) { DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref); continue; } } if (S_ISREG(sb.st_mode)) { if (!(flags & F_SCAN_FAST)) process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, flags, dir_id); } else if (S_ISFIFO(sb.st_mode)) { if (!(flags & F_SCAN_FAST)) process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, flags, dir_id); } else if (S_ISDIR(sb.st_mode)) push_dir(&dirstack, entry, dir_id); else DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry); } closedir(dirp); memset(&wi, 0, sizeof(struct watch_info)); // Add inotify watch (for FreeBSD we limit the flags so only dirs will be // opened, otherwise we will be opening way too many files) #if defined(__linux__) wi.wd = inotify_add_watch(inofd, path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF); #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MOVE); #endif if (wi.wd < 0) { DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno)); return; } if (!(flags & F_SCAN_MOVED)) { wi.cookie = 0; wi.path = path; db_watch_add(&wi); } }