git

Форк
0
/
remote-ext.c 
206 строк · 4.6 Кб
1
#include "builtin.h"
2
#include "transport.h"
3
#include "run-command.h"
4
#include "pkt-line.h"
5

6
static const char usage_msg[] =
7
	"git remote-ext <remote> <url>";
8

9
/*
10
 * URL syntax:
11
 *	'command [arg1 [arg2 [...]]]'	Invoke command with given arguments.
12
 *	Special characters:
13
 *	'% ': Literal space in argument.
14
 *	'%%': Literal percent sign.
15
 *	'%S': Name of service (git-upload-pack/git-upload-archive/
16
 *		git-receive-pack.
17
 *	'%s': Same as \s, but with possible git- prefix stripped.
18
 *	'%G': Only allowed as first 'character' of argument. Do not pass this
19
 *		Argument to command, instead send this as name of repository
20
 *		in in-line git://-style request (also activates sending this
21
 *		style of request).
22
 *	'%V': Only allowed as first 'character' of argument. Used in
23
 *		conjunction with '%G': Do not pass this argument to command,
24
 *		instead send this as vhost in git://-style request (note: does
25
 *		not activate sending git:// style request).
26
 */
27

28
static char *git_req;
29
static char *git_req_vhost;
30

31
static char *strip_escapes(const char *str, const char *service,
32
	const char **next)
33
{
34
	size_t rpos = 0;
35
	int escape = 0;
36
	char special = 0;
37
	const char *service_noprefix = service;
38
	struct strbuf ret = STRBUF_INIT;
39

40
	skip_prefix(service_noprefix, "git-", &service_noprefix);
41

42
	/* Pass the service to command. */
43
	setenv("GIT_EXT_SERVICE", service, 1);
44
	setenv("GIT_EXT_SERVICE_NOPREFIX", service_noprefix, 1);
45

46
	/* Scan the length of argument. */
47
	while (str[rpos] && (escape || str[rpos] != ' ')) {
48
		if (escape) {
49
			switch (str[rpos]) {
50
			case ' ':
51
			case '%':
52
			case 's':
53
			case 'S':
54
				break;
55
			case 'G':
56
			case 'V':
57
				special = str[rpos];
58
				if (rpos == 1)
59
					break;
60
				/* fallthrough */
61
			default:
62
				die("Bad remote-ext placeholder '%%%c'.",
63
					str[rpos]);
64
			}
65
			escape = 0;
66
		} else
67
			escape = (str[rpos] == '%');
68
		rpos++;
69
	}
70
	if (escape && !str[rpos])
71
		die("remote-ext command has incomplete placeholder");
72
	*next = str + rpos;
73
	if (**next == ' ')
74
		++*next;	/* Skip over space */
75

76
	/*
77
	 * Do the actual placeholder substitution. The string will be short
78
	 * enough not to overflow integers.
79
	 */
80
	rpos = special ? 2 : 0;		/* Skip first 2 bytes in specials. */
81
	escape = 0;
82
	while (str[rpos] && (escape || str[rpos] != ' ')) {
83
		if (escape) {
84
			switch (str[rpos]) {
85
			case ' ':
86
			case '%':
87
				strbuf_addch(&ret, str[rpos]);
88
				break;
89
			case 's':
90
				strbuf_addstr(&ret, service_noprefix);
91
				break;
92
			case 'S':
93
				strbuf_addstr(&ret, service);
94
				break;
95
			}
96
			escape = 0;
97
		} else
98
			switch (str[rpos]) {
99
			case '%':
100
				escape = 1;
101
				break;
102
			default:
103
				strbuf_addch(&ret, str[rpos]);
104
				break;
105
			}
106
		rpos++;
107
	}
108
	switch (special) {
109
	case 'G':
110
		git_req = strbuf_detach(&ret, NULL);
111
		return NULL;
112
	case 'V':
113
		git_req_vhost = strbuf_detach(&ret, NULL);
114
		return NULL;
115
	default:
116
		return strbuf_detach(&ret, NULL);
117
	}
118
}
119

120
static void parse_argv(struct strvec *out, const char *arg, const char *service)
121
{
122
	while (*arg) {
123
		char *expanded = strip_escapes(arg, service, &arg);
124
		if (expanded)
125
			strvec_push(out, expanded);
126
		free(expanded);
127
	}
128
}
129

130
static void send_git_request(int stdin_fd, const char *serv, const char *repo,
131
	const char *vhost)
132
{
133
	if (!vhost)
134
		packet_write_fmt(stdin_fd, "%s %s%c", serv, repo, 0);
135
	else
136
		packet_write_fmt(stdin_fd, "%s %s%chost=%s%c", serv, repo, 0,
137
			     vhost, 0);
138
}
139

140
static int run_child(const char *arg, const char *service)
141
{
142
	int r;
143
	struct child_process child = CHILD_PROCESS_INIT;
144

145
	child.in = -1;
146
	child.out = -1;
147
	child.err = 0;
148
	parse_argv(&child.args, arg, service);
149

150
	if (start_command(&child) < 0)
151
		die("Can't run specified command");
152

153
	if (git_req)
154
		send_git_request(child.in, service, git_req, git_req_vhost);
155

156
	r = bidirectional_transfer_loop(child.out, child.in);
157
	if (!r)
158
		r = finish_command(&child);
159
	else
160
		finish_command(&child);
161
	return r;
162
}
163

164
#define MAXCOMMAND 4096
165

166
static int command_loop(const char *child)
167
{
168
	char buffer[MAXCOMMAND];
169

170
	while (1) {
171
		size_t i;
172
		const char *arg;
173

174
		if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
175
			if (ferror(stdin))
176
				die("Command input error");
177
			exit(0);
178
		}
179
		/* Strip end of line characters. */
180
		i = strlen(buffer);
181
		while (i > 0 && isspace(buffer[i - 1]))
182
			buffer[--i] = 0;
183

184
		if (!strcmp(buffer, "capabilities")) {
185
			printf("*connect\n\n");
186
			fflush(stdout);
187
		} else if (skip_prefix(buffer, "connect ", &arg)) {
188
			printf("\n");
189
			fflush(stdout);
190
			return run_child(child, arg);
191
		} else {
192
			fprintf(stderr, "Bad command");
193
			return 1;
194
		}
195
	}
196
}
197

198
int cmd_remote_ext(int argc, const char **argv, const char *prefix)
199
{
200
	BUG_ON_NON_EMPTY_PREFIX(prefix);
201

202
	if (argc != 3)
203
		usage(usage_msg);
204

205
	return command_loop(argv[2]);
206
}
207

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.