ignores *init_ignore(ignores *parent, const char *dirname, const size_t dirname_len) { ignores *ig = ag_malloc(sizeof(ignores)); ig->names = NULL; ig->names_len = 0; ig->slash_names = NULL; ig->slash_names_len = 0; ig->regexes = NULL; ig->regexes_len = 0; ig->slash_regexes = NULL; ig->slash_regexes_len = 0; ig->dirname = dirname; ig->dirname_len = dirname_len; if (parent && is_empty(parent) && parent->parent) { ig->parent = parent->parent; } else { ig->parent = parent; } if (parent && parent->abs_path_len > 0) { ag_asprintf(&(ig->abs_path), "%s/%s", parent->abs_path, dirname); ig->abs_path_len = parent->abs_path_len + 1 + dirname_len; } else if (dirname_len == 1 && dirname[0] == '.') { ig->abs_path = ag_malloc(sizeof(char)); ig->abs_path[0] = '\0'; ig->abs_path_len = 0; } else { ag_asprintf(&(ig->abs_path), "%s", dirname); ig->abs_path_len = dirname_len; } return ig; }
/* This function is REALLY HOT. It gets called for every file */ int filename_filter(const char *path, const struct dirent *dir, void *baton) { const char *filename = dir->d_name; /* TODO: don't call strlen on filename every time we call filename_filter() */ size_t filename_len = strlen(filename); size_t i; scandir_baton_t *scandir_baton = (scandir_baton_t *)baton; const ignores *ig = scandir_baton->ig; const char *base_path = scandir_baton->base_path; const size_t base_path_len = scandir_baton->base_path_len; const char *path_start = path; char *temp; if (!opts.follow_symlinks && is_symlink(path, dir)) { log_debug("File %s ignored becaused it's a symlink", dir->d_name); return 0; } if (is_named_pipe(path, dir)) { log_debug("%s ignored because it's a named pipe", path); return 0; } for (i = 0; evil_hardcoded_ignore_files[i] != NULL; i++) { if (strcmp(filename, evil_hardcoded_ignore_files[i]) == 0) { return 0; } } if (!opts.search_hidden_files && filename[0] == '.') { return 0; } if (opts.search_all_files && !opts.path_to_agignore) { return 1; } for (i = 0; base_path[i] == path[i] && i < base_path_len; i++) { /* base_path always ends with "/\0" while path doesn't, so this is safe */ path_start = path + i + 2; } log_debug("path_start %s filename %s", path_start, filename); while (ig != NULL) { if (path_ignore_search(ig, path_start, filename)) { return 0; } if (is_directory(path, dir) && filename[filename_len - 1] != '/') { ag_asprintf(&temp, "%s/", filename); int rv = path_ignore_search(ig, path_start, temp); free(temp); if (rv) { return 0; } } ig = ig->parent; } return 1; }
int path_ignore_search(const ignores *ig, const char *path, const char *filename) { char *temp; if (filename_ignore_search(ig, filename)) { return 1; } ag_asprintf(&temp, "%s/%s", path, filename); int rv = filename_ignore_search(ig, temp); free(temp); return rv; }
int is_named_pipe(const char *path, const struct dirent *d) { #ifdef HAVE_DIRENT_DTYPE if (d->d_type != DT_UNKNOWN) { return d->d_type == DT_FIFO; } #endif char *full_path; struct stat s; ag_asprintf(&full_path, "%s/%s", path, d->d_name); if (stat(full_path, &s) != 0) { free(full_path); return FALSE; } free(full_path); return S_ISFIFO(s.st_mode); }
int is_symlink(const char *path, const struct dirent *d) { #ifdef HAVE_DIRENT_DTYPE /* Some filesystems, e.g. ReiserFS, always return a type DT_UNKNOWN from readdir or scandir. */ /* Call lstat if we find DT_UNKNOWN to get the information we need. */ if (d->d_type != DT_UNKNOWN) { return (d->d_type == DT_LNK); } #endif char *full_path; struct stat s; ag_asprintf(&full_path, "%s/%s", path, d->d_name); if (lstat(full_path, &s) != 0) { free(full_path); return FALSE; } free(full_path); return (S_ISLNK(s.st_mode)); }
int is_directory(const char *path, const struct dirent *d) { #ifdef HAVE_DIRENT_DTYPE /* Some filesystems, e.g. ReiserFS, always return a type DT_UNKNOWN from readdir or scandir. */ /* Call stat if we don't find DT_DIR to get the information we need. */ /* Also works for symbolic links to directories. */ if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK) { return d->d_type == DT_DIR; } #endif char *full_path; struct stat s; ag_asprintf(&full_path, "%s/%s", path, d->d_name); if (stat(full_path, &s) != 0) { free(full_path); return FALSE; } free(full_path); return S_ISDIR(s.st_mode); }
static int path_ignore_search(const ignores *ig, const char *path, const char *filename, int level) { char *temp, *index; int rv = 0; ag_asprintf(&temp, "%s/%s", path, filename); if ('/' == temp[strlen(temp) - 1]) level++; for (index = temp + strlen(temp) - 1, level++; level > 0 && (!rv); index--) { if ('/' == *index) { rv = filename_ignore_search(ig, index + 1); if (! --level) { /* Cater for .gitignore patterns beginning with a slash */ rv += filename_ignore_search(ig, index); } } } free(temp); return rv; }
int is_symlink(const char *path, const struct dirent *d) { #ifdef _WIN32 char full_path[MAX_PATH + 1] = { 0 }; sprintf(full_path, "%s\\%s", path, d->d_name); return (GetFileAttributesA(full_path) & FILE_ATTRIBUTE_REPARSE_POINT); #else #ifdef HAVE_DIRENT_DTYPE /* Some filesystems, e.g. ReiserFS, always return a type DT_UNKNOWN from readdir or scandir. */ /* Call lstat if we find DT_UNKNOWN to get the information we need. */ if (d->d_type != DT_UNKNOWN) { return (d->d_type == DT_LNK); } #endif char *full_path; struct stat s; ag_asprintf(&full_path, "%s/%s", path, d->d_name); if (lstat(full_path, &s) != 0) { free(full_path); return FALSE; } free(full_path); return S_ISLNK(s.st_mode); #endif }
static int path_ignore_search(const ignores *ig, const char *path, const char *filename) { char *temp; size_t i; int match_pos; if (strncmp(filename, "./", 2) == 0) { filename++; } match_pos = binary_search(filename, ig->names, 0, ig->names_len); if (match_pos >= 0) { log_debug("file %s ignored because name matches static pattern %s", filename, ig->names[match_pos]); return 1; } ag_asprintf(&temp, "%s/%s", path[0] == '.' ? path + 1 : path, filename); log_debug("temp: %s abs path: %s", temp, ig->abs_path); if (strncmp(temp, ig->abs_path, ig->abs_path_len) == 0) { char *slash_filename = temp + ig->abs_path_len; if (slash_filename[0] == '/') { slash_filename++; } match_pos = binary_search(slash_filename, ig->names, 0, ig->names_len); if (match_pos >= 0) { log_debug("file %s ignored because name matches static pattern %s", temp, ig->names[match_pos]); free(temp); return 1; } match_pos = binary_search(slash_filename, ig->slash_names, 0, ig->slash_names_len); if (match_pos >= 0) { log_debug("file %s ignored because name matches slash static pattern %s", slash_filename, ig->slash_names[match_pos]); free(temp); return 1; } for (i = 0; i < ig->names_len; i++) { char *pos = strstr(slash_filename, ig->names[i]); if (pos == slash_filename || (pos && *(pos - 1) == '/')) { pos += strlen(ig->names[i]); if (*pos == '\0' || *pos == '/') { log_debug("file %s ignored because path somewhere matches name %s", slash_filename, ig->names[i]); free(temp); return 1; } } log_debug("pattern %s doesn't match path %s", ig->names[i], slash_filename); } for (i = 0; i < ig->slash_regexes_len; i++) { if (fnmatch(ig->slash_regexes[i], slash_filename, fnmatch_flags) == 0) { log_debug("file %s ignored because name matches slash regex pattern %s", slash_filename, ig->slash_regexes[i]); free(temp); return 1; } log_debug("pattern %s doesn't match slash file %s", ig->slash_regexes[i], slash_filename); } } for (i = 0; i < ig->regexes_len; i++) { if (fnmatch(ig->regexes[i], filename, fnmatch_flags) == 0) { log_debug("file %s ignored because name matches regex pattern %s", filename, ig->regexes[i]); free(temp); return 1; } log_debug("pattern %s doesn't match file %s", ig->regexes[i], filename); } log_debug("file %s not ignored", filename); int rv = ackmate_dir_match(temp); free(temp); return rv; }
void load_svn_ignore_patterns(ignores *ig, const char *path) { FILE *fp = NULL; char *dir_prop_base; ag_asprintf(&dir_prop_base, "%s/%s", path, SVN_DIR_PROP_BASE); fp = fopen(dir_prop_base, "r"); if (fp == NULL) { log_debug("Skipping svn ignore file %s", dir_prop_base); free(dir_prop_base); return; } char *entry = NULL; size_t entry_len = 0; char *key = ag_malloc(32); /* Sane start for max key length. */ size_t key_len = 0; size_t bytes_read = 0; char *entry_line; size_t line_len; int matches; while (fscanf(fp, "K %zu\n", &key_len) == 1) { key = ag_realloc(key, key_len + 1); bytes_read = fread(key, 1, key_len, fp); key[key_len] = '\0'; matches = fscanf(fp, "\nV %zu\n", &entry_len); if (matches != 1) { log_debug("Unable to parse svnignore file %s: fscanf() got %i matches, expected 1.", dir_prop_base, matches); goto cleanup; } if (strncmp(SVN_PROP_IGNORE, key, bytes_read) != 0) { log_debug("key is %s, not %s. skipping %u bytes", key, SVN_PROP_IGNORE, entry_len); /* Not the key we care about. fseek and repeat */ fseek(fp, entry_len + 1, SEEK_CUR); /* +1 to account for newline. yes I know this is hacky */ continue; } /* Aww yeah. Time to ignore stuff */ entry = ag_malloc(entry_len + 1); bytes_read = fread(entry, 1, entry_len, fp); entry[bytes_read] = '\0'; log_debug("entry: %s", entry); break; } if (entry == NULL) { goto cleanup; } char *patterns = entry; size_t patterns_len = strlen(patterns); while (*patterns != '\0' && patterns < (entry + bytes_read)) { for (line_len = 0; line_len < patterns_len; line_len++) { if (patterns[line_len] == '\n') { break; } } if (line_len > 0) { entry_line = ag_strndup(patterns, line_len); add_ignore_pattern(ig, entry_line); free(entry_line); } patterns += line_len + 1; patterns_len -= line_len + 1; } free(entry); cleanup: free(dir_prop_base); free(key); fclose(fp); }
/* TODO: Append matches to some data structure instead of just printing them out. * Then ag can have sweet summaries of matches/files scanned/time/etc. */ void search_dir(ignores *ig, const char *base_path, const char *path, const int depth) { struct dirent **dir_list = NULL; struct dirent *dir = NULL; scandir_baton_t scandir_baton; int results = 0; char *dir_full_path = NULL; const char *ignore_file = NULL; int i; /* find agignore/gitignore/hgignore/etc files to load ignore patterns from */ for (i = 0; opts.skip_vcs_ignores ? (i == 0) : (ignore_pattern_files[i] != NULL); i++) { ignore_file = ignore_pattern_files[i]; ag_asprintf(&dir_full_path, "%s/%s", path, ignore_file); if (strcmp(SVN_DIR, ignore_file) == 0) { load_svn_ignore_patterns(ig, dir_full_path); } else { load_ignore_patterns(ig, dir_full_path); } free(dir_full_path); dir_full_path = NULL; } if (opts.path_to_agignore) { load_ignore_patterns(ig, opts.path_to_agignore); } scandir_baton.ig = ig; scandir_baton.base_path = base_path; results = ag_scandir(path, &dir_list, &filename_filter, &scandir_baton); if (results == 0) { log_debug("No results found in directory %s", path); goto search_dir_cleanup; } else if (results == -1) { if (errno == ENOTDIR) { /* Not a directory. Probably a file. */ /* If we're only searching one file, don't print the filename header at the top. */ if (depth == 0 && opts.paths_len == 1) { opts.print_heading = -1; } search_file(path); } else { log_err("Error opening directory %s: %s", path, strerror(errno)); } goto search_dir_cleanup; } int offset_vector[3]; int rc = 0; work_queue_t *queue_item; for (i = 0; i < results; i++) { queue_item = NULL; dir = dir_list[i]; ag_asprintf(&dir_full_path, "%s/%s", path, dir->d_name); /* If a link points to a directory then we need to treat it as a directory. */ if (!opts.follow_symlinks && is_symlink(path, dir)) { log_debug("File %s ignored becaused it's a symlink", dir->d_name); goto cleanup; } if (!is_directory(path, dir)) { if (opts.file_search_regex) { rc = pcre_exec(opts.file_search_regex, NULL, dir_full_path, strlen(dir_full_path), 0, 0, offset_vector, 3); if (rc < 0) { /* no match */ log_debug("Skipping %s due to file_search_regex.", dir_full_path); goto cleanup; } else if (opts.match_files) { log_debug("match_files: file_search_regex matched for %s.", dir_full_path); pthread_mutex_lock(&print_mtx); print_path(dir_full_path, '\n'); pthread_mutex_unlock(&print_mtx); goto cleanup; } } queue_item = ag_malloc(sizeof(work_queue_t)); queue_item->path = dir_full_path; queue_item->next = NULL; pthread_mutex_lock(&work_queue_mtx); if (work_queue_tail == NULL) { work_queue = queue_item; } else { work_queue_tail->next = queue_item; } work_queue_tail = queue_item; pthread_mutex_unlock(&work_queue_mtx); pthread_cond_signal(&files_ready); log_debug("%s added to work queue", dir_full_path); } else if (opts.recurse_dirs) { if (depth < opts.max_search_depth) { log_debug("Searching dir %s", dir_full_path); ignores *child_ig = init_ignore(ig); search_dir(child_ig, base_path, dir_full_path, depth + 1); cleanup_ignore(child_ig); } else { log_err("Skipping %s. Use the --depth option to search deeper.", dir_full_path); } } cleanup: ; free(dir); dir = NULL; if (queue_item == NULL) { free(dir_full_path); dir_full_path = NULL; } } search_dir_cleanup: ; free(dir_list); dir_list = NULL; }
int main(int argc, char **argv) { char **base_paths = NULL; char **paths = NULL; int i; int pcre_opts = PCRE_MULTILINE; int study_opts = 0; double time_diff; worker_t *workers = NULL; int workers_len; int num_cores; #ifdef KJK_BUILD extern void setup_crash_handler(); /* in kjk_crash_handler.cpp */ setup_crash_handler(); #endif set_log_level(LOG_LEVEL_WARN); work_queue = NULL; work_queue_tail = NULL; memset(&stats, 0, sizeof(stats)); root_ignores = init_ignore(NULL, "", 0); out_fd = stdout; #ifdef USE_PCRE_JIT int has_jit = 0; pcre_config(PCRE_CONFIG_JIT, &has_jit); if (has_jit) { study_opts |= PCRE_STUDY_JIT_COMPILE; } #endif gettimeofday(&(stats.time_start), NULL); parse_options(argc, argv, &base_paths, &paths); log_debug("PCRE Version: %s", pcre_version()); #ifdef _WIN32 { SYSTEM_INFO si; GetSystemInfo(&si); num_cores = si.dwNumberOfProcessors; } #else num_cores = (int)sysconf(_SC_NPROCESSORS_ONLN); #endif workers_len = num_cores; if (opts.literal) { workers_len--; } if (opts.workers) { workers_len = opts.workers; } if (workers_len < 1) { workers_len = 1; } log_debug("Using %i workers", workers_len); done_adding_files = FALSE; workers = (worker_t *) ag_calloc(workers_len, sizeof(worker_t)); if (pthread_cond_init(&files_ready, NULL)) { die("pthread_cond_init failed!"); } if (pthread_mutex_init(&print_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (pthread_mutex_init(&stats_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (pthread_mutex_init(&work_queue_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (opts.casing == CASE_SMART) { opts.casing = is_lowercase(opts.query) ? CASE_INSENSITIVE : CASE_SENSITIVE; } if (opts.literal) { if (opts.casing == CASE_INSENSITIVE) { /* Search routine needs the query to be lowercase */ char *c = opts.query; for (; *c != '\0'; ++c) { *c = (char)tolower(*c); } } generate_alpha_skip(opts.query, opts.query_len, alpha_skip_lookup, opts.casing == CASE_SENSITIVE); find_skip_lookup = NULL; generate_find_skip(opts.query, opts.query_len, &find_skip_lookup, opts.casing == CASE_SENSITIVE); if (opts.word_regexp) { init_wordchar_table(); opts.literal_starts_wordchar = is_wordchar(opts.query[0]); opts.literal_ends_wordchar = is_wordchar(opts.query[opts.query_len - 1]); } } else { if (opts.casing == CASE_INSENSITIVE) { pcre_opts |= PCRE_CASELESS; } if (opts.word_regexp) { char *word_regexp_query; ag_asprintf(&word_regexp_query, "\\b%s\\b", opts.query); free(opts.query); opts.query = word_regexp_query; opts.query_len = strlen(opts.query); } compile_study(&opts.re, &opts.re_extra, opts.query, pcre_opts, study_opts); } if (opts.search_stream) { // search_stream(stdin, ""); } else { for (i = 0; i < workers_len; i++) { workers[i].id = i; int rv = pthread_create(&(workers[i].thread), NULL, &search_file_worker, &(workers[i].id)); if (rv != 0) { die("error in pthread_create(): %s", strerror(rv)); } #if defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(USE_CPU_SET) if (opts.use_thread_affinity) { cpu_set_t cpu_set; CPU_ZERO(&cpu_set); CPU_SET(i % num_cores, &cpu_set); rv = pthread_setaffinity_np(workers[i].thread, sizeof(cpu_set), &cpu_set); if (rv != 0) { die("error in pthread_setaffinity_np(): %s", strerror(rv)); } log_debug("Thread %i set to CPU %i", i, i); } else { log_debug("Thread affinity disabled."); } #else log_debug("No CPU affinity support."); #endif } for (i = 0; paths[i] != NULL; i++) { log_debug("searching path %s for %s", paths[i], opts.query); symhash = NULL; ignores *ig = init_ignore(root_ignores, "", 0); struct stat s; s.st_dev = 0; #ifndef _WIN32 /* The device is ignored if opts.one_dev is false, so it's fine * to leave it at the default 0 */ if (opts.one_dev && lstat(paths[i], &s) == -1) { log_err("Failed to get device information for path %s. Skipping...", paths[i]); } #endif search_dir(ig, base_paths[i], paths[i], 0, s.st_dev); cleanup_ignore(ig); } pthread_mutex_lock(&work_queue_mtx); done_adding_files = TRUE; pthread_cond_broadcast(&files_ready); pthread_mutex_unlock(&work_queue_mtx); for (i = 0; i < workers_len; i++) { if (pthread_join(workers[i].thread, NULL)) { die("pthread_join failed!"); } } } if (opts.stats) { gettimeofday(&(stats.time_end), NULL); time_diff = ((long)stats.time_end.tv_sec * 1000000 + stats.time_end.tv_usec) - ((long)stats.time_start.tv_sec * 1000000 + stats.time_start.tv_usec); time_diff /= 1000000; printf("%ld matches\n%ld files searched\n%ld bytes searched\n%f seconds\n", stats.total_matches, stats.total_files, stats.total_bytes, time_diff); } if (opts.pager) { pclose(out_fd); } cleanup_options(); pthread_cond_destroy(&files_ready); pthread_mutex_destroy(&work_queue_mtx); pthread_mutex_destroy(&stats_mtx); pthread_mutex_destroy(&print_mtx); cleanup_ignore(root_ignores); free(workers); for (i = 0; paths[i] != NULL; i++) { free(paths[i]); free(base_paths[i]); } free(base_paths); free(paths); if (find_skip_lookup) { free(find_skip_lookup); } return !opts.match_found; }
int main(int argc, char **argv) { char **base_paths = NULL; char **paths = NULL; int i; int pcre_opts = PCRE_MULTILINE; int study_opts = 0; double time_diff; pthread_t *workers = NULL; int workers_len; set_log_level(LOG_LEVEL_WARN); work_queue = NULL; work_queue_tail = NULL; memset(&stats, 0, sizeof(stats)); root_ignores = init_ignore(NULL, "", 0); out_fd = stdout; #ifdef USE_PCRE_JIT int has_jit = 0; pcre_config(PCRE_CONFIG_JIT, &has_jit); if (has_jit) { study_opts |= PCRE_STUDY_JIT_COMPILE; } #endif gettimeofday(&(stats.time_start), NULL); parse_options(argc, argv, &base_paths, &paths); log_debug("PCRE Version: %s", pcre_version()); #ifdef _WIN32 { SYSTEM_INFO si; GetSystemInfo(&si); workers_len = si.dwNumberOfProcessors; } #else workers_len = (int)sysconf(_SC_NPROCESSORS_ONLN); #endif if (opts.literal) { workers_len--; } if (opts.workers) { workers_len = opts.workers; } if (workers_len < 1) { workers_len = 1; } log_debug("Using %i workers", workers_len); done_adding_files = FALSE; workers = ag_calloc(workers_len, sizeof(pthread_t)); if (pthread_cond_init(&files_ready, NULL)) { die("pthread_cond_init failed!"); } if (pthread_mutex_init(&print_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (pthread_mutex_init(&stats_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (pthread_mutex_init(&work_queue_mtx, NULL)) { die("pthread_mutex_init failed!"); } if (opts.casing == CASE_SMART) { opts.casing = is_lowercase(opts.query) ? CASE_INSENSITIVE : CASE_SENSITIVE; } if (opts.literal) { if (opts.casing == CASE_INSENSITIVE) { /* Search routine needs the query to be lowercase */ char *c = opts.query; for (; *c != '\0'; ++c) { *c = (char)tolower(*c); } } generate_alpha_skip(opts.query, opts.query_len, alpha_skip_lookup, opts.casing == CASE_SENSITIVE); find_skip_lookup = NULL; generate_find_skip(opts.query, opts.query_len, &find_skip_lookup, opts.casing == CASE_SENSITIVE); if (opts.word_regexp) { init_wordchar_table(); opts.literal_starts_wordchar = is_wordchar(opts.query[0]); opts.literal_ends_wordchar = is_wordchar(opts.query[opts.query_len - 1]); } } else { if (opts.casing == CASE_INSENSITIVE) { pcre_opts |= PCRE_CASELESS; } if (opts.word_regexp) { char *word_regexp_query; ag_asprintf(&word_regexp_query, "\\b%s\\b", opts.query); free(opts.query); opts.query = word_regexp_query; opts.query_len = strlen(opts.query); } compile_study(&opts.re, &opts.re_extra, opts.query, pcre_opts, study_opts); } if (opts.search_stream) { search_stream(stdin, ""); } else { for (i = 0; i < workers_len; i++) { int rv = pthread_create(&(workers[i]), NULL, &search_file_worker, &i); if (rv != 0) { die("error in pthread_create(): %s", strerror(rv)); } } for (i = 0; paths[i] != NULL; i++) { log_debug("searching path %s for %s", paths[i], opts.query); symhash = NULL; ignores *ig = init_ignore(root_ignores, "", 0); search_dir(ig, base_paths[i], paths[i], 0); cleanup_ignore(ig); } pthread_mutex_lock(&work_queue_mtx); done_adding_files = TRUE; pthread_cond_broadcast(&files_ready); pthread_mutex_unlock(&work_queue_mtx); for (i = 0; i < workers_len; i++) { if (pthread_join(workers[i], NULL)) { die("pthread_join failed!"); } } } if (opts.stats) { gettimeofday(&(stats.time_end), NULL); time_diff = ((long)stats.time_end.tv_sec * 1000000 + stats.time_end.tv_usec) - ((long)stats.time_start.tv_sec * 1000000 + stats.time_start.tv_usec); time_diff /= 1000000; printf("%ld matches\n%ld files searched\n%ld bytes searched\n%f seconds\n", stats.total_matches, stats.total_files, stats.total_bytes, time_diff); } if (opts.pager) { pclose(out_fd); } cleanup_options(); pthread_cond_destroy(&files_ready); pthread_mutex_destroy(&work_queue_mtx); pthread_mutex_destroy(&stats_mtx); pthread_mutex_destroy(&print_mtx); cleanup_ignore(root_ignores); free(workers); for (i = 0; paths[i] != NULL; i++) { free(paths[i]); free(base_paths[i]); } free(base_paths); free(paths); if (find_skip_lookup) { free(find_skip_lookup); } return !opts.match_found; }
/* This function is REALLY HOT. It gets called for every file */ int filename_filter(const char *path, const struct dirent *dir, void *baton) { const char *filename = dir->d_name; if (!opts.search_hidden_files && filename[0] == '.') { return 0; } size_t i; for (i = 0; evil_hardcoded_ignore_files[i] != NULL; i++) { if (strcmp(filename, evil_hardcoded_ignore_files[i]) == 0) { return 0; } } if (!opts.follow_symlinks && is_symlink(path, dir)) { log_debug("File %s ignored becaused it's a symlink", dir->d_name); return 0; } if (is_named_pipe(path, dir)) { log_debug("%s ignored because it's a named pipe or socket", path); return 0; } if (opts.search_all_files && !opts.path_to_ignore) { return 1; } scandir_baton_t *scandir_baton = (scandir_baton_t *)baton; const char *base_path = scandir_baton->base_path; const size_t base_path_len = scandir_baton->base_path_len; const char *path_start = path; for (i = 0; base_path[i] == path[i] && i < base_path_len; i++) { /* base_path always ends with "/\0" while path doesn't, so this is safe */ path_start = path + i + 2; } log_debug("path_start %s filename %s", path_start, filename); const char *extension = strchr(filename, '.'); if (extension) { if (extension[1]) { // The dot is not the last character, extension starts at the next one ++extension; } else { // No extension extension = NULL; } } #ifdef HAVE_DIRENT_DNAMLEN size_t filename_len = dir->d_namlen; #else size_t filename_len = 0; #endif if (strncmp(filename, "./", 2) == 0) { #ifndef HAVE_DIRENT_DNAMLEN filename_len = strlen(filename); #endif filename++; filename_len--; } const ignores *ig = scandir_baton->ig; while (ig != NULL) { if (extension) { int match_pos = binary_search(extension, ig->extensions, 0, ig->extensions_len); if (match_pos >= 0) { log_debug("file %s ignored because name matches extension %s", filename, ig->extensions[match_pos]); return 0; } } if (path_ignore_search(ig, path_start, filename)) { return 0; } if (is_directory(path, dir)) { #ifndef HAVE_DIRENT_DNAMLEN if (!filename_len) { filename_len = strlen(filename); } #endif if (filename[filename_len - 1] != '/') { char *temp; ag_asprintf(&temp, "%s/", filename); int rv = path_ignore_search(ig, path_start, temp); free(temp); if (rv) { return 0; } } } ig = ig->parent; } log_debug("%s not ignored", filename); return 1; }
/* This function is REALLY HOT. It gets called for every file */ int filename_filter(const char *path, const struct dirent *dir, void *baton) { const char *filename = dir->d_name; size_t i; scandir_baton_t *scandir_baton = (scandir_baton_t*) baton; const ignores *ig = scandir_baton->ig; const char *base_path = scandir_baton->base_path; const char *path_start = path; char *temp; if (!opts.follow_symlinks && is_symlink(path, dir)) { log_debug("File %s ignored becaused it's a symlink", dir->d_name); return 0; } if (is_named_pipe(path, dir)) { log_debug("%s ignored because it's a named pipe", path); return 0; } for (i = 0; evil_hardcoded_ignore_files[i] != NULL; i++) { if (strcmp(filename, evil_hardcoded_ignore_files[i]) == 0) { return 0; } } if (!opts.search_hidden_files && filename[0] == '.') { return 0; } if (opts.search_all_files && !opts.path_to_agignore) { return 1; } for (i = 0; base_path[i] == path[i] && i < strlen(base_path); i++) { /* base_path always ends with "/\0" while path doesn't, so this is safe */ path_start = path + i + 2; } log_debug("path_start is %s", path_start); if (path_ignore_search(ig, path_start, filename)) { return 0; } if (is_directory(path, dir) && filename[strlen(filename) - 1] != '/') { ag_asprintf(&temp, "%s/", filename); int rv = path_ignore_search(ig, path_start, temp); free(temp); if (rv) { return 0; } } /* TODO: copy-pasted from above */ if (scandir_baton->level == 0) { char *temp2; /* horrible variable name, I know */ ag_asprintf(&temp, "/%s", filename); if (path_ignore_search(ig, path_start, temp)) { return 0; } if (is_directory(path, dir) && temp[strlen(filename) - 1] != '/') { ag_asprintf(&temp2, "%s/", temp); int rv = path_ignore_search(ig, path_start, temp2); free(temp2); if (rv) { return 0; } } free(temp); } scandir_baton->level++; if (ig->parent != NULL) { scandir_baton->ig = ig->parent; return filename_filter(path, dir, (void *)scandir_baton); } return 1; }