git

Форк
0
/
server-info.c 
371 строка · 7.7 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "dir.h"
5
#include "environment.h"
6
#include "hex.h"
7
#include "repository.h"
8
#include "refs.h"
9
#include "object.h"
10
#include "commit.h"
11
#include "tag.h"
12
#include "packfile.h"
13
#include "path.h"
14
#include "object-file.h"
15
#include "object-store-ll.h"
16
#include "server-info.h"
17
#include "strbuf.h"
18
#include "tempfile.h"
19

20
struct update_info_ctx {
21
	FILE *cur_fp;
22
	FILE *old_fp; /* becomes NULL if it differs from cur_fp */
23
	struct strbuf cur_sb;
24
	struct strbuf old_sb;
25
};
26

27
static void uic_mark_stale(struct update_info_ctx *uic)
28
{
29
	fclose(uic->old_fp);
30
	uic->old_fp = NULL;
31
}
32

33
static int uic_is_stale(const struct update_info_ctx *uic)
34
{
35
	return uic->old_fp == NULL;
36
}
37

38
__attribute__((format (printf, 2, 3)))
39
static int uic_printf(struct update_info_ctx *uic, const char *fmt, ...)
40
{
41
	va_list ap;
42
	int ret = -1;
43

44
	va_start(ap, fmt);
45

46
	if (uic_is_stale(uic)) {
47
		ret = vfprintf(uic->cur_fp, fmt, ap);
48
	} else {
49
		ssize_t r;
50
		struct strbuf *cur = &uic->cur_sb;
51
		struct strbuf *old = &uic->old_sb;
52

53
		strbuf_reset(cur);
54
		strbuf_vinsertf(cur, 0, fmt, ap);
55

56
		strbuf_reset(old);
57
		strbuf_grow(old, cur->len);
58
		r = fread(old->buf, 1, cur->len, uic->old_fp);
59
		if (r != cur->len || memcmp(old->buf, cur->buf, r))
60
			uic_mark_stale(uic);
61

62
		if (fwrite(cur->buf, 1, cur->len, uic->cur_fp) == cur->len)
63
			ret = 0;
64
	}
65

66
	va_end(ap);
67

68
	return ret;
69
}
70

71
/*
72
 * Create the file "path" by writing to a temporary file and renaming
73
 * it into place. The contents of the file come from "generate", which
74
 * should return non-zero if it encounters an error.
75
 */
76
static int update_info_file(char *path,
77
			int (*generate)(struct update_info_ctx *),
78
			int force)
79
{
80
	char *tmp = mkpathdup("%s_XXXXXX", path);
81
	struct tempfile *f = NULL;
82
	int ret = -1;
83
	struct update_info_ctx uic = {
84
		.cur_fp = NULL,
85
		.old_fp = NULL,
86
		.cur_sb = STRBUF_INIT,
87
		.old_sb = STRBUF_INIT
88
	};
89

90
	safe_create_leading_directories(path);
91
	f = mks_tempfile_m(tmp, 0666);
92
	if (!f)
93
		goto out;
94
	uic.cur_fp = fdopen_tempfile(f, "w");
95
	if (!uic.cur_fp)
96
		goto out;
97

98
	/* no problem on ENOENT and old_fp == NULL, it's stale, now */
99
	if (!force)
100
		uic.old_fp = fopen_or_warn(path, "r");
101

102
	/*
103
	 * uic_printf will compare incremental comparison against old_fp
104
	 * and mark uic as stale if needed
105
	 */
106
	ret = generate(&uic);
107
	if (ret)
108
		goto out;
109

110
	/* new file may be shorter than the old one, check here */
111
	if (!uic_is_stale(&uic)) {
112
		struct stat st;
113
		long new_len = ftell(uic.cur_fp);
114
		int old_fd = fileno(uic.old_fp);
115

116
		if (new_len < 0) {
117
			ret = -1;
118
			goto out;
119
		}
120
		if (fstat(old_fd, &st) || (st.st_size != (size_t)new_len))
121
			uic_mark_stale(&uic);
122
	}
123

124
	uic.cur_fp = NULL;
125

126
	if (uic_is_stale(&uic)) {
127
		if (adjust_shared_perm(get_tempfile_path(f)) < 0)
128
			goto out;
129
		if (rename_tempfile(&f, path) < 0)
130
			goto out;
131
	} else {
132
		delete_tempfile(&f);
133
	}
134
	ret = 0;
135

136
out:
137
	if (ret) {
138
		error_errno("unable to update %s", path);
139
		if (f)
140
			delete_tempfile(&f);
141
	}
142
	free(tmp);
143
	if (uic.old_fp)
144
		fclose(uic.old_fp);
145
	strbuf_release(&uic.old_sb);
146
	strbuf_release(&uic.cur_sb);
147
	return ret;
148
}
149

150
static int add_info_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
151
			int flag UNUSED,
152
			void *cb_data)
153
{
154
	struct update_info_ctx *uic = cb_data;
155
	struct object *o = parse_object(the_repository, oid);
156
	if (!o)
157
		return -1;
158

159
	if (uic_printf(uic, "%s	%s\n", oid_to_hex(oid), path) < 0)
160
		return -1;
161

162
	if (o->type == OBJ_TAG) {
163
		o = deref_tag(the_repository, o, path, 0);
164
		if (o)
165
			if (uic_printf(uic, "%s	%s^{}\n",
166
				oid_to_hex(&o->oid), path) < 0)
167
				return -1;
168
	}
169
	return 0;
170
}
171

172
static int generate_info_refs(struct update_info_ctx *uic)
173
{
174
	return refs_for_each_ref(get_main_ref_store(the_repository),
175
				 add_info_ref, uic);
176
}
177

178
static int update_info_refs(int force)
179
{
180
	char *path = git_pathdup("info/refs");
181
	int ret = update_info_file(path, generate_info_refs, force);
182
	free(path);
183
	return ret;
184
}
185

186
/* packs */
187
static struct pack_info {
188
	struct packed_git *p;
189
	int old_num;
190
	int new_num;
191
} **info;
192
static int num_pack;
193

194
static struct pack_info *find_pack_by_name(const char *name)
195
{
196
	int i;
197
	for (i = 0; i < num_pack; i++) {
198
		struct packed_git *p = info[i]->p;
199
		if (!strcmp(pack_basename(p), name))
200
			return info[i];
201
	}
202
	return NULL;
203
}
204

205
/* Returns non-zero when we detect that the info in the
206
 * old file is useless.
207
 */
208
static int parse_pack_def(const char *packname, int old_cnt)
209
{
210
	struct pack_info *i = find_pack_by_name(packname);
211
	if (i) {
212
		i->old_num = old_cnt;
213
		return 0;
214
	}
215
	else {
216
		/* The file describes a pack that is no longer here */
217
		return 1;
218
	}
219
}
220

221
/* Returns non-zero when we detect that the info in the
222
 * old file is useless.
223
 */
224
static int read_pack_info_file(const char *infofile)
225
{
226
	FILE *fp;
227
	struct strbuf line = STRBUF_INIT;
228
	int old_cnt = 0;
229
	int stale = 1;
230

231
	fp = fopen_or_warn(infofile, "r");
232
	if (!fp)
233
		return 1; /* nonexistent is not an error. */
234

235
	while (strbuf_getline(&line, fp) != EOF) {
236
		const char *arg;
237

238
		if (!line.len)
239
			continue;
240

241
		if (skip_prefix(line.buf, "P ", &arg)) {
242
			/* P name */
243
			if (parse_pack_def(arg, old_cnt++))
244
				goto out_stale;
245
		} else if (line.buf[0] == 'D') {
246
			/* we used to emit D but that was misguided. */
247
			goto out_stale;
248
		} else if (line.buf[0] == 'T') {
249
			/* we used to emit T but nobody uses it. */
250
			goto out_stale;
251
		} else {
252
			error("unrecognized: %s", line.buf);
253
		}
254
	}
255
	stale = 0;
256

257
 out_stale:
258
	strbuf_release(&line);
259
	fclose(fp);
260
	return stale;
261
}
262

263
static int compare_info(const void *a_, const void *b_)
264
{
265
	struct pack_info *const *a = a_;
266
	struct pack_info *const *b = b_;
267

268
	if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
269
		/* Keep the order in the original */
270
		return (*a)->old_num - (*b)->old_num;
271
	else if (0 <= (*a)->old_num)
272
		/* Only A existed in the original so B is obviously newer */
273
		return -1;
274
	else if (0 <= (*b)->old_num)
275
		/* The other way around. */
276
		return 1;
277

278
	/* then it does not matter but at least keep the comparison stable */
279
	if ((*a)->p == (*b)->p)
280
		return 0;
281
	else if ((*a)->p < (*b)->p)
282
		return -1;
283
	else
284
		return 1;
285
}
286

287
static void init_pack_info(const char *infofile, int force)
288
{
289
	struct packed_git *p;
290
	int stale;
291
	int i;
292
	size_t alloc = 0;
293

294
	for (p = get_all_packs(the_repository); p; p = p->next) {
295
		/* we ignore things on alternate path since they are
296
		 * not available to the pullers in general.
297
		 */
298
		if (!p->pack_local || !file_exists(p->pack_name))
299
			continue;
300

301
		i = num_pack++;
302
		ALLOC_GROW(info, num_pack, alloc);
303
		CALLOC_ARRAY(info[i], 1);
304
		info[i]->p = p;
305
		info[i]->old_num = -1;
306
	}
307

308
	if (infofile && !force)
309
		stale = read_pack_info_file(infofile);
310
	else
311
		stale = 1;
312

313
	for (i = 0; i < num_pack; i++)
314
		if (stale)
315
			info[i]->old_num = -1;
316

317
	/* renumber them */
318
	QSORT(info, num_pack, compare_info);
319
	for (i = 0; i < num_pack; i++)
320
		info[i]->new_num = i;
321
}
322

323
static void free_pack_info(void)
324
{
325
	int i;
326
	for (i = 0; i < num_pack; i++)
327
		free(info[i]);
328
	free(info);
329
}
330

331
static int write_pack_info_file(struct update_info_ctx *uic)
332
{
333
	int i;
334
	for (i = 0; i < num_pack; i++) {
335
		if (uic_printf(uic, "P %s\n", pack_basename(info[i]->p)) < 0)
336
			return -1;
337
	}
338
	if (uic_printf(uic, "\n") < 0)
339
		return -1;
340
	return 0;
341
}
342

343
static int update_info_packs(int force)
344
{
345
	char *infofile = mkpathdup("%s/info/packs", get_object_directory());
346
	int ret;
347

348
	init_pack_info(infofile, force);
349
	ret = update_info_file(infofile, write_pack_info_file, force);
350
	free_pack_info();
351
	free(infofile);
352
	return ret;
353
}
354

355
/* public */
356
int update_server_info(int force)
357
{
358
	/* We would add more dumb-server support files later,
359
	 * including index of available pack files and their
360
	 * intended audiences.
361
	 */
362
	int errs = 0;
363

364
	errs = errs | update_info_refs(force);
365
	errs = errs | update_info_packs(force);
366

367
	/* remove leftover rev-cache file if there is any */
368
	unlink_or_warn(git_path("info/rev-cache"));
369

370
	return errs;
371
}
372

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

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

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

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