예제 #1
0
파일: packed-backend.c 프로젝트: guban/git
/*
 * Create a newly-allocated `snapshot` of the `packed-refs` file in
 * its current state and return it. The return value will already have
 * its reference count incremented.
 *
 * A comment line of the form "# pack-refs with: " may contain zero or
 * more traits. We interpret the traits as follows:
 *
 *   Neither `peeled` nor `fully-peeled`:
 *
 *      Probably no references are peeled. But if the file contains a
 *      peeled value for a reference, we will use it.
 *
 *   `peeled`:
 *
 *      References under "refs/tags/", if they *can* be peeled, *are*
 *      peeled in this file. References outside of "refs/tags/" are
 *      probably not peeled even if they could have been, but if we find
 *      a peeled value for such a reference we will use it.
 *
 *   `fully-peeled`:
 *
 *      All references in the file that can be peeled are peeled.
 *      Inversely (and this is more important), any references in the
 *      file for which no peeled value is recorded is not peelable. This
 *      trait should typically be written alongside "peeled" for
 *      compatibility with older clients, but we do not require it
 *      (i.e., "peeled" is a no-op if "fully-peeled" is set).
 *
 *   `sorted`:
 *
 *      The references in this file are known to be sorted by refname.
 */
static struct snapshot *create_snapshot(struct packed_ref_store *refs)
{
	struct snapshot *snapshot = xcalloc(1, sizeof(*snapshot));
	int sorted = 0;

	snapshot->refs = refs;
	acquire_snapshot(snapshot);
	snapshot->peeled = PEELED_NONE;

	if (!load_contents(snapshot))
		return snapshot;

	/* If the file has a header line, process it: */
	if (snapshot->buf < snapshot->eof && *snapshot->buf == '#') {
		struct strbuf tmp = STRBUF_INIT;
		char *p;
		const char *eol;
		struct string_list traits = STRING_LIST_INIT_NODUP;

		eol = memchr(snapshot->buf, '\n',
			     snapshot->eof - snapshot->buf);
		if (!eol)
			die_unterminated_line(refs->path,
					      snapshot->buf,
					      snapshot->eof - snapshot->buf);

		strbuf_add(&tmp, snapshot->buf, eol - snapshot->buf);

		if (!skip_prefix(tmp.buf, "# pack-refs with:", (const char **)&p))
			die_invalid_line(refs->path,
					 snapshot->buf,
					 snapshot->eof - snapshot->buf);

		string_list_split_in_place(&traits, p, ' ', -1);

		if (unsorted_string_list_has_string(&traits, "fully-peeled"))
			snapshot->peeled = PEELED_FULLY;
		else if (unsorted_string_list_has_string(&traits, "peeled"))
			snapshot->peeled = PEELED_TAGS;

		sorted = unsorted_string_list_has_string(&traits, "sorted");

		/* perhaps other traits later as well */

		/* The "+ 1" is for the LF character. */
		snapshot->header_len = eol + 1 - snapshot->buf;

		string_list_clear(&traits, 0);
		strbuf_release(&tmp);
	}

	verify_buffer_safe(snapshot);

	if (!sorted) {
		sort_snapshot(snapshot);

		/*
		 * Reordering the records might have moved a short one
		 * to the end of the buffer, so verify the buffer's
		 * safety again:
		 */
		verify_buffer_safe(snapshot);
	}

	if (mmap_strategy != MMAP_OK && snapshot->mmapped) {
		/*
		 * We don't want to leave the file mmapped, so we are
		 * forced to make a copy now:
		 */
		size_t size = snapshot->eof -
			(snapshot->buf + snapshot->header_len);
		char *buf_copy = xmalloc(size);

		memcpy(buf_copy, snapshot->buf + snapshot->header_len, size);
		clear_snapshot_buffer(snapshot);
		snapshot->buf = buf_copy;
		snapshot->eof = buf_copy + size;
	}

	return snapshot;
}
예제 #2
0
trial<actor> spawn(message const& params) {
  auto schema_file = ""s;
  auto output = "-"s;
  auto r = params.extract_opts({
    {"schema,s", "alternate schema file", schema_file},
    {"write,w", "path to write events to", output},
    {"uds,u", "treat -w as UNIX domain socket to connect to"}
  });
  // Setup a custom schema.
  schema sch;
  if (!schema_file.empty()) {
    auto t = load_contents(schema_file);
    if (!t)
      return t.error();
    auto s = to<schema>(*t);
    if (!s)
      return error{"failed to load schema"};
    sch = std::move(*s);
  }
  // Facilitate actor shutdown when returning with error.
  actor snk;
  auto guard = make_scope_guard([&] { anon_send_exit(snk, exit::error); });
  // The "pcap" and "bro" sink manually handle file output. All other
  // sources are file-based and we setup their input stream here.
  auto& format = params.get_as<std::string>(0);
  std::unique_ptr<std::ostream> out;
  if (!(format == "pcap" || format == "bro")) {
    if (r.opts.count("uds") > 0) {
      if (output == "-")
        return error{"cannot use stdout as UNIX domain socket"};
      auto uds = util::unix_domain_socket::connect(output);
      if (!uds)
        return error{"failed to connect to UNIX domain socket at ", output};
      auto remote_fd = uds.recv_fd(); // Blocks!
      out = std::make_unique<util::fdostream>(remote_fd);
    } else if (output == "-") {
      out = std::make_unique<util::fdostream>(1); // stdout
    } else {
      out = std::make_unique<std::ofstream>(output);
    }
  }
  if (format == "pcap") {
#ifndef VAST_HAVE_PCAP
    return error{"not compiled with pcap support"};
#else
    auto flush = 10000u;
    r = r.remainder.extract_opts({
      {"flush,f", "flush to disk after this many packets", flush}
    });
    if (!r.error.empty())
      return error{std::move(r.error)};
    snk = caf::spawn<priority_aware>(pcap, sch, output, flush);
#endif
  } else if (format == "bro") {
    snk = caf::spawn(bro, output);
  } else if (format == "csv") {
    snk = caf::spawn(csv, std::move(out));
  } else if (format == "ascii") {
    snk = caf::spawn(ascii, std::move(out));
  } else if (format == "json") {
    r = r.remainder.extract_opts({
      {"flatten,f", "flatten records"}
    });
    snk = caf::spawn(sink::json, std::move(out), r.opts.count("flatten") > 0);
  // FIXME: currently the "vast export" command cannot take sink parameters,
  // which is why we add a hacky convenience sink called "flat-json". We should
  // have a command line format akin to "vast export json -f query ...",
  // which would allow passing both sink and exporter arguments.
  } else if (format == "flat-json") {
    snk = caf::spawn(sink::json, std::move(out), true);
  } else {
    return error{"invalid export format: ", format};
  }
  guard.disable();
  return snk;
}