#include "walk.h" #include "src/ctx.h" #include "src/parsing/parse.h" #include #define STR_STARTS_WITH(x, y) (strncmp(y, x, strlen(y) - 1) == 0) __always_inline parse_job_t *create_fs_parse_job(const char *filepath, const struct stat *info, int base) { int len = (int) strlen(filepath); parse_job_t *job = malloc(sizeof(parse_job_t) + len); strcpy(job->filepath, filepath); job->base = base; char *p = strrchr(filepath + base, '.'); if (p != NULL) { job->ext = (int) (p - filepath + 1); } else { job->ext = len; } job->vfile.info = *info; memset(job->parent, 0, MD5_DIGEST_LENGTH); job->vfile.filepath = job->filepath; job->vfile.read = fs_read; // Filesystem reads are always rewindable job->vfile.read_rewindable = fs_read; job->vfile.reset = fs_reset; job->vfile.close = fs_close; job->vfile.fd = -1; job->vfile.is_fs_file = TRUE; job->vfile.has_checksum = FALSE; job->vfile.rewind_buffer_size = 0; job->vfile.rewind_buffer = NULL; job->vfile.calculate_checksum = ScanCtx.calculate_checksums; return job; } int sub_strings[30]; #define EXCLUDED(str) (pcre_exec(ScanCtx.exclude, ScanCtx.exclude_extra, str, strlen(str), 0, 0, sub_strings, sizeof(sub_strings)) >= 0) int handle_entry(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftw) { if (ftw->level > ScanCtx.depth) { if (typeflag == FTW_D) { return FTW_SKIP_SUBTREE; } return FTW_CONTINUE; } if (ScanCtx.exclude != NULL && EXCLUDED(filepath)) { LOG_DEBUGF("walk.c", "Excluded: %s", filepath) if (typeflag == FTW_F && S_ISREG(info->st_mode)) { pthread_mutex_lock(&ScanCtx.dbg_file_counts_mu); ScanCtx.dbg_excluded_files_count += 1; pthread_mutex_unlock(&ScanCtx.dbg_file_counts_mu); } else if (typeflag == FTW_D) { return FTW_SKIP_SUBTREE; } return FTW_CONTINUE; } if (typeflag == FTW_F && S_ISREG(info->st_mode)) { parse_job_t *job = create_fs_parse_job(filepath, info, ftw->base); tpool_add_work(ScanCtx.pool, parse, job); } return FTW_CONTINUE; } #define MAX_FILE_DESCRIPTORS 64 int walk_directory_tree(const char *dirpath) { return nftw(dirpath, handle_entry, MAX_FILE_DESCRIPTORS, FTW_PHYS | FTW_ACTIONRETVAL); } int iterate_file_list(void *input_file) { char buf[PATH_MAX]; struct stat info; while (fgets(buf, sizeof(buf), input_file) != NULL) { // Remove trailing newline *(buf + strlen(buf) - 1) = '\0'; int stat_ret = stat(buf, &info); if (stat_ret != 0) { LOG_ERRORF("walk.c", "Could not stat file %s (%s)", buf, strerror(errno)); continue; } if (!S_ISREG(info.st_mode)) { LOG_ERRORF("walk.c", "Is not a regular file: %s", buf); continue; } char *absolute_path = canonicalize_file_name(buf); if (absolute_path == NULL) { LOG_FATALF("walk.c", "FIXME: Could not get absolute path of %s", buf); } if (ScanCtx.exclude != NULL && EXCLUDED(absolute_path)) { LOG_DEBUGF("walk.c", "Excluded: %s", absolute_path) if (S_ISREG(info.st_mode)) { pthread_mutex_lock(&ScanCtx.dbg_file_counts_mu); ScanCtx.dbg_excluded_files_count += 1; pthread_mutex_unlock(&ScanCtx.dbg_file_counts_mu); } continue; } if (!STR_STARTS_WITH(absolute_path, ScanCtx.index.desc.root)) { LOG_FATALF("walk.c", "File is not a children of root folder (%s): %s", ScanCtx.index.desc.root, buf); } int base = (int) (strrchr(buf, '/') - buf) + 1; parse_job_t *job = create_fs_parse_job(absolute_path, &info, base); free(absolute_path); tpool_add_work(ScanCtx.pool, parse, job); } return 0; }