blob: e2fe0f91432d8089e74c7e562728aca329dec66c [file] [log] [blame]
Elijah Newren623b80b2023-04-22 20:17:11 +00001#include "git-compat-util.h"
Eric Wonge941c482019-05-23 17:27:23 +00002#include "dir.h"
Elijah Newren32a8f512023-03-21 06:26:03 +00003#include "environment.h"
Elijah Newren41771fa2023-02-24 00:09:27 +00004#include "hex.h"
Stefan Bellera80d72d2018-03-23 18:20:59 +01005#include "repository.h"
Junio C Hamano8f3f9b02005-07-23 17:54:41 -07006#include "refs.h"
7#include "object.h"
8#include "commit.h"
Junio C Hamanob614e3d2005-07-28 14:33:17 -07009#include "tag.h"
Jonathan Tan0abe14f2017-08-18 15:20:26 -070010#include "packfile.h"
Elijah Newrenc3399322023-05-16 06:33:59 +000011#include "path.h"
Elijah Newren87bed172023-04-11 00:41:53 -070012#include "object-file.h"
Elijah Newrena034e912023-05-16 06:34:06 +000013#include "object-store-ll.h"
Elijah Newren623b80b2023-04-22 20:17:11 +000014#include "server-info.h"
Eric Wongf4f476b2019-05-13 23:17:08 +000015#include "strbuf.h"
16
17struct update_info_ctx {
18 FILE *cur_fp;
19 FILE *old_fp; /* becomes NULL if it differs from cur_fp */
20 struct strbuf cur_sb;
21 struct strbuf old_sb;
22};
23
24static void uic_mark_stale(struct update_info_ctx *uic)
25{
26 fclose(uic->old_fp);
27 uic->old_fp = NULL;
28}
29
30static int uic_is_stale(const struct update_info_ctx *uic)
31{
32 return uic->old_fp == NULL;
33}
34
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +020035__attribute__((format (printf, 2, 3)))
Eric Wongf4f476b2019-05-13 23:17:08 +000036static int uic_printf(struct update_info_ctx *uic, const char *fmt, ...)
37{
38 va_list ap;
39 int ret = -1;
40
41 va_start(ap, fmt);
42
43 if (uic_is_stale(uic)) {
44 ret = vfprintf(uic->cur_fp, fmt, ap);
45 } else {
46 ssize_t r;
47 struct strbuf *cur = &uic->cur_sb;
48 struct strbuf *old = &uic->old_sb;
49
50 strbuf_reset(cur);
51 strbuf_vinsertf(cur, 0, fmt, ap);
52
53 strbuf_reset(old);
54 strbuf_grow(old, cur->len);
55 r = fread(old->buf, 1, cur->len, uic->old_fp);
56 if (r != cur->len || memcmp(old->buf, cur->buf, r))
57 uic_mark_stale(uic);
58
59 if (fwrite(cur->buf, 1, cur->len, uic->cur_fp) == cur->len)
60 ret = 0;
61 }
62
63 va_end(ap);
64
65 return ret;
66}
Junio C Hamano8f3f9b02005-07-23 17:54:41 -070067
Jeff Kingd38379e2014-09-13 16:19:20 -040068/*
69 * Create the file "path" by writing to a temporary file and renaming
70 * it into place. The contents of the file come from "generate", which
71 * should return non-zero if it encounters an error.
72 */
Eric Wongf4f476b2019-05-13 23:17:08 +000073static int update_info_file(char *path,
74 int (*generate)(struct update_info_ctx *),
75 int force)
Jeff Kingd38379e2014-09-13 16:19:20 -040076{
77 char *tmp = mkpathdup("%s_XXXXXX", path);
78 int ret = -1;
79 int fd = -1;
Eric Wongf4f476b2019-05-13 23:17:08 +000080 FILE *to_close;
81 struct update_info_ctx uic = {
82 .cur_fp = NULL,
83 .old_fp = NULL,
84 .cur_sb = STRBUF_INIT,
85 .old_sb = STRBUF_INIT
86 };
Jeff Kingd38379e2014-09-13 16:19:20 -040087
88 safe_create_leading_directories(path);
Jeff Kingd91175b2015-01-05 22:50:49 -050089 fd = git_mkstemp_mode(tmp, 0666);
Jeff Kingd38379e2014-09-13 16:19:20 -040090 if (fd < 0)
91 goto out;
Eric Wongf4f476b2019-05-13 23:17:08 +000092 to_close = uic.cur_fp = fdopen(fd, "w");
93 if (!uic.cur_fp)
Jeff Kingd38379e2014-09-13 16:19:20 -040094 goto out;
René Scharfefa1912c2017-04-16 18:55:58 +020095 fd = -1;
Eric Wongf4f476b2019-05-13 23:17:08 +000096
97 /* no problem on ENOENT and old_fp == NULL, it's stale, now */
98 if (!force)
99 uic.old_fp = fopen_or_warn(path, "r");
100
101 /*
Elijah Newren15beaaa2019-11-05 17:07:23 +0000102 * uic_printf will compare incremental comparison against old_fp
Eric Wongf4f476b2019-05-13 23:17:08 +0000103 * and mark uic as stale if needed
104 */
105 ret = generate(&uic);
Jeff Kingd38379e2014-09-13 16:19:20 -0400106 if (ret)
107 goto out;
Eric Wongf4f476b2019-05-13 23:17:08 +0000108
109 /* new file may be shorter than the old one, check here */
110 if (!uic_is_stale(&uic)) {
111 struct stat st;
112 long new_len = ftell(uic.cur_fp);
113 int old_fd = fileno(uic.old_fp);
114
115 if (new_len < 0) {
116 ret = -1;
117 goto out;
118 }
119 if (fstat(old_fd, &st) || (st.st_size != (size_t)new_len))
120 uic_mark_stale(&uic);
121 }
122
123 uic.cur_fp = NULL;
René Scharfefa1912c2017-04-16 18:55:58 +0200124 if (fclose(to_close))
Jeff Kingd38379e2014-09-13 16:19:20 -0400125 goto out;
Eric Wongf4f476b2019-05-13 23:17:08 +0000126
127 if (uic_is_stale(&uic)) {
128 if (adjust_shared_perm(tmp) < 0)
129 goto out;
130 if (rename(tmp, path) < 0)
131 goto out;
132 } else {
133 unlink(tmp);
134 }
Jeff Kingd38379e2014-09-13 16:19:20 -0400135 ret = 0;
136
137out:
138 if (ret) {
Nguyễn Thái Ngọc Duy02382f52016-05-08 16:47:55 +0700139 error_errno("unable to update %s", path);
Eric Wongf4f476b2019-05-13 23:17:08 +0000140 if (uic.cur_fp)
141 fclose(uic.cur_fp);
Jeff Kingd38379e2014-09-13 16:19:20 -0400142 else if (fd >= 0)
143 close(fd);
144 unlink(tmp);
145 }
146 free(tmp);
Eric Wongf4f476b2019-05-13 23:17:08 +0000147 if (uic.old_fp)
148 fclose(uic.old_fp);
149 strbuf_release(&uic.old_sb);
150 strbuf_release(&uic.cur_sb);
Jeff Kingd38379e2014-09-13 16:19:20 -0400151 return ret;
152}
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700153
Michael Haggertye2b0bcd2015-05-25 18:39:04 +0000154static int add_info_ref(const char *path, const struct object_id *oid,
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 19:09:48 +0200155 int flag UNUSED,
Jeff King63e14ee2022-08-19 06:08:32 -0400156 void *cb_data)
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700157{
Eric Wongf4f476b2019-05-13 23:17:08 +0000158 struct update_info_ctx *uic = cb_data;
Stefan Beller109cd762018-06-28 18:21:51 -0700159 struct object *o = parse_object(the_repository, oid);
Shawn O. Pearce76f8a302007-01-31 02:24:44 -0500160 if (!o)
161 return -1;
Junio C Hamanof6b42a82005-10-13 18:57:40 -0700162
Eric Wongf4f476b2019-05-13 23:17:08 +0000163 if (uic_printf(uic, "%s %s\n", oid_to_hex(oid), path) < 0)
Jeff Kingd38379e2014-09-13 16:19:20 -0400164 return -1;
165
Linus Torvalds19746322006-07-11 20:45:31 -0700166 if (o->type == OBJ_TAG) {
Stefan Bellera74093d2018-06-28 18:22:05 -0700167 o = deref_tag(the_repository, o, path, 0);
Junio C Hamano9534f402005-11-02 15:19:13 -0800168 if (o)
Eric Wongf4f476b2019-05-13 23:17:08 +0000169 if (uic_printf(uic, "%s %s^{}\n",
brian m. carlsonf2fd0762015-11-10 02:22:28 +0000170 oid_to_hex(&o->oid), path) < 0)
Jeff Kingd38379e2014-09-13 16:19:20 -0400171 return -1;
Junio C Hamanof6b42a82005-10-13 18:57:40 -0700172 }
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700173 return 0;
174}
175
Eric Wongf4f476b2019-05-13 23:17:08 +0000176static int generate_info_refs(struct update_info_ctx *uic)
Jeff Kingd38379e2014-09-13 16:19:20 -0400177{
Eric Wongf4f476b2019-05-13 23:17:08 +0000178 return for_each_ref(add_info_ref, uic);
Jeff Kingd38379e2014-09-13 16:19:20 -0400179}
180
Eric Wongf4f476b2019-05-13 23:17:08 +0000181static int update_info_refs(int force)
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700182{
Jeff Kingd38379e2014-09-13 16:19:20 -0400183 char *path = git_pathdup("info/refs");
Eric Wongf4f476b2019-05-13 23:17:08 +0000184 int ret = update_info_file(path, generate_info_refs, force);
Jeff Kingd38379e2014-09-13 16:19:20 -0400185 free(path);
186 return ret;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700187}
188
189/* packs */
Linus Torvalds4d8fa912005-08-01 12:11:53 -0700190static struct pack_info {
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700191 struct packed_git *p;
192 int old_num;
193 int new_num;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700194} **info;
195static int num_pack;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700196
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700197static struct pack_info *find_pack_by_name(const char *name)
198{
199 int i;
200 for (i = 0; i < num_pack; i++) {
201 struct packed_git *p = info[i]->p;
Jeff Kingb9fb1422019-04-05 14:14:04 -0400202 if (!strcmp(pack_basename(p), name))
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700203 return info[i];
204 }
205 return NULL;
206}
207
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700208/* Returns non-zero when we detect that the info in the
209 * old file is useless.
210 */
Jeff Kingb83a3082019-04-05 14:13:10 -0400211static int parse_pack_def(const char *packname, int old_cnt)
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700212{
Jeff Kingb83a3082019-04-05 14:13:10 -0400213 struct pack_info *i = find_pack_by_name(packname);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700214 if (i) {
215 i->old_num = old_cnt;
216 return 0;
217 }
218 else {
Junio C Hamano6f42f892005-12-04 22:52:19 -0800219 /* The file describes a pack that is no longer here */
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700220 return 1;
221 }
222}
223
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700224/* Returns non-zero when we detect that the info in the
225 * old file is useless.
226 */
227static int read_pack_info_file(const char *infofile)
228{
229 FILE *fp;
Jeff King4ecbd642019-04-05 14:13:56 -0400230 struct strbuf line = STRBUF_INIT;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700231 int old_cnt = 0;
Jeff King965cc512019-04-05 14:13:14 -0400232 int stale = 1;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700233
Nguyễn Thái Ngọc Duye9d983f2017-05-03 17:16:50 +0700234 fp = fopen_or_warn(infofile, "r");
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700235 if (!fp)
Pavel Roskinaddf88e2006-07-09 03:44:30 -0400236 return 1; /* nonexistent is not an error. */
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700237
Jeff King4ecbd642019-04-05 14:13:56 -0400238 while (strbuf_getline(&line, fp) != EOF) {
Jeff Kingb83a3082019-04-05 14:13:10 -0400239 const char *arg;
Junio C Hamano8ac48382005-12-21 13:48:47 -0800240
Jeff King4ecbd642019-04-05 14:13:56 -0400241 if (!line.len)
Junio C Hamano8ac48382005-12-21 13:48:47 -0800242 continue;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700243
Jeff King4ecbd642019-04-05 14:13:56 -0400244 if (skip_prefix(line.buf, "P ", &arg)) {
Jeff Kingb83a3082019-04-05 14:13:10 -0400245 /* P name */
246 if (parse_pack_def(arg, old_cnt++))
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700247 goto out_stale;
Jeff King4ecbd642019-04-05 14:13:56 -0400248 } else if (line.buf[0] == 'D') {
Jeff Kingb83a3082019-04-05 14:13:10 -0400249 /* we used to emit D but that was misguided. */
Junio C Hamano3e15c672005-12-04 23:12:36 -0800250 goto out_stale;
Jeff King4ecbd642019-04-05 14:13:56 -0400251 } else if (line.buf[0] == 'T') {
Jeff Kingb83a3082019-04-05 14:13:10 -0400252 /* we used to emit T but nobody uses it. */
253 goto out_stale;
254 } else {
Jeff King4ecbd642019-04-05 14:13:56 -0400255 error("unrecognized: %s", line.buf);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700256 }
257 }
Jeff King965cc512019-04-05 14:13:14 -0400258 stale = 0;
259
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700260 out_stale:
Jeff King4ecbd642019-04-05 14:13:56 -0400261 strbuf_release(&line);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700262 fclose(fp);
Jeff King965cc512019-04-05 14:13:14 -0400263 return stale;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700264}
265
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700266static int compare_info(const void *a_, const void *b_)
267{
Felipe Contreras4b25d092009-05-01 12:06:36 +0300268 struct pack_info *const *a = a_;
269 struct pack_info *const *b = b_;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700270
271 if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
272 /* Keep the order in the original */
273 return (*a)->old_num - (*b)->old_num;
274 else if (0 <= (*a)->old_num)
275 /* Only A existed in the original so B is obviously newer */
276 return -1;
277 else if (0 <= (*b)->old_num)
278 /* The other way around. */
279 return 1;
280
Junio C Hamanod5eac492005-12-04 23:02:54 -0800281 /* then it does not matter but at least keep the comparison stable */
Junio C Hamano2dee5812005-12-08 17:29:11 -0800282 if ((*a)->p == (*b)->p)
283 return 0;
284 else if ((*a)->p < (*b)->p)
285 return -1;
286 else
287 return 1;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700288}
289
290static void init_pack_info(const char *infofile, int force)
291{
292 struct packed_git *p;
293 int stale;
Eric Wonge941c482019-05-23 17:27:23 +0000294 int i;
295 size_t alloc = 0;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700296
Derrick Stolee454ea2e2018-08-20 16:52:04 +0000297 for (p = get_all_packs(the_repository); p; p = p->next) {
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700298 /* we ignore things on alternate path since they are
299 * not available to the pullers in general.
300 */
Eric Wonge941c482019-05-23 17:27:23 +0000301 if (!p->pack_local || !file_exists(p->pack_name))
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700302 continue;
Eric Wonge941c482019-05-23 17:27:23 +0000303
304 i = num_pack++;
305 ALLOC_GROW(info, num_pack, alloc);
René Scharfeca56dad2021-03-13 17:17:22 +0100306 CALLOC_ARRAY(info[i], 1);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700307 info[i]->p = p;
308 info[i]->old_num = -1;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700309 }
310
311 if (infofile && !force)
312 stale = read_pack_info_file(infofile);
313 else
314 stale = 1;
315
brian m. carlson910710b2018-05-02 00:25:30 +0000316 for (i = 0; i < num_pack; i++)
317 if (stale)
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700318 info[i]->old_num = -1;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700319
Junio C Hamano6f42f892005-12-04 22:52:19 -0800320 /* renumber them */
René Scharfe9ed0d8d2016-09-29 17:27:31 +0200321 QSORT(info, num_pack, compare_info);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700322 for (i = 0; i < num_pack; i++)
323 info[i]->new_num = i;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700324}
325
Jeff King3907a402014-09-13 16:19:38 -0400326static void free_pack_info(void)
327{
328 int i;
329 for (i = 0; i < num_pack; i++)
330 free(info[i]);
331 free(info);
332}
333
Eric Wongf4f476b2019-05-13 23:17:08 +0000334static int write_pack_info_file(struct update_info_ctx *uic)
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700335{
Junio C Hamano3e15c672005-12-04 23:12:36 -0800336 int i;
Jeff Kingd38379e2014-09-13 16:19:20 -0400337 for (i = 0; i < num_pack; i++) {
Eric Wongf4f476b2019-05-13 23:17:08 +0000338 if (uic_printf(uic, "P %s\n", pack_basename(info[i]->p)) < 0)
Jeff Kingd38379e2014-09-13 16:19:20 -0400339 return -1;
340 }
Eric Wongf4f476b2019-05-13 23:17:08 +0000341 if (uic_printf(uic, "\n") < 0)
Jeff Kingd38379e2014-09-13 16:19:20 -0400342 return -1;
343 return 0;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700344}
345
346static int update_info_packs(int force)
347{
Jeff Kingd38379e2014-09-13 16:19:20 -0400348 char *infofile = mkpathdup("%s/info/packs", get_object_directory());
349 int ret;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700350
351 init_pack_info(infofile, force);
Eric Wongf4f476b2019-05-13 23:17:08 +0000352 ret = update_info_file(infofile, write_pack_info_file, force);
Jeff King3907a402014-09-13 16:19:38 -0400353 free_pack_info();
Jeff Kingd38379e2014-09-13 16:19:20 -0400354 free(infofile);
355 return ret;
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700356}
357
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700358/* public */
359int update_server_info(int force)
360{
361 /* We would add more dumb-server support files later,
362 * including index of available pack files and their
363 * intended audiences.
364 */
365 int errs = 0;
366
Eric Wongf4f476b2019-05-13 23:17:08 +0000367 errs = errs | update_info_refs(force);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700368 errs = errs | update_info_packs(force);
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700369
Junio C Hamano6f42f892005-12-04 22:52:19 -0800370 /* remove leftover rev-cache file if there is any */
Alex Riesen691f1a22009-04-29 23:22:56 +0200371 unlink_or_warn(git_path("info/rev-cache"));
Junio C Hamano6f42f892005-12-04 22:52:19 -0800372
Junio C Hamano8f3f9b02005-07-23 17:54:41 -0700373 return errs;
374}