static bool eval_pcre(struct w_query_ctx *ctx, struct watchman_file *file, void *data) { struct match_pcre *match = data; w_string_t *str; int rc; if (match->wholename) { str = w_query_ctx_get_wholename(ctx); } else { str = file->name; } rc = pcre_exec(match->re, match->extra, str->buf, str->len, 0, 0, NULL, 0); if (rc == PCRE_ERROR_NOMATCH) { return false; } if (rc >= 0) { return true; } // An error. It's not actionable here return false; }
static bool eval_match(struct w_query_ctx *ctx, struct watchman_file *file, void *data) { struct match_data *match = data; w_string_t *str; if (match->wholename) { str = w_query_ctx_get_wholename(ctx); } else { str = file->name; } return fnmatch(match->pattern, str->buf, FNM_PERIOD | (match->caseless ? FNM_CASEFOLD : 0)) == 0; }
static bool eval_dirname(struct w_query_ctx *ctx, struct watchman_file *file, void *ptr) { struct dirname_data *data = ptr; w_string_t *str = w_query_ctx_get_wholename(ctx); json_int_t depth = 0; size_t i; unused_parameter(file); if (str->len <= data->dirname->len) { // Either it doesn't prefix match, or file name is == dirname. // That means that the best case is that the wholename matches. // we only want to match if dirname(wholename) matches, so it // is not possible for us to match unless the length of wholename // is greater than the dirname operand return false; } // Want to make sure that wholename is a child of dirname, so // check for a dir separator. Special case for dirname == '' (the root), // which won't have a slash in position 0. if (data->dirname->len > 0 && str->buf[data->dirname->len] != '/') { // may have a common prefix with, but is not a child of dirname return false; } if (!data->startswith(str, data->dirname)) { return false; } // Now compute the depth of file from dirname. We do this by // counting dir separators, not including the one we saw above. for (i = data->dirname->len + 1; i < str->len; i++) { if (str->buf[i] == '/') { depth++; } } return eval_int_compare(depth, &data->depth); }
static bool eval_name(struct w_query_ctx *ctx, struct watchman_file *file, void *data) { struct name_data *name = data; w_string_t *str; if (name->wholename) { str = w_query_ctx_get_wholename(ctx); } else { str = file->name; } if (name->map) { bool matched; w_ht_val_t val; if (name->caseless) { str = w_string_dup_lower(str); if (!str) { return false; } } matched = w_ht_lookup(name->map, w_ht_ptr_val(str), &val, false); if (name->caseless) { w_string_delref(str); } return matched; } if (name->caseless) { return w_string_equal_caseless(str, name->name); } return w_string_equal(str, name->name); }
bool w_query_process_file( w_query *query, struct w_query_ctx *ctx, struct watchman_file *file) { struct watchman_rule_match *m; if (ctx->wholename) { w_string_delref(ctx->wholename); ctx->wholename = NULL; } ctx->file = file; // For fresh instances, only return files that currently exist. if (!ctx->since.is_timestamp && ctx->since.clock.is_fresh_instance && !file->exists) { return true; } // We produce an output for this file if there is no expression, // or if the expression matched. if (query->expr && !w_query_expr_evaluate(query->expr, ctx, file)) { // No matched return true; } // Need more room? if (ctx->num_results + 1 > ctx->num_allocd) { uint32_t new_num = ctx->num_allocd ? ctx->num_allocd * 2 : 64; struct watchman_rule_match *res; res = realloc(ctx->results, new_num * sizeof(*res)); if (!res) { w_log(W_LOG_ERR, "out of memory while capturing matches!\n"); return false; } ctx->results = res; ctx->num_allocd = new_num; } m = &ctx->results[ctx->num_results++]; m->root_number = ctx->root->number; m->relname = w_query_ctx_get_wholename(ctx); if (!m->relname) { w_log(W_LOG_ERR, "out of memory while capturing matches!\n"); return false; } w_string_addref(m->relname); m->file = file; if (ctx->since.is_timestamp) { m->is_new = w_timeval_compare(ctx->since.timestamp, file->ctime.tv) > 0; } else if (ctx->since.clock.is_fresh_instance) { m->is_new = true; } else { m->is_new = file->ctime.ticks > ctx->since.clock.ticks; } return true; }