THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
7.5KB

  1. #include "cache.h"
  2. #include "dir.h"
  3. #include "repository.h"
  4. #include "refs.h"
  5. #include "object.h"
  6. #include "commit.h"
  7. #include "tag.h"
  8. #include "packfile.h"
  9. #include "object-store.h"
  10. #include "strbuf.h"
  11. struct update_info_ctx {
  12. FILE *cur_fp;
  13. FILE *old_fp; /* becomes NULL if it differs from cur_fp */
  14. struct strbuf cur_sb;
  15. struct strbuf old_sb;
  16. };
  17. static void uic_mark_stale(struct update_info_ctx *uic)
  18. {
  19. fclose(uic->old_fp);
  20. uic->old_fp = NULL;
  21. }
  22. static int uic_is_stale(const struct update_info_ctx *uic)
  23. {
  24. return uic->old_fp == NULL;
  25. }
  26. static int uic_printf(struct update_info_ctx *uic, const char *fmt, ...)
  27. {
  28. va_list ap;
  29. int ret = -1;
  30. va_start(ap, fmt);
  31. if (uic_is_stale(uic)) {
  32. ret = vfprintf(uic->cur_fp, fmt, ap);
  33. } else {
  34. ssize_t r;
  35. struct strbuf *cur = &uic->cur_sb;
  36. struct strbuf *old = &uic->old_sb;
  37. strbuf_reset(cur);
  38. strbuf_vinsertf(cur, 0, fmt, ap);
  39. strbuf_reset(old);
  40. strbuf_grow(old, cur->len);
  41. r = fread(old->buf, 1, cur->len, uic->old_fp);
  42. if (r != cur->len || memcmp(old->buf, cur->buf, r))
  43. uic_mark_stale(uic);
  44. if (fwrite(cur->buf, 1, cur->len, uic->cur_fp) == cur->len)
  45. ret = 0;
  46. }
  47. va_end(ap);
  48. return ret;
  49. }
  50. /*
  51. * Create the file "path" by writing to a temporary file and renaming
  52. * it into place. The contents of the file come from "generate", which
  53. * should return non-zero if it encounters an error.
  54. */
  55. static int update_info_file(char *path,
  56. int (*generate)(struct update_info_ctx *),
  57. int force)
  58. {
  59. char *tmp = mkpathdup("%s_XXXXXX", path);
  60. int ret = -1;
  61. int fd = -1;
  62. FILE *to_close;
  63. struct update_info_ctx uic = {
  64. .cur_fp = NULL,
  65. .old_fp = NULL,
  66. .cur_sb = STRBUF_INIT,
  67. .old_sb = STRBUF_INIT
  68. };
  69. safe_create_leading_directories(path);
  70. fd = git_mkstemp_mode(tmp, 0666);
  71. if (fd < 0)
  72. goto out;
  73. to_close = uic.cur_fp = fdopen(fd, "w");
  74. if (!uic.cur_fp)
  75. goto out;
  76. fd = -1;
  77. /* no problem on ENOENT and old_fp == NULL, it's stale, now */
  78. if (!force)
  79. uic.old_fp = fopen_or_warn(path, "r");
  80. /*
  81. * uic_printf will compare incremental comparison aginst old_fp
  82. * and mark uic as stale if needed
  83. */
  84. ret = generate(&uic);
  85. if (ret)
  86. goto out;
  87. /* new file may be shorter than the old one, check here */
  88. if (!uic_is_stale(&uic)) {
  89. struct stat st;
  90. long new_len = ftell(uic.cur_fp);
  91. int old_fd = fileno(uic.old_fp);
  92. if (new_len < 0) {
  93. ret = -1;
  94. goto out;
  95. }
  96. if (fstat(old_fd, &st) || (st.st_size != (size_t)new_len))
  97. uic_mark_stale(&uic);
  98. }
  99. uic.cur_fp = NULL;
  100. if (fclose(to_close))
  101. goto out;
  102. if (uic_is_stale(&uic)) {
  103. if (adjust_shared_perm(tmp) < 0)
  104. goto out;
  105. if (rename(tmp, path) < 0)
  106. goto out;
  107. } else {
  108. unlink(tmp);
  109. }
  110. ret = 0;
  111. out:
  112. if (ret) {
  113. error_errno("unable to update %s", path);
  114. if (uic.cur_fp)
  115. fclose(uic.cur_fp);
  116. else if (fd >= 0)
  117. close(fd);
  118. unlink(tmp);
  119. }
  120. free(tmp);
  121. if (uic.old_fp)
  122. fclose(uic.old_fp);
  123. strbuf_release(&uic.old_sb);
  124. strbuf_release(&uic.cur_sb);
  125. return ret;
  126. }
  127. static int add_info_ref(const char *path, const struct object_id *oid,
  128. int flag, void *cb_data)
  129. {
  130. struct update_info_ctx *uic = cb_data;
  131. struct object *o = parse_object(the_repository, oid);
  132. if (!o)
  133. return -1;
  134. if (uic_printf(uic, "%s %s\n", oid_to_hex(oid), path) < 0)
  135. return -1;
  136. if (o->type == OBJ_TAG) {
  137. o = deref_tag(the_repository, o, path, 0);
  138. if (o)
  139. if (uic_printf(uic, "%s %s^{}\n",
  140. oid_to_hex(&o->oid), path) < 0)
  141. return -1;
  142. }
  143. return 0;
  144. }
  145. static int generate_info_refs(struct update_info_ctx *uic)
  146. {
  147. return for_each_ref(add_info_ref, uic);
  148. }
  149. static int update_info_refs(int force)
  150. {
  151. char *path = git_pathdup("info/refs");
  152. int ret = update_info_file(path, generate_info_refs, force);
  153. free(path);
  154. return ret;
  155. }
  156. /* packs */
  157. static struct pack_info {
  158. struct packed_git *p;
  159. int old_num;
  160. int new_num;
  161. } **info;
  162. static int num_pack;
  163. static struct pack_info *find_pack_by_name(const char *name)
  164. {
  165. int i;
  166. for (i = 0; i < num_pack; i++) {
  167. struct packed_git *p = info[i]->p;
  168. if (!strcmp(pack_basename(p), name))
  169. return info[i];
  170. }
  171. return NULL;
  172. }
  173. /* Returns non-zero when we detect that the info in the
  174. * old file is useless.
  175. */
  176. static int parse_pack_def(const char *packname, int old_cnt)
  177. {
  178. struct pack_info *i = find_pack_by_name(packname);
  179. if (i) {
  180. i->old_num = old_cnt;
  181. return 0;
  182. }
  183. else {
  184. /* The file describes a pack that is no longer here */
  185. return 1;
  186. }
  187. }
  188. /* Returns non-zero when we detect that the info in the
  189. * old file is useless.
  190. */
  191. static int read_pack_info_file(const char *infofile)
  192. {
  193. FILE *fp;
  194. struct strbuf line = STRBUF_INIT;
  195. int old_cnt = 0;
  196. int stale = 1;
  197. fp = fopen_or_warn(infofile, "r");
  198. if (!fp)
  199. return 1; /* nonexistent is not an error. */
  200. while (strbuf_getline(&line, fp) != EOF) {
  201. const char *arg;
  202. if (!line.len)
  203. continue;
  204. if (skip_prefix(line.buf, "P ", &arg)) {
  205. /* P name */
  206. if (parse_pack_def(arg, old_cnt++))
  207. goto out_stale;
  208. } else if (line.buf[0] == 'D') {
  209. /* we used to emit D but that was misguided. */
  210. goto out_stale;
  211. } else if (line.buf[0] == 'T') {
  212. /* we used to emit T but nobody uses it. */
  213. goto out_stale;
  214. } else {
  215. error("unrecognized: %s", line.buf);
  216. }
  217. }
  218. stale = 0;
  219. out_stale:
  220. strbuf_release(&line);
  221. fclose(fp);
  222. return stale;
  223. }
  224. static int compare_info(const void *a_, const void *b_)
  225. {
  226. struct pack_info *const *a = a_;
  227. struct pack_info *const *b = b_;
  228. if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
  229. /* Keep the order in the original */
  230. return (*a)->old_num - (*b)->old_num;
  231. else if (0 <= (*a)->old_num)
  232. /* Only A existed in the original so B is obviously newer */
  233. return -1;
  234. else if (0 <= (*b)->old_num)
  235. /* The other way around. */
  236. return 1;
  237. /* then it does not matter but at least keep the comparison stable */
  238. if ((*a)->p == (*b)->p)
  239. return 0;
  240. else if ((*a)->p < (*b)->p)
  241. return -1;
  242. else
  243. return 1;
  244. }
  245. static void init_pack_info(const char *infofile, int force)
  246. {
  247. struct packed_git *p;
  248. int stale;
  249. int i;
  250. size_t alloc = 0;
  251. for (p = get_all_packs(the_repository); p; p = p->next) {
  252. /* we ignore things on alternate path since they are
  253. * not available to the pullers in general.
  254. */
  255. if (!p->pack_local || !file_exists(p->pack_name))
  256. continue;
  257. i = num_pack++;
  258. ALLOC_GROW(info, num_pack, alloc);
  259. info[i] = xcalloc(1, sizeof(struct pack_info));
  260. info[i]->p = p;
  261. info[i]->old_num = -1;
  262. }
  263. if (infofile && !force)
  264. stale = read_pack_info_file(infofile);
  265. else
  266. stale = 1;
  267. for (i = 0; i < num_pack; i++)
  268. if (stale)
  269. info[i]->old_num = -1;
  270. /* renumber them */
  271. QSORT(info, num_pack, compare_info);
  272. for (i = 0; i < num_pack; i++)
  273. info[i]->new_num = i;
  274. }
  275. static void free_pack_info(void)
  276. {
  277. int i;
  278. for (i = 0; i < num_pack; i++)
  279. free(info[i]);
  280. free(info);
  281. }
  282. static int write_pack_info_file(struct update_info_ctx *uic)
  283. {
  284. int i;
  285. for (i = 0; i < num_pack; i++) {
  286. if (uic_printf(uic, "P %s\n", pack_basename(info[i]->p)) < 0)
  287. return -1;
  288. }
  289. if (uic_printf(uic, "\n") < 0)
  290. return -1;
  291. return 0;
  292. }
  293. static int update_info_packs(int force)
  294. {
  295. char *infofile = mkpathdup("%s/info/packs", get_object_directory());
  296. int ret;
  297. init_pack_info(infofile, force);
  298. ret = update_info_file(infofile, write_pack_info_file, force);
  299. free_pack_info();
  300. free(infofile);
  301. return ret;
  302. }
  303. /* public */
  304. int update_server_info(int force)
  305. {
  306. /* We would add more dumb-server support files later,
  307. * including index of available pack files and their
  308. * intended audiences.
  309. */
  310. int errs = 0;
  311. errs = errs | update_info_refs(force);
  312. errs = errs | update_info_packs(force);
  313. /* remove leftover rev-cache file if there is any */
  314. unlink_or_warn(git_path("info/rev-cache"));
  315. return errs;
  316. }