Example #1
0
static bool parse_relative_root(w_root_t *root, w_query *res, json_t *query)
{
  json_t *relative_root;
  w_string_t *path, *canon_path;

  relative_root = json_object_get(query, "relative_root");
  if (!relative_root) {
    return true;
  }

  if (!json_is_string(relative_root)) {
    res->errmsg = strdup("'relative_root' must be a string");
    return false;
  }

  path = w_string_new(json_string_value(relative_root));
  canon_path = w_string_canon_path(path);
  res->relative_root = w_string_path_cat(root->root_path, canon_path);
  res->relative_root_slash = w_string_make_printf("%.*s%c",
        res->relative_root->len, res->relative_root->buf,
        WATCHMAN_DIR_SEP);
  w_string_delref(path);
  w_string_delref(canon_path);

  return true;
}
Example #2
0
static void build_list(struct pending_list *list, w_string_t *parent_name,
                       size_t depth, size_t num_files, size_t num_dirs) {
  size_t i;
  for (i = 0; i < num_files; i++) {
    struct watchman_pending_fs *item = next_pending(list);
    item->path = w_string_make_printf("%.*s/file%d", parent_name->len,
                                      parent_name->buf, i);
    item->flags = W_PENDING_VIA_NOTIFY;
  }

  for (i = 0; i < num_dirs; i++) {
    struct watchman_pending_fs *item = next_pending(list);
    item->path = w_string_make_printf("%.*s/dir%d", parent_name->len,
                                      parent_name->buf, i);
    item->flags = W_PENDING_RECURSIVE;

    if (depth > 0) {
      build_list(list, item->path, depth - 1, num_files, num_dirs);
    }
  }
}
Example #3
0
static void *fsevents_thread(void *arg)
{
  w_root_t *root = arg;
  FSEventStreamContext ctx;
  CFMutableArrayRef parray;
  CFStringRef cpath;
  FSEventStreamRef fs_stream = NULL;
  CFFileDescriptorContext fdctx;
  CFFileDescriptorRef fdref;
  struct fsevents_root_state *state = root->watch;
  double latency;

  w_set_thread_name("fsevents %.*s", root->root_path->len,
      root->root_path->buf);

  // Block until fsevents_root_start is waiting for our initialization
  pthread_mutex_lock(&state->fse_mtx);

  memset(&ctx, 0, sizeof(ctx));
  ctx.info = root;

  memset(&fdctx, 0, sizeof(fdctx));
  fdctx.info = root;

  fdref = CFFileDescriptorCreate(NULL, state->fse_pipe[0], true,
      fse_pipe_callback, &fdctx);
  CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
  {
    CFRunLoopSourceRef fdsrc;

    fdsrc = CFFileDescriptorCreateRunLoopSource(NULL, fdref, 0);
    if (!fdsrc) {
      root->failure_reason = w_string_new(
          "CFFileDescriptorCreateRunLoopSource failed");
      goto done;
    }
    CFRunLoopAddSource(CFRunLoopGetCurrent(), fdsrc, kCFRunLoopDefaultMode);
    CFRelease(fdsrc);
  }

  parray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
  if (!parray) {
    root->failure_reason = w_string_new("CFArrayCreateMutable failed");
    goto done;
  }

  cpath = CFStringCreateWithBytes(NULL, (const UInt8*)root->root_path->buf,
      root->root_path->len, kCFStringEncodingUTF8,
      false);
  if (!cpath) {
    root->failure_reason = w_string_new("CFStringCreateWithBytes failed");
    goto done;
  }

  CFArrayAppendValue(parray, cpath);
  CFRelease(cpath);

  latency = cfg_get_double(root, "fsevents_latency", 0.01),
  w_log(W_LOG_DBG,
      "FSEventStreamCreate for path %.*s with latency %f seconds\n",
      root->root_path->len,
      root->root_path->buf,
      latency);

  fs_stream = FSEventStreamCreate(NULL, fse_callback,
      &ctx, parray, kFSEventStreamEventIdSinceNow,
      latency,
      kFSEventStreamCreateFlagNoDefer|
      kFSEventStreamCreateFlagWatchRoot|
      kFSEventStreamCreateFlagFileEvents);

  if (!fs_stream) {
    root->failure_reason = w_string_new("FSEventStreamCreate failed");
    goto done;
  }

  FSEventStreamScheduleWithRunLoop(fs_stream,
      CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  if (!FSEventStreamStart(fs_stream)) {
    root->failure_reason = w_string_make_printf(
        "FSEventStreamStart failed, look at your log file %s for "
        "lines mentioning FSEvents and see "
        "https://facebook.github.io/watchman/docs/troubleshooting.html#"
        "fsevents for more information\n", log_name);
    goto done;
  }

  // Signal to fsevents_root_start that we're done initializing
  pthread_cond_signal(&state->fse_cond);
  pthread_mutex_unlock(&state->fse_mtx);

  // Process the events stream until we get signalled to quit
  CFRunLoopRun();

  // Since the goto's above hold fse_mtx, we should grab it here
  pthread_mutex_lock(&state->fse_mtx);
done:
  if (fs_stream) {
    FSEventStreamStop(fs_stream);
    FSEventStreamInvalidate(fs_stream);
    FSEventStreamRelease(fs_stream);
  }
  if (fdref) {
    CFRelease(fdref);
  }

  // Signal to fsevents_root_start that we're done initializing in
  // the failure path.  We'll also do this after we've completed
  // the run loop in the success path; it's a spurious wakeup but
  // harmless and saves us from adding and setting a control flag
  // in each of the failure `goto` statements. fsevents_root_dtor
  // will `pthread_join` us before `state` is freed.
  pthread_cond_signal(&state->fse_cond);
  pthread_mutex_unlock(&state->fse_mtx);

  w_log(W_LOG_DBG, "fse_thread done\n");
  w_root_delref(root);
  return NULL;
}