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.
 
 
 
 
 
 

286 lines
5.7 KiB

  1. #include "cache.h"
  2. #include "refs.h"
  3. #include "object.h"
  4. #include "commit.h"
  5. #include "tag.h"
  6. /*
  7. * Create the file "path" by writing to a temporary file and renaming
  8. * it into place. The contents of the file come from "generate", which
  9. * should return non-zero if it encounters an error.
  10. */
  11. static int update_info_file(char *path, int (*generate)(FILE *))
  12. {
  13. char *tmp = mkpathdup("%s_XXXXXX", path);
  14. int ret = -1;
  15. int fd = -1;
  16. FILE *fp = NULL;
  17. safe_create_leading_directories(path);
  18. fd = git_mkstemp_mode(tmp, 0666);
  19. if (fd < 0)
  20. goto out;
  21. fp = fdopen(fd, "w");
  22. if (!fp)
  23. goto out;
  24. ret = generate(fp);
  25. if (ret)
  26. goto out;
  27. if (fclose(fp))
  28. goto out;
  29. if (adjust_shared_perm(tmp) < 0)
  30. goto out;
  31. if (rename(tmp, path) < 0)
  32. goto out;
  33. ret = 0;
  34. out:
  35. if (ret) {
  36. error("unable to update %s: %s", path, strerror(errno));
  37. if (fp)
  38. fclose(fp);
  39. else if (fd >= 0)
  40. close(fd);
  41. unlink(tmp);
  42. }
  43. free(tmp);
  44. return ret;
  45. }
  46. static int add_info_ref(const char *path, const struct object_id *oid,
  47. int flag, void *cb_data)
  48. {
  49. FILE *fp = cb_data;
  50. struct object *o = parse_object(oid->hash);
  51. if (!o)
  52. return -1;
  53. if (fprintf(fp, "%s %s\n", oid_to_hex(oid), path) < 0)
  54. return -1;
  55. if (o->type == OBJ_TAG) {
  56. o = deref_tag(o, path, 0);
  57. if (o)
  58. if (fprintf(fp, "%s %s^{}\n",
  59. oid_to_hex(&o->oid), path) < 0)
  60. return -1;
  61. }
  62. return 0;
  63. }
  64. static int generate_info_refs(FILE *fp)
  65. {
  66. return for_each_ref(add_info_ref, fp);
  67. }
  68. static int update_info_refs(int force)
  69. {
  70. char *path = git_pathdup("info/refs");
  71. int ret = update_info_file(path, generate_info_refs);
  72. free(path);
  73. return ret;
  74. }
  75. /* packs */
  76. static struct pack_info {
  77. struct packed_git *p;
  78. int old_num;
  79. int new_num;
  80. int nr_alloc;
  81. int nr_heads;
  82. unsigned char (*head)[20];
  83. } **info;
  84. static int num_pack;
  85. static const char *objdir;
  86. static int objdirlen;
  87. static struct pack_info *find_pack_by_name(const char *name)
  88. {
  89. int i;
  90. for (i = 0; i < num_pack; i++) {
  91. struct packed_git *p = info[i]->p;
  92. /* skip "/pack/" after ".git/objects" */
  93. if (!strcmp(p->pack_name + objdirlen + 6, name))
  94. return info[i];
  95. }
  96. return NULL;
  97. }
  98. /* Returns non-zero when we detect that the info in the
  99. * old file is useless.
  100. */
  101. static int parse_pack_def(const char *line, int old_cnt)
  102. {
  103. struct pack_info *i = find_pack_by_name(line + 2);
  104. if (i) {
  105. i->old_num = old_cnt;
  106. return 0;
  107. }
  108. else {
  109. /* The file describes a pack that is no longer here */
  110. return 1;
  111. }
  112. }
  113. /* Returns non-zero when we detect that the info in the
  114. * old file is useless.
  115. */
  116. static int read_pack_info_file(const char *infofile)
  117. {
  118. FILE *fp;
  119. char line[1000];
  120. int old_cnt = 0;
  121. fp = fopen(infofile, "r");
  122. if (!fp)
  123. return 1; /* nonexistent is not an error. */
  124. while (fgets(line, sizeof(line), fp)) {
  125. int len = strlen(line);
  126. if (len && line[len-1] == '\n')
  127. line[--len] = 0;
  128. if (!len)
  129. continue;
  130. switch (line[0]) {
  131. case 'P': /* P name */
  132. if (parse_pack_def(line, old_cnt++))
  133. goto out_stale;
  134. break;
  135. case 'D': /* we used to emit D but that was misguided. */
  136. case 'T': /* we used to emit T but nobody uses it. */
  137. goto out_stale;
  138. default:
  139. error("unrecognized: %s", line);
  140. break;
  141. }
  142. }
  143. fclose(fp);
  144. return 0;
  145. out_stale:
  146. fclose(fp);
  147. return 1;
  148. }
  149. static int compare_info(const void *a_, const void *b_)
  150. {
  151. struct pack_info *const *a = a_;
  152. struct pack_info *const *b = b_;
  153. if (0 <= (*a)->old_num && 0 <= (*b)->old_num)
  154. /* Keep the order in the original */
  155. return (*a)->old_num - (*b)->old_num;
  156. else if (0 <= (*a)->old_num)
  157. /* Only A existed in the original so B is obviously newer */
  158. return -1;
  159. else if (0 <= (*b)->old_num)
  160. /* The other way around. */
  161. return 1;
  162. /* then it does not matter but at least keep the comparison stable */
  163. if ((*a)->p == (*b)->p)
  164. return 0;
  165. else if ((*a)->p < (*b)->p)
  166. return -1;
  167. else
  168. return 1;
  169. }
  170. static void init_pack_info(const char *infofile, int force)
  171. {
  172. struct packed_git *p;
  173. int stale;
  174. int i = 0;
  175. objdir = get_object_directory();
  176. objdirlen = strlen(objdir);
  177. prepare_packed_git();
  178. for (p = packed_git; p; p = p->next) {
  179. /* we ignore things on alternate path since they are
  180. * not available to the pullers in general.
  181. */
  182. if (!p->pack_local)
  183. continue;
  184. i++;
  185. }
  186. num_pack = i;
  187. info = xcalloc(num_pack, sizeof(struct pack_info *));
  188. for (i = 0, p = packed_git; p; p = p->next) {
  189. if (!p->pack_local)
  190. continue;
  191. info[i] = xcalloc(1, sizeof(struct pack_info));
  192. info[i]->p = p;
  193. info[i]->old_num = -1;
  194. i++;
  195. }
  196. if (infofile && !force)
  197. stale = read_pack_info_file(infofile);
  198. else
  199. stale = 1;
  200. for (i = 0; i < num_pack; i++) {
  201. if (stale) {
  202. info[i]->old_num = -1;
  203. info[i]->nr_heads = 0;
  204. }
  205. }
  206. /* renumber them */
  207. qsort(info, num_pack, sizeof(info[0]), compare_info);
  208. for (i = 0; i < num_pack; i++)
  209. info[i]->new_num = i;
  210. }
  211. static void free_pack_info(void)
  212. {
  213. int i;
  214. for (i = 0; i < num_pack; i++)
  215. free(info[i]);
  216. free(info);
  217. }
  218. static int write_pack_info_file(FILE *fp)
  219. {
  220. int i;
  221. for (i = 0; i < num_pack; i++) {
  222. if (fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6) < 0)
  223. return -1;
  224. }
  225. if (fputc('\n', fp) == EOF)
  226. return -1;
  227. return 0;
  228. }
  229. static int update_info_packs(int force)
  230. {
  231. char *infofile = mkpathdup("%s/info/packs", get_object_directory());
  232. int ret;
  233. init_pack_info(infofile, force);
  234. ret = update_info_file(infofile, write_pack_info_file);
  235. free_pack_info();
  236. free(infofile);
  237. return ret;
  238. }
  239. /* public */
  240. int update_server_info(int force)
  241. {
  242. /* We would add more dumb-server support files later,
  243. * including index of available pack files and their
  244. * intended audiences.
  245. */
  246. int errs = 0;
  247. errs = errs | update_info_refs(force);
  248. errs = errs | update_info_packs(force);
  249. /* remove leftover rev-cache file if there is any */
  250. unlink_or_warn(git_path("info/rev-cache"));
  251. return errs;
  252. }