Ejemplo n.º 1
0
static bool subscription_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    void *gendata)
{
  struct watchman_file *f;
  struct watchman_client_subscription *sub = gendata;

  w_log(W_LOG_DBG, "running subscription %s %p\n",
      sub->name->buf, sub);

  // Walk back in time until we hit the boundary
  for (f = root->latest_file; f; f = f->next) {
    if (ctx->since.is_timestamp &&
        w_timeval_compare(f->otime.tv, ctx->since.timestamp) < 0) {
      break;
    }
    if (!ctx->since.is_timestamp &&
        f->otime.ticks <= ctx->since.clock.ticks) {
      break;
    }

    if (!w_query_process_file(query, ctx, f)) {
      return false;
    }
  }

  return true;
}
Ejemplo n.º 2
0
static bool time_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx)
{
  struct watchman_file *f;

  // Walk back in time until we hit the boundary
  for (f = root->latest_file; f; f = f->next) {
    if (ctx->since.is_timestamp &&
        w_timeval_compare(f->otime.tv, ctx->since.timestamp) < 0) {
      break;
    }
    if (!ctx->since.is_timestamp &&
        f->otime.ticks < ctx->since.clock.ticks) {
      break;
    }

    if (!w_query_process_file(query, ctx, f)) {
      return false;
    }
  }

  return true;
}
Ejemplo n.º 3
0
static bool trigger_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    void *gendata)
{
  struct watchman_file *f;
  struct watchman_trigger_command *cmd = gendata;

  w_log(W_LOG_DBG, "assessing trigger %s %p\n",
      cmd->triggername->buf, cmd);

  // Walk back in time until we hit the boundary
  for (f = root->latest_file; f; f = f->next) {
    if (ctx->since.is_timestamp &&
        w_timeval_compare(f->otime.tv, ctx->since.timestamp) < 0) {
      break;
    }
    if (!ctx->since.is_timestamp &&
        f->otime.ticks <= ctx->since.clock.ticks) {
      break;
    }

    if (!w_query_file_matches_relative_root(ctx, f)) {
      continue;
    }

    if (!w_query_process_file(query, ctx, f)) {
      return false;
    }
  }

  return true;
}
Ejemplo n.º 4
0
static bool dir_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    struct watchman_dir *dir,
    uint32_t depth)
{
  w_ht_iter_t i;

  if (w_ht_first(dir->files, &i)) do {
    struct watchman_file *file = w_ht_val_ptr(i.value);

    if (!w_query_process_file(query, ctx, file)) {
      return false;
    }
  } while (w_ht_next(dir->files, &i));

  if (depth > 0 && w_ht_first(dir->dirs, &i)) do {
    struct watchman_dir *child = w_ht_val_ptr(i.value);

    if (!dir_generator(query, root, ctx, child, depth - 1)) {
      return false;
    }
  } while (w_ht_next(dir->dirs, &i));

  return true;
}
Ejemplo n.º 5
0
static bool all_files_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    int64_t *num_walked)
{
  struct watchman_file *f;
  int64_t n = 0;
  bool result = true;

  for (f = root->latest_file; f; f = f->next) {
    ++n;
    if (!w_query_file_matches_relative_root(ctx, f)) {
      continue;
    }

    if (!w_query_process_file(query, ctx, f)) {
      result = false;
      goto done;
    }
  }

done:
  *num_walked = n;
  return result;
}
Ejemplo n.º 6
0
static bool suffix_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    int64_t *num_walked)
{
  uint32_t i;
  struct watchman_file *f;
  int64_t n = 0;
  bool result = true;

  for (i = 0; i < query->nsuffixes; i++) {
    // Head of suffix index for this suffix
    f = w_ht_val_ptr(w_ht_get(root->suffixes,
          w_ht_ptr_val(query->suffixes[i])));


    // Walk and process
    for (; f; f = f->suffix_next) {
      ++n;
      if (!w_query_file_matches_relative_root(ctx, f)) {
        continue;
      }

      if (!w_query_process_file(query, ctx, f)) {
        result = false;
        goto done;
      }
    }
  }

done:
  *num_walked = n;
  return result;
}
Ejemplo n.º 7
0
static bool time_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    int64_t *num_walked)
{
  struct watchman_file *f;
  int64_t n = 0;
  bool result = true;

  // Walk back in time until we hit the boundary
  for (f = root->latest_file; f; f = f->next) {
    ++n;
    if (ctx->since.is_timestamp && f->otime.timestamp < ctx->since.timestamp) {
      break;
    }
    if (!ctx->since.is_timestamp &&
        f->otime.ticks <= ctx->since.clock.ticks) {
      break;
    }

    if (!w_query_file_matches_relative_root(ctx, f)) {
      continue;
    }

    if (!w_query_process_file(query, ctx, f)) {
      result = false;
      goto done;
    }
  }

done:
  *num_walked = n;
  return result;
}
Ejemplo n.º 8
0
static bool all_files_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx)
{
  struct watchman_file *f;

  for (f = root->latest_file; f; f = f->next) {
    if (!w_query_process_file(query, ctx, f)) {
      return false;
    }
  }
  return true;
}
Ejemplo n.º 9
0
static bool subscription_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    void *gendata,
    int64_t *num_walked)
{
  struct watchman_file *f;
  struct watchman_client_subscription *sub = gendata;
  int64_t n = 0;
  bool result = true;

  w_log(W_LOG_DBG, "running subscription %s %p\n",
      sub->name->buf, sub);

  // Walk back in time until we hit the boundary
  for (f = root->latest_file; f; f = f->next) {
    ++n;
    if (ctx->since.is_timestamp && f->otime.timestamp < ctx->since.timestamp) {
      break;
    }
    if (!ctx->since.is_timestamp &&
        f->otime.ticks <= ctx->since.clock.ticks) {
      break;
    }

    if (!w_query_file_matches_relative_root(ctx, f)) {
      continue;
    }

    if (!w_query_process_file(query, ctx, f)) {
      result = false;
      goto done;
    }
  }

done:
  *num_walked = n;
  return result;
}
Ejemplo n.º 10
0
static bool dir_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx,
    struct watchman_dir *dir,
    uint32_t depth,
    int64_t *num_walked)
{
  w_ht_iter_t i;
  int64_t n = 0;
  bool result = true;

  if (w_ht_first(dir->files, &i)) do {
    struct watchman_file *file = w_ht_val_ptr(i.value);
    ++n;

    if (!w_query_process_file(query, ctx, file)) {
      result = false;
      goto done;
    }
  } while (w_ht_next(dir->files, &i));

  if (depth > 0 && w_ht_first(dir->dirs, &i)) do {
    struct watchman_dir *child = w_ht_val_ptr(i.value);
    int64_t child_walked = 0;

    result = dir_generator(query, root, ctx, child, depth - 1, &child_walked);
    n += child_walked;
    if (!result) {
      goto done;
    }
  } while (w_ht_next(dir->dirs, &i));

done:
  *num_walked = n;
  return result;
}
Ejemplo n.º 11
0
static bool suffix_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx)
{
  uint32_t i;
  struct watchman_file *f;

  for (i = 0; i < query->nsuffixes; i++) {
    // Head of suffix index for this suffix
    f = w_ht_val_ptr(w_ht_get(root->suffixes,
          w_ht_ptr_val(query->suffixes[i])));


    // Walk and process
    while (f) {
      if (!w_query_process_file(query, ctx, f)) {
        return false;
      }
      f = f->suffix_next;
    }
  }
  return true;
}
Ejemplo n.º 12
0
static bool path_generator(
    w_query *query,
    w_root_t *root,
    struct w_query_ctx *ctx)
{
  struct watchman_file *f;
  uint32_t i;

  for (i = 0; i < query->npaths; i++) {
    struct watchman_dir *dir;
    w_string_t *dir_name, *file_name, *full_name;

    // Compose path with root
    full_name = w_string_path_cat(root->root_path, query->paths[i].name);

    // special case of root dir itself
    if (w_string_equal(root->root_path, full_name)) {
      // dirname on the root is outside the root, which is useless
      dir = w_root_resolve_dir(root, full_name, false);
      goto is_dir;
    }

    // Ideally, we'd just resolve it directly as a dir and be done.
    // It's not quite so simple though, because we may resolve a dir
    // that had been deleted and replaced by a file.
    // We prefer to resolve the parent and walk down.
    dir_name = w_string_dirname(full_name);
    if (!dir_name) {
      w_string_delref(full_name);
      continue;
    }

    dir = w_root_resolve_dir(root, dir_name, false);
    w_string_delref(dir_name);

    if (!dir) {
      // Doesn't exist, and never has
      w_string_delref(full_name);
      continue;
    }

    if (dir->files) {
      file_name = w_string_basename(query->paths[i].name);
      f = w_ht_val_ptr(w_ht_get(dir->files, w_ht_ptr_val(file_name)));
      w_string_delref(file_name);

      // If it's a file (but not an existent dir)
      if (f && (!f->exists || !S_ISDIR(f->st.st_mode))) {
        w_string_delref(full_name);
        if (!w_query_process_file(query, ctx, f)) {
          return false;
        }
        continue;
      }
    }

    // Is it a dir?
    dir = w_ht_val_ptr(w_ht_get(dir->dirs, w_ht_ptr_val(full_name)));
    w_string_delref(full_name);
is_dir:
    // We got a dir; process recursively to specified depth
    if (dir && !dir_generator(query, root, ctx, dir,
          query->paths[i].depth)) {
      return false;
    }
  }
  return true;
}
Ejemplo n.º 13
0
/* Match each child of node against the children of dir */
void InMemoryView::globGeneratorTree(
    struct w_query_ctx* ctx,
    const struct watchman_glob_tree* node,
    const struct watchman_dir* dir) const {
  w_string_t component;

  if (!node->doublestar_children.empty()) {
    globGeneratorDoublestar(ctx, dir, node, nullptr, 0);
  }

  for (const auto& child_node : node->children) {
    w_assert(!child_node->is_doublestar, "should not get here with ** glob");

    // If there are child dirs, consider them for recursion.
    // Note that we don't restrict this to !leaf because the user may have
    // set their globs list to something like ["some_dir", "some_dir/file"]
    // and we don't want to preclude matching the latter.
    if (!dir->dirs.empty()) {
      // Attempt direct lookup if possible
      if (!child_node->had_specials && ctx->query->case_sensitive) {
        w_string_new_len_typed_stack(
            &component,
            child_node->pattern.data(),
            child_node->pattern.size(),
            W_STRING_BYTE);
        const auto child_dir = dir->getChildDir(&component);

        if (child_dir) {
          globGeneratorTree(ctx, child_node.get(), child_dir);
        }
      } else {
        // Otherwise we have to walk and match
        for (auto& it : dir->dirs) {
          const auto child_dir = it.second.get();

          if (!child_dir->last_check_existed) {
            // Globs can only match files in dirs that exist
            continue;
          }

          if (wildmatch(
                  child_node->pattern.c_str(),
                  child_dir->name.c_str(),
                  ctx->query->glob_flags |
                      (ctx->query->case_sensitive ? 0 : WM_CASEFOLD),
                  0) == WM_MATCH) {
            globGeneratorTree(ctx, child_node.get(), child_dir);
          }
        }
      }
    }

    // If the node is a leaf we are in a position to match files.
    if (child_node->is_leaf && !dir->files.empty()) {
      // Attempt direct lookup if possible
      if (!child_node->had_specials && ctx->query->case_sensitive) {
        w_string_new_len_typed_stack(
            &component,
            child_node->pattern.data(),
            child_node->pattern.size(),
            W_STRING_BYTE);
        auto file = dir->getChildFile(&component);

        if (file) {
          ctx->bumpNumWalked();
          if (file->exists) {
            // Globs can only match files that exist
            w_query_process_file(
                ctx->query,
                ctx,
                make_unique<InMemoryFileResult>(file, contentHashCache_));
          }
        }
      } else {
        for (auto& it : dir->files) {
          // Otherwise we have to walk and match
          auto file = it.second.get();
          auto file_name = file->getName();
          ctx->bumpNumWalked();

          if (!file->exists) {
            // Globs can only match files that exist
            continue;
          }

          if (wildmatch(
                  child_node->pattern.c_str(),
                  file_name.data(),
                  ctx->query->glob_flags |
                      (ctx->query->case_sensitive ? WM_CASEFOLD : 0),
                  0) == WM_MATCH) {
            w_query_process_file(
                ctx->query,
                ctx,
                make_unique<InMemoryFileResult>(file, contentHashCache_));
          }
        }
      }
    }
  }
}
Ejemplo n.º 14
0
/* effectively runs the same query multiple times.  By combining the
 * doublestar walk for both into a single walk, we can then match each
 * file against the list of patterns, terminating that match as soon
 * as any one of them matches the file node.
 */
void InMemoryView::globGeneratorDoublestar(
    struct w_query_ctx* ctx,
    const struct watchman_dir* dir,
    const struct watchman_glob_tree* node,
    const char* dir_name,
    uint32_t dir_name_len) const {
  bool matched;

  // First step is to walk the set of files contained in this node
  for (auto& it : dir->files) {
    auto file = it.second.get();
    auto file_name = file->getName();

    ctx->bumpNumWalked();

    if (!file->exists) {
      // Globs can only match files that exist
      continue;
    }

    auto subject = make_path_name(
        dir_name, dir_name_len, file_name.data(), file_name.size());

    // Now that we have computed the name of this candidate file node,
    // attempt to match against each of the possible doublestar patterns
    // in turn.  As soon as any one of them matches we can stop this loop
    // as it doesn't make a lot of sense to yield multiple results for
    // the same file.
    for (const auto& child_node : node->doublestar_children) {
      matched = wildmatch(
                    child_node->pattern.c_str(),
                    subject.c_str(),
                    ctx->query->glob_flags | WM_PATHNAME |
                        (ctx->query->case_sensitive ? 0 : WM_CASEFOLD),
                    0) == WM_MATCH;

      if (matched) {
        w_query_process_file(
            ctx->query,
            ctx,
            make_unique<InMemoryFileResult>(file, contentHashCache_));
        // No sense running multiple matches for this same file node
        // if this one succeeded.
        break;
      }
    }
  }

  // And now walk down to any dirs; all dirs are eligible
  for (auto& it : dir->dirs) {
    const auto child = it.second.get();

    if (!child->last_check_existed) {
      // Globs can only match files in dirs that exist
      continue;
    }

    auto subject = make_path_name(
        dir_name, dir_name_len, child->name.data(), child->name.size());
    globGeneratorDoublestar(ctx, child, node, subject.data(), subject.size());
  }
}