Example #1
0
static void show_ref(const char *path, const unsigned char *sha1)
{
	if (ref_is_hidden(path))
		return;

	if (sent_capabilities) {
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
	} else {
		struct strbuf cap = STRBUF_INIT;

		strbuf_addstr(&cap,
			      "report-status delete-refs side-band-64k quiet");
		if (advertise_atomic_push)
			strbuf_addstr(&cap, " atomic");
		if (prefer_ofs_delta)
			strbuf_addstr(&cap, " ofs-delta");
		if (push_cert_nonce)
			strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
		strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
		packet_write(1, "%s %s%c%s\n",
			     sha1_to_hex(sha1), path, 0, cap.buf);
		strbuf_release(&cap);
		sent_capabilities = 1;
	}
}
Example #2
0
static int send_ref(const char *refname, const struct object_id *oid,
		    int flag, void *cb_data)
{
	static const char *capabilities = "multi_ack thin-pack side-band"
		" side-band-64k ofs-delta shallow no-progress"
		" include-tag multi_ack_detailed";
	const char *refname_nons = strip_namespace(refname);
	struct object_id peeled;

	if (mark_our_ref(refname_nons, refname, oid))
		return 0;

	if (capabilities) {
		struct strbuf symref_info = STRBUF_INIT;

		format_symref_info(&symref_info, cb_data);
		packet_write(1, "%s %s%c%s%s%s%s%s agent=%s\n",
			     oid_to_hex(oid), refname_nons,
			     0, capabilities,
			     (allow_unadvertised_object_request & ALLOW_TIP_SHA1) ?
				     " allow-tip-sha1-in-want" : "",
			     (allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1) ?
				     " allow-reachable-sha1-in-want" : "",
			     stateless_rpc ? " no-done" : "",
			     symref_info.buf,
			     git_user_agent_sanitized());
		strbuf_release(&symref_info);
	} else {
		packet_write(1, "%s %s\n", oid_to_hex(oid), refname_nons);
	}
	capabilities = NULL;
	if (!peel_ref(refname, peeled.hash))
		packet_write(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
	return 0;
}
Example #3
0
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
	static const char *capabilities = "multi_ack thin-pack side-band"
		" side-band-64k ofs-delta shallow no-progress"
		" include-tag multi_ack_detailed";
	const char *refname_nons = strip_namespace(refname);
	unsigned char peeled[20];

	if (mark_our_ref(refname, sha1, flag, NULL))
		return 0;

	if (capabilities) {
		struct strbuf symref_info = STRBUF_INIT;

		format_symref_info(&symref_info, cb_data);
		packet_write(1, "%s %s%c%s%s%s%s agent=%s\n",
			     sha1_to_hex(sha1), refname_nons,
			     0, capabilities,
			     allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
			     stateless_rpc ? " no-done" : "",
			     symref_info.buf,
			     git_user_agent_sanitized());
		strbuf_release(&symref_info);
	} else {
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
	}
	capabilities = NULL;
	if (!peel_ref(refname, peeled))
		packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
	return 0;
}
Example #4
0
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
	static const char *capabilities = "multi_ack thin-pack side-band"
		" side-band-64k ofs-delta shallow no-progress"
		" include-tag multi_ack_detailed";
	struct object *o = parse_object(sha1);

	if (!o)
		die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));

	if (capabilities)
		packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname,
			     0, capabilities,
			     stateless_rpc ? " no-done" : "");
	else
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
	capabilities = NULL;
	if (!(o->flags & OUR_REF)) {
		o->flags |= OUR_REF;
		nr_our_refs++;
	}
	if (o->type == OBJ_TAG) {
		o = deref_tag(o, refname, 0);
		if (o)
			packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
	}
	return 0;
}
Example #5
0
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
	const char *sent_argv[MAX_ARGS];
	struct child_process cld = { sent_argv };
	cld.out = cld.err = -1;
	cld.git_cmd = 1;

	if (argc != 2)
		usage(upload_archive_usage);

	if (!enter_repo(argv[1], 0))
		die("'%s' does not appear to be a git repository", argv[1]);

	prepare_argv(sent_argv, argv);
	if (start_command(&cld)) {
		int err = errno;
		packet_write(1, "NACK fork failed on the remote side\n");
		die("upload-archive: %s", strerror(err));
	}

	/* parent - read from child, multiplex and send out to fd#1 */
	packet_write(1, "ACK\n");
	packet_flush(1);

	while (1) {
		struct pollfd pfd[2];
		int status;

		pfd[0].fd = cld.out;
		pfd[0].events = POLLIN;
		pfd[1].fd = cld.err;
		pfd[1].events = POLLIN;
		if (poll(pfd, 2, -1) < 0) {
			if (errno != EINTR) {
				error("poll failed resuming: %s",
				      strerror(errno));
				sleep(1);
			}
			continue;
		}
		if (pfd[1].revents & POLLIN)
			/* Status stream ready */
			if (process_input(pfd[1].fd, 2))
				continue;
		if (pfd[0].revents & POLLIN)
			/* Data stream ready */
			if (process_input(pfd[0].fd, 1))
				continue;

		if (waitpid(cld.pid, &status, 0) < 0)
			error_clnt("%s", lostchild);
		else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
			error_clnt("%s", deadchild);
		packet_flush(1);
		break;
	}
	return 0;
}
Example #6
0
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
	if (!capabilities_to_send)
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
	else
		packet_write(1, "%s %s%c%s\n",
			     sha1_to_hex(sha1), path, 0, capabilities_to_send);
	capabilities_to_send = NULL;
	return 0;
}
Example #7
0
static void show_ref(const char *path, const unsigned char *sha1)
{
	if (sent_capabilities)
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
	else
		packet_write(1, "%s %s%c%s%s\n",
			     sha1_to_hex(sha1), path, 0,
			     " report-status delete-refs side-band-64k",
			     prefer_ofs_delta ? " ofs-delta" : "");
	sent_capabilities = 1;
}
Example #8
0
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
	struct child_process writer = { argv };

	/*
	 * Set up sideband subprocess.
	 *
	 * We (parent) monitor and read from child, sending its fd#1 and fd#2
	 * multiplexed out to our fd#1.  If the child dies, we tell the other
	 * end over channel #3.
	 */
	argv[0] = "upload-archive--writer";
	writer.out = writer.err = -1;
	writer.git_cmd = 1;
	if (start_command(&writer)) {
		int err = errno;
		packet_write(1, "NACK unable to spawn subprocess\n");
		die("upload-archive: %s", strerror(err));
	}

	packet_write(1, "ACK\n");
	packet_flush(1);

	while (1) {
		struct pollfd pfd[2];

		pfd[0].fd = writer.out;
		pfd[0].events = POLLIN;
		pfd[1].fd = writer.err;
		pfd[1].events = POLLIN;
		if (poll(pfd, 2, -1) < 0) {
			if (errno != EINTR) {
				error("poll failed resuming: %s",
				      strerror(errno));
				sleep(1);
			}
			continue;
		}
		if (pfd[1].revents & POLLIN)
			/* Status stream ready */
			if (process_input(pfd[1].fd, 2))
				continue;
		if (pfd[0].revents & POLLIN)
			/* Data stream ready */
			if (process_input(pfd[0].fd, 1))
				continue;

		if (finish_command(&writer))
			error_clnt("%s", deadchild);
		packet_flush(1);
		break;
	}
	return 0;
}
static int run_remote_archiver(int argc, const char **argv,
			       const char *remote, const char *exec,
			       const char *name_hint)
{
	char buf[LARGE_PACKET_MAX];
	int fd[2], i, len, rv;
	struct transport *transport;
	struct remote *_remote;

	_remote = remote_get(remote);
	if (!_remote->url[0])
		die(_("git archive: Remote with no URL"));
	transport = transport_get(_remote, _remote->url[0]);
	transport_connect(transport, "git-upload-archive", exec, fd);

	/*
	 * Inject a fake --format field at the beginning of the
	 * arguments, with the format inferred from our output
	 * filename. This way explicit --format options can override
	 * it.
	 */
	if (name_hint) {
		const char *format = archive_format_from_filename(name_hint);
		if (format)
			packet_write(fd[1], "argument --format=%s\n", format);
	}
	for (i = 1; i < argc; i++)
		packet_write(fd[1], "argument %s\n", argv[i]);
	packet_flush(fd[1]);

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (!len)
		die(_("git archive: expected ACK/NAK, got EOF"));
	if (buf[len-1] == '\n')
		buf[--len] = 0;
	if (strcmp(buf, "ACK")) {
		if (len > 5 && !prefixcmp(buf, "NACK "))
			die(_("git archive: NACK %s"), buf + 5);
		die(_("git archive: protocol error"));
	}

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (len)
		die(_("git archive: expected a flush"));

	/* Now, start reading from fd[0] and spit it out to stdout */
	rv = recv_sideband("archive", fd[0], 1);
	rv |= transport_disconnect(transport);

	return !!rv;
}
Example #10
0
static void report(const char *unpack_status)
{
	struct command *cmd;
	packet_write(1, "unpack %s\n",
		     unpack_status ? unpack_status : "ok");
	for (cmd = commands; cmd; cmd = cmd->next) {
		if (!cmd->error_string)
			packet_write(1, "ok %s\n",
				     cmd->ref_name);
		else
			packet_write(1, "ng %s %s\n",
				     cmd->ref_name, cmd->error_string);
	}
	packet_flush(1);
}
Example #11
0
static void show_ref(const char *path, const unsigned char *sha1)
{
	if (ref_is_hidden(path))
		return;

	if (sent_capabilities)
		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
	else
		packet_write(1, "%s %s%c%s%s agent=%s\n",
			     sha1_to_hex(sha1), path, 0,
			     " report-status delete-refs side-band-64k quiet",
			     prefer_ofs_delta ? " ofs-delta" : "",
			     git_user_agent_sanitized());
	sent_capabilities = 1;
}
Example #12
0
static int daemon_error(const char *dir, const char *msg)
{
	if (!informative_errors)
		msg = "access denied or repository not exported";
	packet_write(1, "ERR %s: %s", msg, dir);
	return -1;
}
Example #13
0
static void get_info_refs(char *arg)
{
	const char *service_name = get_parameter("service");
	struct strbuf buf = STRBUF_INIT;

	hdr_nocache();

	if (service_name) {
		const char *argv[] = {NULL /* service name */,
			"--stateless-rpc", "--advertise-refs",
			".", NULL};
		struct rpc_service *svc = select_service(service_name);

		strbuf_addf(&buf, "application/x-git-%s-advertisement",
			svc->name);
		hdr_str(content_type, buf.buf);
		end_headers();

		packet_write(1, "# service=git-%s\n", svc->name);
		packet_flush(1);

		argv[0] = svc->name;
		run_service(argv);

	} else {
		select_getanyfile();
		for_each_namespaced_ref(show_text_ref, &buf);
		send_strbuf("text/plain", &buf);
	}
	strbuf_release(&buf);
}
Example #14
0
static int get_common_commits(void)
{
	static char line[1000];
	unsigned char sha1[20];
	char last_hex[41];

	save_commit_buffer = 0;

	for (;;) {
		int len = packet_read_line(0, line, sizeof(line));
		reset_timeout();

		if (!len) {
			if (have_obj.nr == 0 || multi_ack)
				packet_write(1, "NAK\n");
			if (stateless_rpc)
				exit(0);
			continue;
		}
		strip(line, len);
		if (!prefixcmp(line, "have ")) {
			switch (got_sha1(line+5, sha1)) {
			case -1: /* they have what we do not */
				if (multi_ack && ok_to_give_up()) {
					const char *hex = sha1_to_hex(sha1);
					if (multi_ack == 2)
						packet_write(1, "ACK %s ready\n", hex);
					else
						packet_write(1, "ACK %s continue\n", hex);
				}
				break;
			default:
				memcpy(last_hex, sha1_to_hex(sha1), 41);
				if (multi_ack == 2)
					packet_write(1, "ACK %s common\n", last_hex);
				else if (multi_ack)
					packet_write(1, "ACK %s continue\n", last_hex);
				else if (have_obj.nr == 1)
					packet_write(1, "ACK %s\n", last_hex);
				break;
			}
			continue;
		}
		if (!strcmp(line, "done")) {
			if (have_obj.nr > 0) {
				if (multi_ack)
					packet_write(1, "ACK %s\n", last_hex);
				return 0;
			}
			packet_write(1, "NAK\n");
			return -1;
		}
		die("git upload-pack: expected SHA1 list, got '%s'", line);
	}
}
Example #15
0
int cmd_send_cache_hash (SESSION * session)
{
	int ret;
        struct buf* buf = buf_new();
	buf_append_data(buf, session->cache_hash, sizeof (session->cache_hash));

	ret = packet_write (session, 0x0f, buf->ptr, buf->len);
	DSFYDEBUG ("packet_write() returned %d\n", ret);
	buf_free(buf);

	return ret;
}
Example #16
0
/*
 * Open a connection using Git's native protocol.
 *
 * The caller is responsible for freeing hostandport, but this function may
 * modify it (for example, to truncate it to remove the port part).
 */
static struct child_process *git_connect_git(int fd[2], char *hostandport,
					     const char *path, const char *prog,
					     enum protocol_version version,
					     int flags)
{
	struct child_process *conn;
	struct strbuf request = STRBUF_INIT;
	/*
	 * Set up virtual host information based on where we will
	 * connect, unless the user has overridden us in
	 * the environment.
	 */
	char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST");
	if (target_host)
		target_host = xstrdup(target_host);
	else
		target_host = xstrdup(hostandport);

	transport_check_allowed("git");

	/*
	 * These underlying connection commands die() if they
	 * cannot connect.
	 */
	if (git_use_proxy(hostandport))
		conn = git_proxy_connect(fd, hostandport);
	else
		conn = git_tcp_connect(fd, hostandport, flags);
	/*
	 * Separate original protocol components prog and path
	 * from extended host header with a NUL byte.
	 *
	 * Note: Do not add any other headers here!  Doing so
	 * will cause older git-daemon servers to crash.
	 */
	strbuf_addf(&request,
		    "%s %s%chost=%s%c",
		    prog, path, 0,
		    target_host, 0);

	/* If using a new version put that stuff here after a second null byte */
	if (version > 0) {
		strbuf_addch(&request, '\0');
		strbuf_addf(&request, "version=%d%c",
			    version, '\0');
	}

	packet_write(fd[1], request.buf, request.len);

	free(target_host);
	strbuf_release(&request);
	return conn;
}
Example #17
0
/** Returns -1 if there was an error writing.
 *  Otherwise the number of bytes written is returned */
int connection_write( struct connection   * c,
                      const struct packet * p )
{
  uint16_t buff_size = p->size + 4;
  unsigned char * buffer = malloc( buff_size );
  init_packet( buffer, p->size + 4 );
  packet_write( buffer, p );
  int16_t nb_bytes = write( c->fd_out, buffer, buff_size );
  if ( nb_bytes == -1 ) {
#ifndef EMBEDDED
    perror("write");
#endif
    return -1;
  }
  free( buffer );
  return nb_bytes;
}
Example #18
0
static void udp_write(struct dechunkiser_ctx *o, int id, uint8_t *data, int size)
{
  int i = 0;

  while (i < size) {
    int stream, psize;

    udp_payload_header_parse(data + i, &psize, &stream);
    if (stream > o->ports) {
      fprintf(stderr, "Bad stream %d > %d\n", stream, o->ports);

      return;
    }

    packet_write(o->outfd, o->ip, o->port[stream], data + i + UDP_PAYLOAD_HEADER_SIZE, psize);
    i += UDP_PAYLOAD_HEADER_SIZE + psize;
  }
}
Example #19
0
int main(int argc, char *argv[]) {
	int fd, opt;
	char pktbuf[1500], *iface_name = NULL;
	ssize_t len;

	while((opt = getopt(argc, argv, "hi:")) != -1) {
		switch (opt) {
			case 'i':
				iface_name = optarg;
				break;
			case 'h':
			default:
				usage();
				return EXIT_FAILURE;
		}
	}

	if (iface_name == NULL) {
		fprintf(stderr, "No interface set\n");
		return EXIT_FAILURE;
	}

	
	fd = sock_open_raw(iface_name);
	if (fd < 0) {
		perror("sock_open_raw");
		return EXIT_FAILURE;
	}
	
	len = packet_read(STDIN_FILENO, pktbuf, sizeof(pktbuf));
	if (len < 0) {
		perror("packet_read");
		return EXIT_FAILURE;
	}
	
	close(STDIN_FILENO);
	if (packet_write(fd, pktbuf, (size_t)len) != len) {
		perror("packet_write");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}
Example #20
0
static error_t 
stream_write (struct pq *pq, void *source,
	      char *data, size_t data_len, size_t *amount)
{
  struct packet *packet = pq_tail (pq, PACKET_TYPE_DATA, source);

  if (packet_readable (packet) > 0
      && data_len > PACKET_SIZE_LARGE
      && (! page_aligned (data - packet->buf_end)
	  || ! packet_ensure_efficiently (packet, data_len)))
    /* Put a large page-aligned transfer in its own packet, if it's
       page-aligned `differently' than the end of the current packet, or if
       the current packet can't be extended in place.  */
    packet = pq_queue (pq, PACKET_TYPE_DATA, source);

  if (!packet)
    return ENOBUFS;
  else
    return packet_write (packet, data, data_len, amount);
}
Example #21
0
static void rtp_write(struct dechunkiser_ctx *ctx, int id, uint8_t *data, int size) {
  uint8_t* data_end = data + size;
  printf_log(ctx, 2, "Got chunk of size %i", size);
  while (data < data_end) {
    // NOTE: `stream` here is the index in the ports array.
    int stream, psize;

    rtp_payload_per_pkt_header_parse(data, &psize, &stream);
    data += RTP_PAYLOAD_PER_PKT_HEADER_SIZE;
    if (stream > ctx->ports_len) {
      printf_log(ctx, 1, "Received Chunk with bad stream %d > %d",
                 stream, ctx->ports_len);
      return;
    }

    printf_log(ctx, 2,
               "sending packet of size %i from port id #%i to port %i",
               psize, stream, ctx->ports[stream]);
    packet_write(ctx->outfd, ctx->ip, ctx->ports[stream], data, psize);
    data += psize;
  }
}
static int run_remote_archiver(int argc, const char **argv,
			       const char *remote, const char *exec)
{
	char buf[LARGE_PACKET_MAX];
	int fd[2], i, len, rv;
	struct transport *transport;
	struct remote *_remote;

	_remote = remote_get(remote);
	if (!_remote->url[0])
		die(_("git archive: Remote with no URL"));
	transport = transport_get(_remote, _remote->url[0]);
	transport_connect(transport, "git-upload-archive", exec, fd);

	for (i = 1; i < argc; i++)
		packet_write(fd[1], "argument %s\n", argv[i]);
	packet_flush(fd[1]);

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (!len)
		die(_("git archive: expected ACK/NAK, got EOF"));
	if (buf[len-1] == '\n')
		buf[--len] = 0;
	if (strcmp(buf, "ACK")) {
		if (len > 5 && !prefixcmp(buf, "NACK "))
			die(_("git archive: NACK %s"), buf + 5);
		die(_("git archive: protocol error"));
	}

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (len)
		die(_("git archive: expected a flush"));

	/* Now, start reading from fd[0] and spit it out to stdout */
	rv = recv_sideband("archive", fd[0], 1);
	rv |= transport_disconnect(transport);

	return !!rv;
}
Example #23
0
static int run_remote_archiver(int argc, const char **argv,
			       const char *remote, const char *exec)
{
	char *url, buf[LARGE_PACKET_MAX];
	int fd[2], i, len, rv;
	struct child_process *conn;

	url = xstrdup(remote);
	conn = git_connect(fd, url, exec, 0);

	for (i = 1; i < argc; i++)
		packet_write(fd[1], "argument %s\n", argv[i]);
	packet_flush(fd[1]);

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (!len)
		die("git archive: expected ACK/NAK, got EOF");
	if (buf[len-1] == '\n')
		buf[--len] = 0;
	if (strcmp(buf, "ACK")) {
		if (len > 5 && !prefixcmp(buf, "NACK "))
			die("git archive: NACK %s", buf + 5);
		die("git archive: protocol error");
	}

	len = packet_read_line(fd[0], buf, sizeof(buf));
	if (len)
		die("git archive: expected a flush");

	/* Now, start reading from fd[0] and spit it out to stdout */
	rv = recv_sideband("archive", fd[0], 1);
	close(fd[0]);
	close(fd[1]);
	rv |= finish_connect(conn);

	return !!rv;
}
Example #24
0
/*
 * Request ads
 * The response is plain XML
 *
 */
int cmd_requestad (SESSION * session, unsigned char ad_type)
{
	CHANNEL *ch;
	int ret;
	char buf[100];
        struct buf* b = buf_new();

		_snprintf(buf, sizeof(buf), "RequestAd-with-type-%d", ad_type);
	ch = channel_register (buf, dump_generic, NULL);

	DSFYDEBUG
		("allocated channel %d, retrieving ads with type id %d\n",
		 ch->channel_id, ad_type);

        buf_append_u16(b, ch->channel_id);
	buf_append_u8(b, ad_type);

	ret = packet_write (session, CMD_REQUESTAD, b->ptr, b->len);
	DSFYDEBUG ("packet_write() returned %d\n", ret);

	buf_free(b);

	return ret;
}
Example #25
0
int send_pack(struct send_pack_args *args,
	      int fd[], struct child_process *conn,
	      struct ref *remote_refs,
	      struct extra_have_objects *extra_have)
{
	int in = fd[0];
	int out = fd[1];
	struct ref *ref;
	int new_refs;
	int ask_for_status_report = 0;
	int allow_deleting_refs = 0;
	int expect_status_report = 0;
	int ret;

	/* Does the other end support the reporting? */
	if (server_supports("report-status"))
		ask_for_status_report = 1;
	if (server_supports("delete-refs"))
		allow_deleting_refs = 1;
	if (server_supports("ofs-delta"))
		args->use_ofs_delta = 1;

	if (!remote_refs) {
		fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
			"Perhaps you should specify a branch such as 'master'.\n");
		return 0;
	}

	/*
	 * Finally, tell the other end!
	 */
	new_refs = 0;
	for (ref = remote_refs; ref; ref = ref->next) {

		if (ref->peer_ref)
			hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
		else if (!args->send_mirror)
			continue;

		ref->deletion = is_null_sha1(ref->new_sha1);
		if (ref->deletion && !allow_deleting_refs) {
			ref->status = REF_STATUS_REJECT_NODELETE;
			continue;
		}
		if (!ref->deletion &&
		    !hashcmp(ref->old_sha1, ref->new_sha1)) {
			ref->status = REF_STATUS_UPTODATE;
			continue;
		}

		/* This part determines what can overwrite what.
		 * The rules are:
		 *
		 * (0) you can always use --force or +A:B notation to
		 *     selectively force individual ref pairs.
		 *
		 * (1) if the old thing does not exist, it is OK.
		 *
		 * (2) if you do not have the old thing, you are not allowed
		 *     to overwrite it; you would not know what you are losing
		 *     otherwise.
		 *
		 * (3) if both new and old are commit-ish, and new is a
		 *     descendant of old, it is OK.
		 *
		 * (4) regardless of all of the above, removing :B is
		 *     always allowed.
		 */

		ref->nonfastforward =
		    !ref->deletion &&
		    !is_null_sha1(ref->old_sha1) &&
		    (!has_sha1_file(ref->old_sha1)
		      || !ref_newer(ref->new_sha1, ref->old_sha1));

		if (ref->nonfastforward && !ref->force && !args->force_update) {
			ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
			continue;
		}

		if (!ref->deletion)
			new_refs++;

		if (!args->dry_run) {
			char *old_hex = sha1_to_hex(ref->old_sha1);
			char *new_hex = sha1_to_hex(ref->new_sha1);

			if (ask_for_status_report) {
				packet_write(out, "%s %s %s%c%s",
					old_hex, new_hex, ref->name, 0,
					"report-status");
				ask_for_status_report = 0;
				expect_status_report = 1;
			}
			else
				packet_write(out, "%s %s %s",
					old_hex, new_hex, ref->name);
		}
		ref->status = expect_status_report ?
			REF_STATUS_EXPECTING_REPORT :
			REF_STATUS_OK;
	}

	packet_flush(out);
	if (new_refs && !args->dry_run) {
		if (pack_objects(out, remote_refs, extra_have, args) < 0) {
			for (ref = remote_refs; ref; ref = ref->next)
				ref->status = REF_STATUS_NONE;
			return -1;
		}
	}

	if (expect_status_report)
		ret = receive_status(in, remote_refs);
	else
		ret = 0;

	if (ret < 0)
		return ret;
	for (ref = remote_refs; ref; ref = ref->next) {
		switch (ref->status) {
		case REF_STATUS_NONE:
		case REF_STATUS_UPTODATE:
		case REF_STATUS_OK:
			break;
		default:
			return -1;
		}
	}
	return 0;
}
Example #26
0
static void receive_needs(void)
{
	struct object_array shallows = OBJECT_ARRAY_INIT;
	int depth = 0;
	int has_non_tip = 0;

	shallow_nr = 0;
	for (;;) {
		struct object *o;
		const char *features;
		unsigned char sha1_buf[20];
		char *line = packet_read_line(0, NULL);
		reset_timeout();
		if (!line)
			break;

		if (starts_with(line, "shallow ")) {
			unsigned char sha1[20];
			struct object *object;
			if (get_sha1_hex(line + 8, sha1))
				die("invalid shallow line: %s", line);
			object = parse_object(sha1);
			if (!object)
				continue;
			if (object->type != OBJ_COMMIT)
				die("invalid shallow object %s", sha1_to_hex(sha1));
			if (!(object->flags & CLIENT_SHALLOW)) {
				object->flags |= CLIENT_SHALLOW;
				add_object_array(object, NULL, &shallows);
			}
			continue;
		}
		if (starts_with(line, "deepen ")) {
			char *end;
			depth = strtol(line + 7, &end, 0);
			if (end == line + 7 || depth <= 0)
				die("Invalid deepen: %s", line);
			continue;
		}
		if (!starts_with(line, "want ") ||
		    get_sha1_hex(line+5, sha1_buf))
			die("git upload-pack: protocol error, "
			    "expected to get sha, not '%s'", line);

		features = line + 45;

		if (parse_feature_request(features, "multi_ack_detailed"))
			multi_ack = 2;
		else if (parse_feature_request(features, "multi_ack"))
			multi_ack = 1;
		if (parse_feature_request(features, "no-done"))
			no_done = 1;
		if (parse_feature_request(features, "thin-pack"))
			use_thin_pack = 1;
		if (parse_feature_request(features, "ofs-delta"))
			use_ofs_delta = 1;
		if (parse_feature_request(features, "side-band-64k"))
			use_sideband = LARGE_PACKET_MAX;
		else if (parse_feature_request(features, "side-band"))
			use_sideband = DEFAULT_PACKET_MAX;
		if (parse_feature_request(features, "no-progress"))
			no_progress = 1;
		if (parse_feature_request(features, "include-tag"))
			use_include_tag = 1;

		o = parse_object(sha1_buf);
		if (!o)
			die("git upload-pack: not our ref %s",
			    sha1_to_hex(sha1_buf));
		if (!(o->flags & WANTED)) {
			o->flags |= WANTED;
			if (!is_our_ref(o))
				has_non_tip = 1;
			add_object_array(o, NULL, &want_obj);
		}
	}

	/*
	 * We have sent all our refs already, and the other end
	 * should have chosen out of them. When we are operating
	 * in the stateless RPC mode, however, their choice may
	 * have been based on the set of older refs advertised
	 * by another process that handled the initial request.
	 */
	if (has_non_tip)
		check_non_tip();

	if (!use_sideband && daemon_mode)
		no_progress = 1;

	if (depth == 0 && shallows.nr == 0)
		return;
	if (depth > 0) {
		struct commit_list *result = NULL, *backup = NULL;
		int i;
		if (depth == INFINITE_DEPTH && !is_repository_shallow())
			for (i = 0; i < shallows.nr; i++) {
				struct object *object = shallows.objects[i].item;
				object->flags |= NOT_SHALLOW;
			}
		else
			backup = result =
				get_shallow_commits(&want_obj, depth,
						    SHALLOW, NOT_SHALLOW);
		while (result) {
			struct object *object = &result->item->object;
			if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
				packet_write(1, "shallow %s",
						sha1_to_hex(object->sha1));
				register_shallow(object->sha1);
				shallow_nr++;
			}
			result = result->next;
		}
		free_commit_list(backup);
		for (i = 0; i < shallows.nr; i++) {
			struct object *object = shallows.objects[i].item;
			if (object->flags & NOT_SHALLOW) {
				struct commit_list *parents;
				packet_write(1, "unshallow %s",
					sha1_to_hex(object->sha1));
				object->flags &= ~CLIENT_SHALLOW;
				/* make sure the real parents are parsed */
				unregister_shallow(object->sha1);
				object->parsed = 0;
				parse_commit_or_die((struct commit *)object);
				parents = ((struct commit *)object)->parents;
				while (parents) {
					add_object_array(&parents->item->object,
							NULL, &want_obj);
					parents = parents->next;
				}
				add_object_array(object, NULL, &extra_edge_obj);
			}
			/* make sure commit traversal conforms to client */
			register_shallow(object->sha1);
		}
		packet_flush(1);
	} else
		if (shallows.nr > 0) {
			int i;
			for (i = 0; i < shallows.nr; i++)
				register_shallow(shallows.objects[i].item->sha1);
		}

	shallow_nr += shallows.nr;
	free(shallows.objects);
}
Example #27
0
static int get_common_commits(void)
{
	unsigned char sha1[20];
	char last_hex[41];
	int got_common = 0;
	int got_other = 0;
	int sent_ready = 0;

	save_commit_buffer = 0;

	for (;;) {
		char *line = packet_read_line(0, NULL);
		reset_timeout();

		if (!line) {
			if (multi_ack == 2 && got_common
			    && !got_other && ok_to_give_up()) {
				sent_ready = 1;
				packet_write(1, "ACK %s ready\n", last_hex);
			}
			if (have_obj.nr == 0 || multi_ack)
				packet_write(1, "NAK\n");

			if (no_done && sent_ready) {
				packet_write(1, "ACK %s\n", last_hex);
				return 0;
			}
			if (stateless_rpc)
				exit(0);
			got_common = 0;
			got_other = 0;
			continue;
		}
		if (starts_with(line, "have ")) {
			switch (got_sha1(line+5, sha1)) {
			case -1: /* they have what we do not */
				got_other = 1;
				if (multi_ack && ok_to_give_up()) {
					const char *hex = sha1_to_hex(sha1);
					if (multi_ack == 2) {
						sent_ready = 1;
						packet_write(1, "ACK %s ready\n", hex);
					} else
						packet_write(1, "ACK %s continue\n", hex);
				}
				break;
			default:
				got_common = 1;
				memcpy(last_hex, sha1_to_hex(sha1), 41);
				if (multi_ack == 2)
					packet_write(1, "ACK %s common\n", last_hex);
				else if (multi_ack)
					packet_write(1, "ACK %s continue\n", last_hex);
				else if (have_obj.nr == 1)
					packet_write(1, "ACK %s\n", last_hex);
				break;
			}
			continue;
		}
		if (!strcmp(line, "done")) {
			if (have_obj.nr > 0) {
				if (multi_ack)
					packet_write(1, "ACK %s\n", last_hex);
				return 0;
			}
			packet_write(1, "NAK\n");
			return -1;
		}
		die("git upload-pack: expected SHA1 list, got '%s'", line);
	}
}
Example #28
0
/*
 * This returns a dummy child_process if the transport protocol does not
 * need fork(2), or a struct child_process object if it does.  Once done,
 * finish the connection with finish_connect() with the value returned from
 * this function (it is safe to call finish_connect() with NULL to support
 * the former case).
 *
 * If it returns, the connect is successful; it just dies on errors (this
 * will hopefully be changed in a libification effort, to return NULL when
 * the connection failed).
 */
struct child_process *git_connect(int fd[2], const char *url_orig,
				  const char *prog, int flags)
{
	char *url = xstrdup(url_orig);
	char *host, *path;
	char *end;
	int c;
	struct child_process *conn;
	enum protocol protocol = PROTO_LOCAL;
	int free_path = 0;
	char *port = NULL;
	const char **arg;
	struct strbuf cmd;

	/* Without this we cannot rely on waitpid() to tell
	 * what happened to our children.
	 */
	signal(SIGCHLD, SIG_DFL);

	host = strstr(url, "://");
	if (host) {
		*host = '\0';
		protocol = get_protocol(url);
		host += 3;
		c = '/';
	} else {
		host = url;
		c = ':';
	}

	/*
	 * Don't do destructive transforms with git:// as that
	 * protocol code does '[]' unwrapping of its own.
	 */
	if (host[0] == '[') {
		end = strchr(host + 1, ']');
		if (end) {
			if (protocol != PROTO_GIT) {
				*end = 0;
				host++;
			}
			end++;
		} else
			end = host;
	} else
		end = host;

	path = strchr(end, c);
	if (path && !has_dos_drive_prefix(end)) {
		if (c == ':') {
			protocol = PROTO_SSH;
			*path++ = '\0';
		}
	} else
		path = end;

	if (!path || !*path)
		die("No path specified. See 'man git-pull' for valid url syntax");

	/*
	 * null-terminate hostname and point path to ~ for URL's like this:
	 *    ssh://host.xz/~user/repo
	 */
	if (protocol != PROTO_LOCAL && host != url) {
		char *ptr = path;
		if (path[1] == '~')
			path++;
		else {
			path = xstrdup(ptr);
			free_path = 1;
		}

		*ptr = '\0';
	}

	/*
	 * Add support for ssh port: ssh://host.xy:<port>/...
	 */
	if (protocol == PROTO_SSH && host != url)
		port = get_port(host);

	if (protocol == PROTO_GIT) {
		/* These underlying connection commands die() if they
		 * cannot connect.
		 */
		char *target_host = xstrdup(host);
		if (git_use_proxy(host))
			git_proxy_connect(fd, host);
		else
			git_tcp_connect(fd, host, flags);
		/*
		 * Separate original protocol components prog and path
		 * from extended host header with a NUL byte.
		 *
		 * Note: Do not add any other headers here!  Doing so
		 * will cause older git-daemon servers to crash.
		 */
		packet_write(fd[1],
			     "%s %s%chost=%s%c",
			     prog, path, 0,
			     target_host, 0);
		free(target_host);
		free(url);
		if (free_path)
			free(path);
		return &no_fork;
	}

	conn = xcalloc(1, sizeof(*conn));

	strbuf_init(&cmd, MAX_CMD_LEN);
	strbuf_addstr(&cmd, prog);
	strbuf_addch(&cmd, ' ');
	sq_quote_buf(&cmd, path);
	if (cmd.len >= MAX_CMD_LEN)
		die("command line too long");

	conn->in = conn->out = -1;
	conn->argv = arg = xcalloc(7, sizeof(*arg));
	if (protocol == PROTO_SSH) {
		const char *ssh = getenv("GIT_SSH");
		int putty = ssh && strcasestr(ssh, "plink");
		if (!ssh) ssh = "ssh";

		*arg++ = ssh;
		if (putty && !strcasestr(ssh, "tortoiseplink"))
			*arg++ = "-batch";
		if (port) {
			/* P is for PuTTY, p is for OpenSSH */
			*arg++ = putty ? "-P" : "-p";
			*arg++ = port;
		}
		*arg++ = host;
	}
	else {
		/* remove these from the environment */
		const char *env[] = {
			ALTERNATE_DB_ENVIRONMENT,
			DB_ENVIRONMENT,
			GIT_DIR_ENVIRONMENT,
			GIT_WORK_TREE_ENVIRONMENT,
			GRAFT_ENVIRONMENT,
			INDEX_ENVIRONMENT,
			NO_REPLACE_OBJECTS_ENVIRONMENT,
			NULL
		};
		conn->env = env;
		conn->use_shell = 1;
	}
	*arg++ = cmd.buf;
	*arg = NULL;

	if (start_command(conn))
		die("unable to fork");

	fd[0] = conn->out; /* read from child's stdout */
	fd[1] = conn->in;  /* write to child's stdin */
	strbuf_release(&cmd);
	free(url);
	if (free_path)
		free(path);
	return conn;
}
Example #29
0
// Go back to the previous sync point, then read everything from there to
// the current sync point, not including the NAND blocks.
static int st_backtrack(struct state *st) {
    struct pkt pkt;
    int ret;
    int before_nand = 1;
    
	ret = st->fdh->seek(st->last_run_offset);
    if (-1 == ret) {
        perror("Unable to backtrack");
    }

    // Read every packet from the last 
    while ((ret = packet_get_next_raw(st, &pkt)) == 0) {

        // Eventually we'll hit the sync point that brought us here.
        // Return to searching.
        if (is_sync_point(st, &pkt)) {
            if (pkt.header.type == PACKET_HELLO) {
                pkt.header.sec = 0;
                pkt.header.nsec = 0;
                packet_write(st, &pkt);
            }
            jstate_set(st, ST_SEARCHING);
			st->last_run_offset = st->fdh->pos();
            break;
        }

        else if (is_nand(st, &pkt))
            before_nand = 0;

        else {
            int nsec_dif, sec_dif;
            if (before_nand) {
                sec_dif = st->last_sec_dif;
                nsec_dif = st->last_nsec_dif;
            }
            else {
                sec_dif = st->sec_dif;
                nsec_dif = st->nsec_dif;
            }

            if (nsec_dif > 0) {
                pkt.header.nsec += nsec_dif;
                if (pkt.header.nsec > 1000000000L) {
                    pkt.header.nsec -= 1000000000L;
                    pkt.header.sec++;
                }
                pkt.header.sec += sec_dif;
            }
            else {
                pkt.header.nsec -= nsec_dif;
                if (pkt.header.nsec <= 0) {
                    pkt.header.nsec += 1000000000L;
                    pkt.header.sec--;
                }
                pkt.header.sec -= sec_dif;
            }

            // Fudge the time for the "reset card" command
            // (due to timing weirdness, it can vary widely.)
            if (pkt.header.type == PACKET_COMMAND
             && pkt.data.command.cmd[0] == 'r'
             && pkt.data.command.cmd[1] == 'c') {
                pkt.header.sec = 0;
                pkt.header.nsec = 8;
            }

            st->last_sec = pkt.header.sec;
            st->last_nsec = pkt.header.nsec;
            packet_write(st, &pkt);
        }
    }
    return ret;
}
Example #30
0
static int st_joining(struct state *st) {
    struct pkt pkt;
    int ret;

    // Actually attempt to join the data
    if (st->buffer_offset >= 0) {
        struct pkt pkts[REQUIRED_MATCHES];
        struct pkt old_pkts[REQUIRED_MATCHES];
        int synced = 0;
        int disk_offset = 0;
        int buffer_start = st->buffer_offset;


        for (disk_offset=disk_offset;
             (disk_offset+REQUIRED_MATCHES) < SKIP_AMOUNT && !synced;
             disk_offset++) {

            fill_buffer(st, pkts, REQUIRED_MATCHES, packet_get_next_raw);

            for (st->search_limit = 0;
                 (st->search_limit + REQUIRED_MATCHES) < SKIP_AMOUNT && !synced;
                 st->search_limit++)
            {
                int i;
                int matches_found = 0;
                fill_buffer(st, old_pkts, REQUIRED_MATCHES, buffer_get_packet);

                // Check to see if our run matches up
                for (i=0; i<REQUIRED_MATCHES; i++) {
                    int dat = pkts[i].data.nand_cycle.data;
                    int old_dat = old_pkts[i].data.nand_cycle.data;
                    int ctrl = pkts[i].data.nand_cycle.control;
                    int old_ctrl = old_pkts[i].data.nand_cycle.control;

                    if (dat == old_dat && ctrl == old_ctrl)
                        matches_found++;
                }
                
                // If enough packets match, we're synced
                if (matches_found >= REQUIRED_MATCHES-1) {
                    st->last_sec_dif = st->sec_dif;
                    st->last_nsec_dif = st->nsec_dif;
                    st->sec_dif =
                        -(pkts[REQUIRED_MATCHES/2].header.sec-old_pkts[REQUIRED_MATCHES/2].header.sec);
                    st->nsec_dif =
                        -(pkts[REQUIRED_MATCHES/2].header.nsec-old_pkts[REQUIRED_MATCHES/2].header.nsec);
                    if (st->nsec_dif > 1000000000L) {
                        st->nsec_dif -= 1000000000L;
                        st->sec_dif++;
                    }
                    else if (st->nsec_dif < 0) {
                        st->nsec_dif += 1000000000L;
                        st->sec_dif--;
                    }
                    synced=1;
                    buffer_unget_packet(st, old_pkts);
                }
                else {
                    empty_buffer(st, old_pkts, REQUIRED_MATCHES, buffer_unget_packet);
                    buffer_get_packet(st, old_pkts);
                }
            }

            if (!synced) {
                empty_buffer(st, pkts, REQUIRED_MATCHES, packet_unget);
                empty_buffer(st, old_pkts, REQUIRED_MATCHES,
                        buffer_unget_packet);
                packet_get_next_raw(st, pkts);
            }
        }
        if (!synced)
            printf("Couldn't join\n");

        // Now we're synced, just ignore the rest of the matched-buffer
        // packets.  This is because if they're in the buffer, they've
        // already been written out.
        int tries = 0;
        while ((st->buffer_offset+st->search_limit)%SKIP_AMOUNT != buffer_start-1) {
            struct pkt old_pkt;
            int dat, old_dat, ctrl, old_ctrl;
            buffer_get_packet(st, &old_pkt);
            packet_get_next_raw(st, &pkt);

            dat = pkt.data.nand_cycle.data;
            old_dat = old_pkt.data.nand_cycle.data;
            ctrl = pkt.data.nand_cycle.control;
            old_ctrl = old_pkt.data.nand_cycle.control;
            
            tries++;
            if ((dat != old_dat) || (ctrl != old_ctrl)) {
                printf("Join anomaly after %d tries: %d/%d and %d/%d\n",
                        tries, old_dat, dat, old_ctrl, ctrl);
            }
        }
        st->buffer_offset = -1;
        st->search_limit = 0;
    }

    // Done now, copy data
    while ((ret = packet_get_next_raw(st, &pkt)) == 0) {
        if (!is_nand(st, &pkt)) {
            packet_unget(st, &pkt);
            jstate_set(st, ST_SEARCHING);
            break;
        }

        if (st->nsec_dif > 0) {
            pkt.header.nsec += st->nsec_dif;
            if (pkt.header.nsec > 1000000000L) {
                pkt.header.nsec -= 1000000000L;
                pkt.header.sec++;
            }
            pkt.header.sec += st->sec_dif;
        }
        else {
            pkt.header.nsec -= st->nsec_dif;
            if (pkt.header.nsec <= 0) {
                pkt.header.nsec += 1000000000L;
                pkt.header.sec--;
            }
            pkt.header.sec -= st->sec_dif;
        }
        packet_write(st, &pkt);
        buffer_put_packet(st, &pkt);
    }

    return ret;
}