Example #1
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_fmt(1, "NACK unable to spawn subprocess\n");
		die("upload-archive: %s", strerror(err));
	}

	packet_write_fmt(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_errno("poll failed resuming");
				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;
}
Example #2
0
static int run_remote_archiver(int argc, const char **argv,
			       const char *remote, const char *exec,
			       const char *name_hint)
{
	char *buf;
	int fd[2], i, 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_fmt(fd[1], "argument --format=%s\n", format);
	}
	for (i = 1; i < argc; i++)
		packet_write_fmt(fd[1], "argument %s\n", argv[i]);
	packet_flush(fd[1]);

	buf = packet_read_line(fd[0], NULL);
	if (!buf)
		die(_("git archive: expected ACK/NAK, got a flush packet"));
	if (strcmp(buf, "ACK")) {
		if (starts_with(buf, "NACK "))
			die(_("git archive: NACK %s"), buf + 5);
		if (starts_with(buf, "ERR "))
			die(_("remote error: %s"), buf + 4);
		die(_("git archive: protocol error"));
	}

	if (packet_read_line(fd[0], NULL))
		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 #3
0
static void get_info_refs(struct strbuf *hdr, char *arg)
{
	const char *service_name = get_parameter("service");
	struct strbuf buf = STRBUF_INIT;

	hdr_nocache(hdr);

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

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

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

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

	} else {
		select_getanyfile(hdr);
		for_each_namespaced_ref(show_text_ref, &buf);
		send_strbuf(hdr, "text/plain", &buf);
	}
	strbuf_release(&buf);
}
Example #4
0
File: daemon.c Project: 9b/git
static int daemon_error(const char *dir, const char *msg)
{
	if (!informative_errors)
		msg = "access denied or repository not exported";
	packet_write_fmt(1, "ERR %s: %s", msg, dir);
	return -1;
}
Example #5
0
static void send_unshallow(const struct object_array *shallows)
{
	int i;

	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_fmt(1, "unshallow %s",
					 oid_to_hex(&object->oid));
			object->flags &= ~CLIENT_SHALLOW;
			/*
			 * We want to _register_ "object" as shallow, but we
			 * also need to traverse object's parents to deepen a
			 * shallow clone. Unregister it for now so we can
			 * parse and add the parents to the want list, then
			 * re-register it.
			 */
			unregister_shallow(&object->oid);
			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(the_repository, &object->oid);
	}
}
Example #6
0
static int parse_want(const char *line)
{
	const char *arg;
	if (skip_prefix(line, "want ", &arg)) {
		struct object_id oid;
		struct object *o;

		if (get_oid_hex(arg, &oid))
			die("git upload-pack: protocol error, "
			    "expected to get oid, not '%s'", line);

		o = parse_object(&oid);
		if (!o) {
			packet_write_fmt(1,
					 "ERR upload-pack: not our ref %s",
					 oid_to_hex(&oid));
			die("git upload-pack: not our ref %s",
			    oid_to_hex(&oid));
		}

		if (!(o->flags & WANTED)) {
			o->flags |= WANTED;
			add_object_array(o, NULL, &want_obj);
		}

		return 1;
	}

	return 0;
}
Example #7
0
int upload_pack_v2(struct repository *r, struct argv_array *keys,
		   struct packet_reader *request)
{
	enum fetch_state state = FETCH_PROCESS_ARGS;
	struct upload_pack_data data;

	git_config(upload_pack_config, NULL);

	upload_pack_data_init(&data);
	use_sideband = LARGE_PACKET_MAX;

	while (state != FETCH_DONE) {
		switch (state) {
		case FETCH_PROCESS_ARGS:
			process_args(request, &data);

			if (!want_obj.nr) {
				/*
				 * Request didn't contain any 'want' lines,
				 * guess they didn't want anything.
				 */
				state = FETCH_DONE;
			} else if (data.haves.nr) {
				/*
				 * Request had 'have' lines, so lets ACK them.
				 */
				state = FETCH_SEND_ACKS;
			} else {
				/*
				 * Request had 'want's but no 'have's so we can
				 * immedietly go to construct and send a pack.
				 */
				state = FETCH_SEND_PACK;
			}
			break;
		case FETCH_SEND_ACKS:
			if (process_haves_and_send_acks(&data))
				state = FETCH_SEND_PACK;
			else
				state = FETCH_DONE;
			break;
		case FETCH_SEND_PACK:
			send_shallow_info(&data);

			packet_write_fmt(1, "packfile\n");
			create_pack_file();
			state = FETCH_DONE;
			break;
		case FETCH_DONE:
			continue;
		}
	}

	upload_pack_data_clear(&data);
	return 0;
}
Example #8
0
int cmd_main(int argc, const char **argv)
{
	const char *dir;
	int strict = 0;
	struct option options[] = {
		OPT_BOOL(0, "stateless-rpc", &stateless_rpc,
			 N_("quit after a single request/response exchange")),
		OPT_BOOL(0, "advertise-refs", &advertise_refs,
			 N_("exit immediately after initial ref advertisement")),
		OPT_BOOL(0, "strict", &strict,
			 N_("do not try <directory>/.git/ if <directory> is no Git directory")),
		OPT_INTEGER(0, "timeout", &timeout,
			    N_("interrupt transfer after <n> seconds of inactivity")),
		OPT_END()
	};

	packet_trace_identity("upload-pack");
	check_replace_refs = 0;

	argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);

	if (argc != 1)
		usage_with_options(upload_pack_usage, options);

	if (timeout)
		daemon_mode = 1;

	setup_path();

	dir = argv[0];

	if (!enter_repo(dir, strict))
		die("'%s' does not appear to be a git repository", dir);

	git_config(upload_pack_config, NULL);

	switch (determine_protocol_version_server()) {
	case protocol_v1:
		/*
		 * v1 is just the original protocol with a version string,
		 * so just fall through after writing the version string.
		 */
		if (advertise_refs || !stateless_rpc)
			packet_write_fmt(1, "version 1\n");

		/* fallthrough */
	case protocol_v0:
		upload_pack();
		break;
	case protocol_unknown_version:
		BUG("unknown protocol version");
	}

	return 0;
}
Example #9
0
/*
 * Serialize the list of changes to the given file.  The goal of this
 * is to just serialize the key fields in wt_status so that a
 * later command can rebuilt it and do the printing.
 *
 * We DO NOT include the contents of wt_status_state NOR
 * current branch info.  This info easily gets stale and
 * is relatively quick for the status consumer to compute
 * as necessary.
 */
void wt_status_serialize_v1(int fd, struct wt_status *s)
{
	struct string_list_item *iter;
	int k;

	/*
	 * version header must be first line.
	 */
	packet_write_fmt(fd, "version 1\n");

	wt_serialize_v1_header(s, fd);

	if (s->change.nr > 0) {
		packet_write_fmt(fd, "changed %d\n", s->change.nr);
		for (k = 0; k < s->change.nr; k++) {
			iter = &(s->change.items[k]);
			wt_serialize_v1_changed(s, fd, iter);
		}
		packet_flush(fd);
	}

	if (s->untracked.nr > 0) {
		packet_write_fmt(fd, "untracked %d\n", s->untracked.nr);
		for (k = 0; k < s->untracked.nr; k++) {
			iter = &(s->untracked.items[k]);
			wt_serialize_v1_untracked(s, fd, iter);
		}
		packet_flush(fd);
	}

	if (s->ignored.nr > 0) {
		packet_write_fmt(fd, "ignored %d\n", s->ignored.nr);
		for (k = 0; k < s->ignored.nr; k++) {
			iter = &(s->ignored.items[k]);
			wt_serialize_v1_ignored(s, fd, iter);
		}
		packet_flush(fd);
	}
}
Example #10
0
static void send_shallow(struct commit_list *result)
{
	while (result) {
		struct object *object = &result->item->object;
		if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
			packet_write_fmt(1, "shallow %s",
					 oid_to_hex(&object->oid));
			register_shallow(the_repository, &object->oid);
			shallow_nr++;
		}
		result = result->next;
	}
}
Example #11
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 deepen-since deepen-not"
		" deepen-relative 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_fmt(1, "%s %s%c%s%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,
			     allow_filter ? " filter" : "",
			     git_user_agent_sanitized());
		strbuf_release(&symref_info);
	} else {
		packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), refname_nons);
	}
	capabilities = NULL;
	if (!peel_ref(refname, &peeled))
		packet_write_fmt(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
	return 0;
}
Example #12
0
static void send_shallow_info(struct upload_pack_data *data)
{
	/* No shallow info needs to be sent */
	if (!data->depth && !data->deepen_rev_list && !data->shallows.nr &&
	    !is_repository_shallow(the_repository))
		return;

	packet_write_fmt(1, "shallow-info\n");

	if (!send_shallow_list(data->depth, data->deepen_rev_list,
			       data->deepen_since, &data->deepen_not,
			       &data->shallows) &&
	    is_repository_shallow(the_repository))
		deepen(INFINITE_DEPTH, data->deepen_relative, &data->shallows);

	packet_delim(1);
}
Example #13
0
/*
 * Write V1 header fields.
 */
static void wt_serialize_v1_header(struct wt_status *s, int fd)
{
	/*
	 * Write select fields from the current index to help
	 * the deserializer recognize a stale data set.
	 */
	packet_write_fmt(fd, "index_mtime %d %d\n",
			 the_index.timestamp.sec,
			 the_index.timestamp.nsec);

	/*
	 * Write data from wt_status to qualify this status report.
	 * That is, if this run specified "-uno", the consumer of
	 * our serialization should know that.
	 */
	packet_write_fmt(fd, "is_initial %d\n", s->is_initial);
	if (s->branch)
		packet_write_fmt(fd, "branch %s\n", s->branch);
	if (s->reference)
		packet_write_fmt(fd, "reference %s\n", s->reference);
	/* pathspec */
	/* verbose */
	/* amend */
	packet_write_fmt(fd, "whence %d\n", s->whence);
	/* nowarn */
	/* use_color */
	/* no_gettext */
	/* display_comment_prefix */
	/* relative_paths */
	/* submodule_summary */
	packet_write_fmt(fd, "show_ignored_mode %d\n", s->show_ignored_mode);
	packet_write_fmt(fd, "show_untracked_files %d\n", s->show_untracked_files);
	if (s->ignore_submodule_arg)
		packet_write_fmt(fd, "ignore_submodule_arg %s\n", s->ignore_submodule_arg);
	/* color_palette */
	/* colopts */
	/* null_termination */
	/* commit_template */
	/* show_branch */
	/* show_stash */
	packet_write_fmt(fd, "hints %d\n", s->hints);
	packet_write_fmt(fd, "detect_rename %d\n", s->detect_rename);
	packet_write_fmt(fd, "rename_score %d\n", s->rename_score);
	packet_write_fmt(fd, "rename_limit %d\n", s->rename_limit);
	/* status_format */
	packet_write_fmt(fd, "sha1_commit %s\n", sha1_to_hex(s->sha1_commit));
	packet_write_fmt(fd, "commitable %d\n", s->commitable);
	packet_write_fmt(fd, "workdir_dirty %d\n", s->workdir_dirty);
	/* prefix */
	packet_flush(fd);
}
Example #14
0
/*
 * Write raw (not c-quoted) pathname for an ignored item.
 * We ALWAYS write a final LF to the packet-line (for debugging)
 * even though Linux pathnames allows LFs.
 */
static inline void wt_serialize_v1_ignored(struct wt_status *s, int fd,
					   struct string_list_item *item)
{
	packet_write_fmt(fd, "%s\n", item->string);
}
Example #15
0
File: connect.c Project: 9b/git
/*
 * 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,
				  const char *prog, int flags)
{
	char *hostandport, *path;
	struct child_process *conn = &no_fork;
	enum protocol protocol;
	struct strbuf cmd = STRBUF_INIT;

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

	protocol = parse_connect_url(url, &hostandport, &path);
	if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
		printf("Diag: url=%s\n", url ? url : "NULL");
		printf("Diag: protocol=%s\n", prot_name(protocol));
		printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
		printf("Diag: path=%s\n", path ? path : "NULL");
		conn = NULL;
	} else if (protocol == PROTO_GIT) {
		/*
		 * 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
			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.
		 */
		packet_write_fmt(fd[1],
			     "%s %s%chost=%s%c",
			     prog, path, 0,
			     target_host, 0);
		free(target_host);
	} else {
		conn = xmalloc(sizeof(*conn));
		child_process_init(conn);

		strbuf_addstr(&cmd, prog);
		strbuf_addch(&cmd, ' ');
		sq_quote_buf(&cmd, path);

		/* remove repo-local variables from the environment */
		conn->env = local_repo_env;
		conn->use_shell = 1;
		conn->in = conn->out = -1;
		if (protocol == PROTO_SSH) {
			const char *ssh;
			int putty = 0, tortoiseplink = 0;
			char *ssh_host = hostandport;
			const char *port = NULL;
			transport_check_allowed("ssh");
			get_host_and_port(&ssh_host, &port);

			if (!port)
				port = get_port(ssh_host);

			if (flags & CONNECT_DIAG_URL) {
				printf("Diag: url=%s\n", url ? url : "NULL");
				printf("Diag: protocol=%s\n", prot_name(protocol));
				printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
				printf("Diag: port=%s\n", port ? port : "NONE");
				printf("Diag: path=%s\n", path ? path : "NULL");

				free(hostandport);
				free(path);
				free(conn);
				return NULL;
			}

			ssh = get_ssh_command();
			if (!ssh) {
				const char *base;
				char *ssh_dup;

				/*
				 * GIT_SSH is the no-shell version of
				 * GIT_SSH_COMMAND (and must remain so for
				 * historical compatibility).
				 */
				conn->use_shell = 0;

				ssh = getenv("GIT_SSH");
				if (!ssh)
					ssh = "ssh";

				ssh_dup = xstrdup(ssh);
				base = basename(ssh_dup);

				tortoiseplink = !strcasecmp(base, "tortoiseplink") ||
					!strcasecmp(base, "tortoiseplink.exe");
				putty = tortoiseplink ||
					!strcasecmp(base, "plink") ||
					!strcasecmp(base, "plink.exe");

				free(ssh_dup);
			}

			argv_array_push(&conn->args, ssh);
			if (flags & CONNECT_IPV4)
				argv_array_push(&conn->args, "-4");
			else if (flags & CONNECT_IPV6)
				argv_array_push(&conn->args, "-6");
			if (tortoiseplink)
				argv_array_push(&conn->args, "-batch");
			if (port) {
				/* P is for PuTTY, p is for OpenSSH */
				argv_array_push(&conn->args, putty ? "-P" : "-p");
				argv_array_push(&conn->args, port);
			}
			argv_array_push(&conn->args, ssh_host);
		} else {
			transport_check_allowed("file");
		}
		argv_array_push(&conn->args, cmd.buf);

		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(hostandport);
	free(path);
	return conn;
}
Example #16
0
static void receive_needs(void)
{
	struct object_array shallows = OBJECT_ARRAY_INIT;
	struct string_list deepen_not = STRING_LIST_INIT_DUP;
	int depth = 0;
	int has_non_tip = 0;
	timestamp_t deepen_since = 0;
	int deepen_rev_list = 0;

	shallow_nr = 0;
	for (;;) {
		struct object *o;
		const char *features;
		struct object_id oid_buf;
		char *line = packet_read_line(0, NULL);
		const char *arg;

		reset_timeout();
		if (!line)
			break;

		if (process_shallow(line, &shallows))
			continue;
		if (process_deepen(line, &depth))
			continue;
		if (process_deepen_since(line, &deepen_since, &deepen_rev_list))
			continue;
		if (process_deepen_not(line, &deepen_not, &deepen_rev_list))
			continue;

		if (skip_prefix(line, "filter ", &arg)) {
			if (!filter_capability_requested)
				die("git upload-pack: filtering capability not negotiated");
			parse_list_objects_filter(&filter_options, arg);
			continue;
		}

		if (!skip_prefix(line, "want ", &arg) ||
		    parse_oid_hex(arg, &oid_buf, &features))
			die("git upload-pack: protocol error, "
			    "expected to get object ID, not '%s'", line);

		if (parse_feature_request(features, "deepen-relative"))
			deepen_relative = 1;
		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;
		if (allow_filter && parse_feature_request(features, "filter"))
			filter_capability_requested = 1;

		o = parse_object(&oid_buf);
		if (!o) {
			packet_write_fmt(1,
					 "ERR upload-pack: not our ref %s",
					 oid_to_hex(&oid_buf));
			die("git upload-pack: not our ref %s",
			    oid_to_hex(&oid_buf));
		}
		if (!(o->flags & WANTED)) {
			o->flags |= WANTED;
			if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1
			      || 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 && !deepen_rev_list && shallows.nr == 0)
		return;

	if (send_shallow_list(depth, deepen_rev_list, deepen_since,
			      &deepen_not, &shallows))
		packet_flush(1);
	object_array_clear(&shallows);
}
Example #17
0
static void receive_needs(void)
{
	struct object_array shallows = OBJECT_ARRAY_INIT;
	struct string_list deepen_not = STRING_LIST_INIT_DUP;
	int depth = 0;
	int has_non_tip = 0;
	timestamp_t deepen_since = 0;
	int deepen_rev_list = 0;

	shallow_nr = 0;
	for (;;) {
		struct object *o;
		const char *features;
		struct object_id oid_buf;
		char *line = packet_read_line(0, NULL);
		const char *arg;

		reset_timeout();
		if (!line)
			break;

		if (skip_prefix(line, "shallow ", &arg)) {
			struct object_id oid;
			struct object *object;
			if (get_oid_hex(arg, &oid))
				die("invalid shallow line: %s", line);
			object = parse_object(&oid);
			if (!object)
				continue;
			if (object->type != OBJ_COMMIT)
				die("invalid shallow object %s", oid_to_hex(&oid));
			if (!(object->flags & CLIENT_SHALLOW)) {
				object->flags |= CLIENT_SHALLOW;
				add_object_array(object, NULL, &shallows);
			}
			continue;
		}
		if (skip_prefix(line, "deepen ", &arg)) {
			char *end = NULL;
			depth = strtol(arg, &end, 0);
			if (!end || *end || depth <= 0)
				die("Invalid deepen: %s", line);
			continue;
		}
		if (skip_prefix(line, "deepen-since ", &arg)) {
			char *end = NULL;
			deepen_since = parse_timestamp(arg, &end, 0);
			if (!end || *end || !deepen_since ||
			    /* revisions.c's max_age -1 is special */
			    deepen_since == -1)
				die("Invalid deepen-since: %s", line);
			deepen_rev_list = 1;
			continue;
		}
		if (skip_prefix(line, "deepen-not ", &arg)) {
			char *ref = NULL;
			struct object_id oid;
			if (expand_ref(arg, strlen(arg), &oid, &ref) != 1)
				die("git upload-pack: ambiguous deepen-not: %s", line);
			string_list_append(&deepen_not, ref);
			free(ref);
			deepen_rev_list = 1;
			continue;
		}
		if (skip_prefix(line, "filter ", &arg)) {
			if (!filter_capability_requested)
				die("git upload-pack: filtering capability not negotiated");
			parse_list_objects_filter(&filter_options, arg);
			continue;
		}
		if (!skip_prefix(line, "want ", &arg) ||
		    get_oid_hex(arg, &oid_buf))
			die("git upload-pack: protocol error, "
			    "expected to get sha, not '%s'", line);

		features = arg + 40;

		if (parse_feature_request(features, "deepen-relative"))
			deepen_relative = 1;
		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;
		if (allow_filter && parse_feature_request(features, "filter"))
			filter_capability_requested = 1;

		o = parse_object(&oid_buf);
		if (!o) {
			packet_write_fmt(1,
					 "ERR upload-pack: not our ref %s",
					 oid_to_hex(&oid_buf));
			die("git upload-pack: not our ref %s",
			    oid_to_hex(&oid_buf));
		}
		if (!(o->flags & WANTED)) {
			o->flags |= WANTED;
			if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1
			      || 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 && !deepen_rev_list && shallows.nr == 0)
		return;
	if (depth > 0 && deepen_rev_list)
		die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together");
	if (depth > 0)
		deepen(depth, deepen_relative, &shallows);
	else if (deepen_rev_list) {
		struct argv_array av = ARGV_ARRAY_INIT;
		int i;

		argv_array_push(&av, "rev-list");
		if (deepen_since)
			argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since);
		if (deepen_not.nr) {
			argv_array_push(&av, "--not");
			for (i = 0; i < deepen_not.nr; i++) {
				struct string_list_item *s = deepen_not.items + i;
				argv_array_push(&av, s->string);
			}
			argv_array_push(&av, "--not");
		}
		for (i = 0; i < want_obj.nr; i++) {
			struct object *o = want_obj.objects[i].item;
			argv_array_push(&av, oid_to_hex(&o->oid));
		}
		deepen_by_rev_list(av.argc, av.argv, &shallows);
		argv_array_clear(&av);
	}
	else
		if (shallows.nr > 0) {
			int i;
			for (i = 0; i < shallows.nr; i++)
				register_shallow(&shallows.objects[i].item->oid);
		}

	shallow_nr += shallows.nr;
	object_array_clear(&shallows);
}
Example #18
0
static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
			      const struct fetch_pack_args *args,
			      const struct ref *wants, struct oidset *common,
			      int *haves_to_send, int *in_vain)
{
	int ret = 0;
	struct strbuf req_buf = STRBUF_INIT;

	if (server_supports_v2("fetch", 1))
		packet_buf_write(&req_buf, "command=fetch");
	if (server_supports_v2("agent", 0))
		packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized());
	if (args->server_options && args->server_options->nr &&
	    server_supports_v2("server-option", 1)) {
		int i;
		for (i = 0; i < args->server_options->nr; i++)
			packet_write_fmt(fd_out, "server-option=%s",
					 args->server_options->items[i].string);
	}

	packet_buf_delim(&req_buf);
	if (args->use_thin_pack)
		packet_buf_write(&req_buf, "thin-pack");
	if (args->no_progress)
		packet_buf_write(&req_buf, "no-progress");
	if (args->include_tag)
		packet_buf_write(&req_buf, "include-tag");
	if (prefer_ofs_delta)
		packet_buf_write(&req_buf, "ofs-delta");

	/* Add shallow-info and deepen request */
	if (server_supports_feature("fetch", "shallow", 0))
		add_shallow_requests(&req_buf, args);
	else if (is_repository_shallow(the_repository) || args->deepen)
		die(_("Server does not support shallow requests"));

	/* Add filter */
	if (server_supports_feature("fetch", "filter", 0) &&
	    args->filter_options.choice) {
		print_verbose(args, _("Server supports filter"));
		packet_buf_write(&req_buf, "filter %s",
				 args->filter_options.filter_spec);
	} else if (args->filter_options.choice) {
		warning("filtering not recognized by server, ignoring");
	}

	/* add wants */
	add_wants(args->no_dependents, wants, &req_buf);

	if (args->no_dependents) {
		packet_buf_write(&req_buf, "done");
		ret = 1;
	} else {
		/* Add all of the common commits we've found in previous rounds */
		add_common(&req_buf, common);

		/* Add initial haves */
		ret = add_haves(negotiator, &req_buf, haves_to_send, in_vain);
	}

	/* Send request */
	packet_buf_flush(&req_buf);
	write_or_die(fd_out, req_buf.buf, req_buf.len);

	strbuf_release(&req_buf);
	return ret;
}
Example #19
0
static int get_common_commits(void)
{
	struct object_id oid;
	char last_hex[GIT_MAX_HEXSZ + 1];
	int got_common = 0;
	int got_other = 0;
	int sent_ready = 0;

	save_commit_buffer = 0;

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

		reset_timeout();

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

			if (no_done && sent_ready) {
				packet_write_fmt(1, "ACK %s\n", last_hex);
				return 0;
			}
			if (stateless_rpc)
				exit(0);
			got_common = 0;
			got_other = 0;
			continue;
		}
		if (skip_prefix(line, "have ", &arg)) {
			switch (got_oid(arg, &oid)) {
			case -1: /* they have what we do not */
				got_other = 1;
				if (multi_ack && ok_to_give_up()) {
					const char *hex = oid_to_hex(&oid);
					if (multi_ack == 2) {
						sent_ready = 1;
						packet_write_fmt(1, "ACK %s ready\n", hex);
					} else
						packet_write_fmt(1, "ACK %s continue\n", hex);
				}
				break;
			default:
				got_common = 1;
				oid_to_hex_r(last_hex, &oid);
				if (multi_ack == 2)
					packet_write_fmt(1, "ACK %s common\n", last_hex);
				else if (multi_ack)
					packet_write_fmt(1, "ACK %s continue\n", last_hex);
				else if (have_obj.nr == 1)
					packet_write_fmt(1, "ACK %s\n", last_hex);
				break;
			}
			continue;
		}
		if (!strcmp(line, "done")) {
			if (have_obj.nr > 0) {
				if (multi_ack)
					packet_write_fmt(1, "ACK %s\n", last_hex);
				return 0;
			}
			packet_write_fmt(1, "NAK\n");
			return -1;
		}
		die("git upload-pack: expected SHA1 list, got '%s'", line);
	}
}