rugged 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (277) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -0
  3. data/README.md +1 -1
  4. data/ext/rugged/rugged.c +7 -4
  5. data/ext/rugged/rugged_object.c +1 -1
  6. data/ext/rugged/rugged_repo.c +3 -3
  7. data/lib/rugged/repository.rb +2 -2
  8. data/lib/rugged/version.rb +1 -1
  9. data/vendor/libgit2/CMakeLists.txt +11 -6
  10. data/vendor/libgit2/COPYING +109 -1
  11. data/vendor/libgit2/cmake/Findfutimens.cmake +14 -0
  12. data/vendor/libgit2/cmake/SelectHTTPSBackend.cmake +4 -0
  13. data/vendor/libgit2/cmake/SelectHashes.cmake +1 -0
  14. data/vendor/libgit2/deps/chromium-zlib/CMakeLists.txt +101 -0
  15. data/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +17 -5
  16. data/vendor/libgit2/deps/ntlmclient/crypt.h +14 -9
  17. data/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c +20 -20
  18. data/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.h +3 -3
  19. data/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c +37 -36
  20. data/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.h +4 -3
  21. data/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +178 -51
  22. data/vendor/libgit2/deps/ntlmclient/crypt_openssl.h +74 -5
  23. data/vendor/libgit2/deps/ntlmclient/ntlm.c +150 -118
  24. data/vendor/libgit2/deps/ntlmclient/ntlm.h +13 -9
  25. data/vendor/libgit2/deps/ntlmclient/ntlmclient.h +16 -3
  26. data/vendor/libgit2/deps/ntlmclient/unicode.h +10 -4
  27. data/vendor/libgit2/deps/ntlmclient/unicode_builtin.c +16 -27
  28. data/vendor/libgit2/deps/ntlmclient/unicode_builtin.h +20 -0
  29. data/vendor/libgit2/deps/ntlmclient/unicode_iconv.c +28 -52
  30. data/vendor/libgit2/deps/ntlmclient/unicode_iconv.h +22 -0
  31. data/vendor/libgit2/include/git2/attr.h +89 -0
  32. data/vendor/libgit2/include/git2/blame.h +93 -42
  33. data/vendor/libgit2/include/git2/blob.h +14 -2
  34. data/vendor/libgit2/include/git2/branch.h +25 -0
  35. data/vendor/libgit2/include/git2/cert.h +42 -5
  36. data/vendor/libgit2/include/git2/checkout.h +28 -12
  37. data/vendor/libgit2/include/git2/commit.h +35 -19
  38. data/vendor/libgit2/include/git2/common.h +14 -4
  39. data/vendor/libgit2/include/git2/deprecated.h +206 -6
  40. data/vendor/libgit2/include/git2/diff.h +34 -19
  41. data/vendor/libgit2/include/git2/errors.h +6 -6
  42. data/vendor/libgit2/include/git2/filter.h +57 -17
  43. data/vendor/libgit2/include/git2/graph.h +20 -2
  44. data/vendor/libgit2/include/git2/index.h +2 -2
  45. data/vendor/libgit2/include/git2/odb.h +29 -0
  46. data/vendor/libgit2/include/git2/patch.h +8 -0
  47. data/vendor/libgit2/include/git2/rebase.h +25 -1
  48. data/vendor/libgit2/include/git2/refs.h +6 -2
  49. data/vendor/libgit2/include/git2/remote.h +59 -6
  50. data/vendor/libgit2/include/git2/revparse.h +5 -5
  51. data/vendor/libgit2/include/git2/status.h +115 -59
  52. data/vendor/libgit2/include/git2/submodule.h +9 -0
  53. data/vendor/libgit2/include/git2/sys/commit_graph.h +174 -0
  54. data/vendor/libgit2/include/git2/sys/filter.h +49 -28
  55. data/vendor/libgit2/include/git2/sys/midx.h +74 -0
  56. data/vendor/libgit2/include/git2/sys/odb_backend.h +7 -0
  57. data/vendor/libgit2/include/git2/sys/transport.h +1 -0
  58. data/vendor/libgit2/include/git2/tag.h +12 -0
  59. data/vendor/libgit2/include/git2/tree.h +0 -14
  60. data/vendor/libgit2/include/git2/types.h +9 -0
  61. data/vendor/libgit2/include/git2/version.h +4 -4
  62. data/vendor/libgit2/include/git2/worktree.h +1 -0
  63. data/vendor/libgit2/src/CMakeLists.txt +25 -4
  64. data/vendor/libgit2/src/alloc.c +21 -8
  65. data/vendor/libgit2/src/allocators/failalloc.c +92 -0
  66. data/vendor/libgit2/src/allocators/failalloc.h +23 -0
  67. data/vendor/libgit2/src/allocators/stdalloc.c +41 -10
  68. data/vendor/libgit2/src/allocators/win32_leakcheck.c +118 -0
  69. data/vendor/libgit2/src/allocators/{win32_crtdbg.h → win32_leakcheck.h} +3 -3
  70. data/vendor/libgit2/src/annotated_commit.c +21 -9
  71. data/vendor/libgit2/src/apply.c +16 -7
  72. data/vendor/libgit2/src/array.h +11 -11
  73. data/vendor/libgit2/src/attr.c +181 -74
  74. data/vendor/libgit2/src/attr_file.c +84 -39
  75. data/vendor/libgit2/src/attr_file.h +32 -11
  76. data/vendor/libgit2/src/attrcache.c +42 -37
  77. data/vendor/libgit2/src/attrcache.h +4 -5
  78. data/vendor/libgit2/src/blame.c +11 -5
  79. data/vendor/libgit2/src/blob.c +35 -24
  80. data/vendor/libgit2/src/branch.c +69 -17
  81. data/vendor/libgit2/src/buffer.c +334 -25
  82. data/vendor/libgit2/src/buffer.h +153 -2
  83. data/vendor/libgit2/src/cache.c +2 -2
  84. data/vendor/libgit2/src/cache.h +7 -7
  85. data/vendor/libgit2/src/cc-compat.h +10 -2
  86. data/vendor/libgit2/src/checkout.c +48 -26
  87. data/vendor/libgit2/src/cherrypick.c +6 -2
  88. data/vendor/libgit2/src/clone.c +41 -47
  89. data/vendor/libgit2/src/commit.c +41 -28
  90. data/vendor/libgit2/src/commit_graph.c +1209 -0
  91. data/vendor/libgit2/src/commit_graph.h +162 -0
  92. data/vendor/libgit2/src/commit_list.c +46 -0
  93. data/vendor/libgit2/src/commit_list.h +2 -0
  94. data/vendor/libgit2/src/common.h +25 -2
  95. data/vendor/libgit2/src/config.c +37 -15
  96. data/vendor/libgit2/src/config_cache.c +5 -3
  97. data/vendor/libgit2/src/config_file.c +16 -8
  98. data/vendor/libgit2/src/config_parse.c +4 -6
  99. data/vendor/libgit2/src/crlf.c +16 -6
  100. data/vendor/libgit2/src/date.c +4 -3
  101. data/vendor/libgit2/src/delta.c +1 -1
  102. data/vendor/libgit2/src/describe.c +6 -3
  103. data/vendor/libgit2/src/diff.c +11 -8
  104. data/vendor/libgit2/src/diff_driver.c +21 -17
  105. data/vendor/libgit2/src/diff_file.c +2 -6
  106. data/vendor/libgit2/src/diff_generate.c +46 -17
  107. data/vendor/libgit2/src/diff_print.c +19 -6
  108. data/vendor/libgit2/src/diff_stats.c +7 -5
  109. data/vendor/libgit2/src/diff_tform.c +9 -8
  110. data/vendor/libgit2/src/diff_xdiff.c +4 -2
  111. data/vendor/libgit2/src/diff_xdiff.h +1 -1
  112. data/vendor/libgit2/src/errors.c +24 -19
  113. data/vendor/libgit2/src/features.h.in +5 -1
  114. data/vendor/libgit2/src/fetch.c +5 -2
  115. data/vendor/libgit2/src/fetchhead.c +8 -4
  116. data/vendor/libgit2/src/filebuf.c +9 -7
  117. data/vendor/libgit2/src/filter.c +206 -110
  118. data/vendor/libgit2/src/filter.h +24 -5
  119. data/vendor/libgit2/src/futils.c +5 -5
  120. data/vendor/libgit2/src/futils.h +1 -1
  121. data/vendor/libgit2/src/graph.c +64 -9
  122. data/vendor/libgit2/src/hash/sha1/collisiondetect.c +3 -3
  123. data/vendor/libgit2/src/hash/sha1/common_crypto.c +3 -3
  124. data/vendor/libgit2/src/hash/sha1/generic.h +1 -1
  125. data/vendor/libgit2/src/hash/sha1/mbedtls.c +12 -12
  126. data/vendor/libgit2/src/hash/sha1/openssl.c +3 -3
  127. data/vendor/libgit2/src/hash/sha1/sha1dc/sha1.c +0 -2
  128. data/vendor/libgit2/src/hash/sha1/win32.c +15 -11
  129. data/vendor/libgit2/src/hash.c +16 -13
  130. data/vendor/libgit2/src/hash.h +1 -1
  131. data/vendor/libgit2/src/hashsig.c +23 -10
  132. data/vendor/libgit2/src/ident.c +13 -3
  133. data/vendor/libgit2/src/ignore.c +35 -19
  134. data/vendor/libgit2/src/index.c +106 -70
  135. data/vendor/libgit2/src/index.h +1 -1
  136. data/vendor/libgit2/src/indexer.c +31 -29
  137. data/vendor/libgit2/src/integer.h +64 -2
  138. data/vendor/libgit2/src/iterator.c +36 -24
  139. data/vendor/libgit2/src/iterator.h +1 -1
  140. data/vendor/libgit2/src/khash.h +2 -11
  141. data/vendor/libgit2/src/{settings.c → libgit2.c} +117 -50
  142. data/vendor/libgit2/src/libgit2.h +15 -0
  143. data/vendor/libgit2/src/mailmap.c +23 -10
  144. data/vendor/libgit2/src/map.h +3 -3
  145. data/vendor/libgit2/src/merge.c +70 -30
  146. data/vendor/libgit2/src/merge.h +2 -1
  147. data/vendor/libgit2/src/merge_driver.c +19 -13
  148. data/vendor/libgit2/src/merge_file.c +11 -3
  149. data/vendor/libgit2/src/message.c +3 -1
  150. data/vendor/libgit2/src/midx.c +471 -10
  151. data/vendor/libgit2/src/midx.h +28 -1
  152. data/vendor/libgit2/src/mwindow.c +103 -59
  153. data/vendor/libgit2/src/mwindow.h +3 -3
  154. data/vendor/libgit2/src/net.c +127 -3
  155. data/vendor/libgit2/src/net.h +16 -2
  156. data/vendor/libgit2/src/netops.c +6 -4
  157. data/vendor/libgit2/src/netops.h +2 -2
  158. data/vendor/libgit2/src/notes.c +10 -10
  159. data/vendor/libgit2/src/object.c +22 -14
  160. data/vendor/libgit2/src/odb.c +285 -48
  161. data/vendor/libgit2/src/odb.h +16 -2
  162. data/vendor/libgit2/src/odb_loose.c +28 -18
  163. data/vendor/libgit2/src/odb_mempack.c +1 -1
  164. data/vendor/libgit2/src/odb_pack.c +391 -114
  165. data/vendor/libgit2/src/oid.c +5 -4
  166. data/vendor/libgit2/src/pack-objects.c +54 -48
  167. data/vendor/libgit2/src/pack.c +329 -119
  168. data/vendor/libgit2/src/pack.h +25 -7
  169. data/vendor/libgit2/src/patch.c +14 -7
  170. data/vendor/libgit2/src/patch_generate.c +2 -2
  171. data/vendor/libgit2/src/patch_parse.c +2 -1
  172. data/vendor/libgit2/src/path.c +98 -53
  173. data/vendor/libgit2/src/path.h +79 -6
  174. data/vendor/libgit2/src/pathspec.c +8 -8
  175. data/vendor/libgit2/src/pool.c +13 -7
  176. data/vendor/libgit2/src/posix.c +11 -3
  177. data/vendor/libgit2/src/reader.c +10 -6
  178. data/vendor/libgit2/src/rebase.c +93 -49
  179. data/vendor/libgit2/src/refdb.c +30 -13
  180. data/vendor/libgit2/src/refdb_fs.c +121 -69
  181. data/vendor/libgit2/src/reflog.c +19 -14
  182. data/vendor/libgit2/src/refs.c +76 -41
  183. data/vendor/libgit2/src/refspec.c +32 -12
  184. data/vendor/libgit2/src/remote.c +272 -102
  185. data/vendor/libgit2/src/remote.h +2 -1
  186. data/vendor/libgit2/src/repository.c +176 -103
  187. data/vendor/libgit2/src/repository.h +12 -1
  188. data/vendor/libgit2/src/reset.c +7 -6
  189. data/vendor/libgit2/src/revert.c +6 -2
  190. data/vendor/libgit2/src/revparse.c +14 -9
  191. data/vendor/libgit2/src/revwalk.c +32 -15
  192. data/vendor/libgit2/src/runtime.c +162 -0
  193. data/vendor/libgit2/src/runtime.h +62 -0
  194. data/vendor/libgit2/src/settings.h +11 -0
  195. data/vendor/libgit2/src/signature.c +6 -5
  196. data/vendor/libgit2/src/sortedcache.h +10 -8
  197. data/vendor/libgit2/src/stash.c +3 -1
  198. data/vendor/libgit2/src/status.c +7 -4
  199. data/vendor/libgit2/src/strarray.c +2 -1
  200. data/vendor/libgit2/src/streams/mbedtls.c +14 -17
  201. data/vendor/libgit2/src/streams/mbedtls.h +1 -1
  202. data/vendor/libgit2/src/streams/openssl.c +101 -201
  203. data/vendor/libgit2/src/streams/openssl.h +9 -1
  204. data/vendor/libgit2/src/streams/openssl_dynamic.c +309 -0
  205. data/vendor/libgit2/src/streams/openssl_dynamic.h +348 -0
  206. data/vendor/libgit2/src/streams/openssl_legacy.c +203 -0
  207. data/vendor/libgit2/src/streams/openssl_legacy.h +63 -0
  208. data/vendor/libgit2/src/streams/registry.c +5 -6
  209. data/vendor/libgit2/src/streams/socket.c +6 -2
  210. data/vendor/libgit2/src/streams/stransport.c +6 -3
  211. data/vendor/libgit2/src/streams/tls.c +5 -3
  212. data/vendor/libgit2/src/submodule.c +128 -62
  213. data/vendor/libgit2/src/submodule.h +9 -9
  214. data/vendor/libgit2/src/sysdir.c +4 -6
  215. data/vendor/libgit2/src/tag.c +47 -11
  216. data/vendor/libgit2/src/thread.c +140 -0
  217. data/vendor/libgit2/src/thread.h +479 -0
  218. data/vendor/libgit2/src/threadstate.c +83 -0
  219. data/vendor/libgit2/src/threadstate.h +24 -0
  220. data/vendor/libgit2/src/trace.c +2 -2
  221. data/vendor/libgit2/src/trace.h +17 -13
  222. data/vendor/libgit2/src/transaction.c +19 -8
  223. data/vendor/libgit2/src/transport.c +3 -3
  224. data/vendor/libgit2/src/transports/auth.c +1 -1
  225. data/vendor/libgit2/src/transports/auth_negotiate.c +11 -4
  226. data/vendor/libgit2/src/transports/auth_ntlm.c +10 -6
  227. data/vendor/libgit2/src/transports/credential.c +15 -7
  228. data/vendor/libgit2/src/transports/git.c +1 -3
  229. data/vendor/libgit2/src/transports/http.c +19 -17
  230. data/vendor/libgit2/src/transports/http.h +1 -0
  231. data/vendor/libgit2/src/transports/httpclient.c +53 -26
  232. data/vendor/libgit2/src/transports/httpclient.h +1 -1
  233. data/vendor/libgit2/src/transports/local.c +3 -3
  234. data/vendor/libgit2/src/transports/smart.c +12 -7
  235. data/vendor/libgit2/src/transports/smart.h +1 -1
  236. data/vendor/libgit2/src/transports/smart_protocol.c +11 -5
  237. data/vendor/libgit2/src/transports/ssh.c +51 -17
  238. data/vendor/libgit2/src/transports/winhttp.c +41 -31
  239. data/vendor/libgit2/src/tree.c +100 -77
  240. data/vendor/libgit2/src/tree.h +1 -0
  241. data/vendor/libgit2/src/tsort.c +0 -2
  242. data/vendor/libgit2/src/unix/map.c +3 -1
  243. data/vendor/libgit2/src/unix/pthread.h +2 -1
  244. data/vendor/libgit2/src/utf8.c +150 -0
  245. data/vendor/libgit2/src/utf8.h +52 -0
  246. data/vendor/libgit2/src/util.c +53 -129
  247. data/vendor/libgit2/src/util.h +33 -39
  248. data/vendor/libgit2/src/vector.c +23 -19
  249. data/vendor/libgit2/src/vector.h +4 -2
  250. data/vendor/libgit2/src/win32/findfile.c +4 -2
  251. data/vendor/libgit2/src/win32/map.c +1 -1
  252. data/vendor/libgit2/src/win32/msvc-compat.h +9 -1
  253. data/vendor/libgit2/src/win32/path_w32.c +22 -24
  254. data/vendor/libgit2/src/win32/path_w32.h +0 -1
  255. data/vendor/libgit2/src/win32/posix_w32.c +7 -1
  256. data/vendor/libgit2/src/win32/precompiled.h +0 -1
  257. data/vendor/libgit2/src/win32/reparse.h +4 -4
  258. data/vendor/libgit2/src/win32/thread.c +24 -15
  259. data/vendor/libgit2/src/win32/thread.h +1 -1
  260. data/vendor/libgit2/src/win32/w32_buffer.c +3 -3
  261. data/vendor/libgit2/src/win32/w32_common.h +18 -9
  262. data/vendor/libgit2/src/win32/{w32_crtdbg_stacktrace.c → w32_leakcheck.c} +269 -33
  263. data/vendor/libgit2/src/win32/w32_leakcheck.h +222 -0
  264. data/vendor/libgit2/src/win32/w32_util.h +6 -6
  265. data/vendor/libgit2/src/worktree.c +27 -16
  266. data/vendor/libgit2/src/zstream.c +1 -1
  267. metadata +32 -16
  268. data/vendor/libgit2/src/allocators/win32_crtdbg.c +0 -118
  269. data/vendor/libgit2/src/buf_text.c +0 -316
  270. data/vendor/libgit2/src/buf_text.h +0 -122
  271. data/vendor/libgit2/src/global.c +0 -363
  272. data/vendor/libgit2/src/global.h +0 -41
  273. data/vendor/libgit2/src/thread-utils.c +0 -58
  274. data/vendor/libgit2/src/thread-utils.h +0 -369
  275. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +0 -127
  276. data/vendor/libgit2/src/win32/w32_stack.c +0 -188
  277. data/vendor/libgit2/src/win32/w32_stack.h +0 -140
@@ -126,7 +126,10 @@ int git_cherrypick_commit(
126
126
  git_tree *parent_tree = NULL, *our_tree = NULL, *cherrypick_tree = NULL;
127
127
  int parent = 0, error = 0;
128
128
 
129
- assert(out && repo && cherrypick_commit && our_commit);
129
+ GIT_ASSERT_ARG(out);
130
+ GIT_ASSERT_ARG(repo);
131
+ GIT_ASSERT_ARG(cherrypick_commit);
132
+ GIT_ASSERT_ARG(our_commit);
130
133
 
131
134
  if (git_commit_parentcount(cherrypick_commit) > 1) {
132
135
  if (!mainline)
@@ -177,7 +180,8 @@ int git_cherrypick(
177
180
  git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
178
181
  int error = 0;
179
182
 
180
- assert(repo && commit);
183
+ GIT_ASSERT_ARG(repo);
184
+ GIT_ASSERT_ARG(commit);
181
185
 
182
186
  GIT_ERROR_CHECK_VERSION(given_opts, GIT_CHERRYPICK_OPTIONS_VERSION, "git_cherrypick_options");
183
187
 
@@ -162,37 +162,6 @@ done:
162
162
  return error;
163
163
  }
164
164
 
165
- static int update_remote_head_byname(
166
- git_repository *repo,
167
- const char *remote_name,
168
- const char *tracking_branch_name,
169
- const char *reflog_message)
170
- {
171
- git_buf tracking_head_name = GIT_BUF_INIT;
172
- git_reference *remote_head = NULL;
173
- int error;
174
-
175
- if ((error = git_buf_printf(&tracking_head_name,
176
- "%s%s/%s",
177
- GIT_REFS_REMOTES_DIR,
178
- remote_name,
179
- GIT_HEAD_FILE)) < 0)
180
- goto cleanup;
181
-
182
- error = git_reference_symbolic_create(
183
- &remote_head,
184
- repo,
185
- git_buf_cstr(&tracking_head_name),
186
- tracking_branch_name,
187
- true,
188
- reflog_message);
189
-
190
- cleanup:
191
- git_reference_free(remote_head);
192
- git_buf_dispose(&tracking_head_name);
193
- return error;
194
- }
195
-
196
165
  static int update_remote_head(
197
166
  git_repository *repo,
198
167
  git_remote *remote,
@@ -200,7 +169,9 @@ static int update_remote_head(
200
169
  const char *reflog_message)
201
170
  {
202
171
  git_refspec *refspec;
203
- git_buf tracking_branch_name = GIT_BUF_INIT;
172
+ git_reference *remote_head = NULL;
173
+ git_buf remote_head_name = GIT_BUF_INIT;
174
+ git_buf remote_branch_name = GIT_BUF_INIT;
204
175
  int error;
205
176
 
206
177
  /* Determine the remote tracking ref name from the local branch */
@@ -213,19 +184,30 @@ static int update_remote_head(
213
184
  }
214
185
 
215
186
  if ((error = git_refspec_transform(
216
- &tracking_branch_name,
187
+ &remote_branch_name,
217
188
  refspec,
218
189
  git_buf_cstr(target))) < 0)
219
190
  goto cleanup;
220
191
 
221
- error = update_remote_head_byname(
222
- repo,
192
+ if ((error = git_buf_printf(&remote_head_name,
193
+ "%s%s/%s",
194
+ GIT_REFS_REMOTES_DIR,
223
195
  git_remote_name(remote),
224
- git_buf_cstr(&tracking_branch_name),
196
+ GIT_HEAD_FILE)) < 0)
197
+ goto cleanup;
198
+
199
+ error = git_reference_symbolic_create(
200
+ &remote_head,
201
+ repo,
202
+ git_buf_cstr(&remote_head_name),
203
+ git_buf_cstr(&remote_branch_name),
204
+ true,
225
205
  reflog_message);
226
206
 
227
207
  cleanup:
228
- git_buf_dispose(&tracking_branch_name);
208
+ git_reference_free(remote_head);
209
+ git_buf_dispose(&remote_branch_name);
210
+ git_buf_dispose(&remote_head_name);
229
211
  return error;
230
212
  }
231
213
 
@@ -249,7 +231,7 @@ static int update_head_to_remote(
249
231
 
250
232
  /* We know we have HEAD, let's see where it points */
251
233
  remote_head = refs[0];
252
- assert(remote_head);
234
+ GIT_ASSERT(remote_head);
253
235
 
254
236
  remote_head_id = &remote_head->oid;
255
237
 
@@ -277,18 +259,20 @@ cleanup:
277
259
 
278
260
  static int update_head_to_branch(
279
261
  git_repository *repo,
280
- const char *remote_name,
262
+ git_remote *remote,
281
263
  const char *branch,
282
264
  const char *reflog_message)
283
265
  {
284
266
  int retcode;
285
267
  git_buf remote_branch_name = GIT_BUF_INIT;
286
268
  git_reference* remote_ref = NULL;
269
+ git_buf default_branch = GIT_BUF_INIT;
287
270
 
288
- assert(remote_name && branch);
271
+ GIT_ASSERT_ARG(remote);
272
+ GIT_ASSERT_ARG(branch);
289
273
 
290
274
  if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
291
- remote_name, branch)) < 0 )
275
+ git_remote_name(remote), branch)) < 0 )
292
276
  goto cleanup;
293
277
 
294
278
  if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
@@ -298,11 +282,18 @@ static int update_head_to_branch(
298
282
  reflog_message)) < 0)
299
283
  goto cleanup;
300
284
 
301
- retcode = update_remote_head_byname(repo, remote_name, remote_branch_name.ptr, reflog_message);
285
+ if ((retcode = git_remote_default_branch(&default_branch, remote)) < 0)
286
+ goto cleanup;
287
+
288
+ if (!git_remote__matching_refspec(remote, git_buf_cstr(&default_branch)))
289
+ goto cleanup;
290
+
291
+ retcode = update_remote_head(repo, remote, &default_branch, reflog_message);
302
292
 
303
293
  cleanup:
304
294
  git_reference_free(remote_ref);
305
295
  git_buf_dispose(&remote_branch_name);
296
+ git_buf_dispose(&default_branch);
306
297
  return retcode;
307
298
  }
308
299
 
@@ -387,8 +378,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
387
378
  int error;
388
379
 
389
380
  if (branch)
390
- error = update_head_to_branch(repo, git_remote_name(remote), branch,
391
- reflog_message);
381
+ error = update_head_to_branch(repo, remote, branch, reflog_message);
392
382
  /* Point HEAD to the same ref as the remote's head */
393
383
  else
394
384
  error = update_head_to_remote(repo, remote, reflog_message);
@@ -406,7 +396,8 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
406
396
  git_fetch_options fetch_opts;
407
397
  git_remote *remote;
408
398
 
409
- assert(repo && _remote);
399
+ GIT_ASSERT_ARG(repo);
400
+ GIT_ASSERT_ARG(_remote);
410
401
 
411
402
  if (!git_repository_is_empty(repo)) {
412
403
  git_error_set(GIT_ERROR_INVALID, "the repository is not empty");
@@ -473,7 +464,9 @@ static int git__clone(
473
464
  uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES;
474
465
  git_repository_create_cb repository_cb;
475
466
 
476
- assert(out && url && local_path);
467
+ GIT_ASSERT_ARG(out);
468
+ GIT_ASSERT_ARG(url);
469
+ GIT_ASSERT_ARG(local_path);
477
470
 
478
471
  if (_options)
479
472
  memcpy(&options, _options, sizeof(git_clone_options));
@@ -596,7 +589,8 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_
596
589
  git_buf src_odb = GIT_BUF_INIT, dst_odb = GIT_BUF_INIT, src_path = GIT_BUF_INIT;
597
590
  git_buf reflog_message = GIT_BUF_INIT;
598
591
 
599
- assert(repo && remote);
592
+ GIT_ASSERT_ARG(repo);
593
+ GIT_ASSERT_ARG(remote);
600
594
 
601
595
  if (!git_repository_is_empty(repo)) {
602
596
  git_error_set(GIT_ERROR_INVALID, "the repository is not empty");
@@ -53,7 +53,8 @@ static int git_commit__create_buffer_internal(
53
53
  size_t i = 0;
54
54
  const git_oid *parent;
55
55
 
56
- assert(out && tree);
56
+ GIT_ASSERT_ARG(out);
57
+ GIT_ASSERT_ARG(tree);
57
58
 
58
59
  git_oid__writebuf(out, "tree ", tree);
59
60
 
@@ -229,7 +230,8 @@ int git_commit_create_v(
229
230
  int error = 0;
230
231
  commit_parent_varargs data;
231
232
 
232
- assert(tree && git_tree_owner(tree) == repo);
233
+ GIT_ASSERT_ARG(tree);
234
+ GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
233
235
 
234
236
  data.total = parent_count;
235
237
  va_start(data.args, parent_count);
@@ -306,7 +308,8 @@ int git_commit_create(
306
308
  {
307
309
  commit_parent_data data = { parent_count, parents, repo };
308
310
 
309
- assert(tree && git_tree_owner(tree) == repo);
311
+ GIT_ASSERT_ARG(tree);
312
+ GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
310
313
 
311
314
  return git_commit__create_internal(
312
315
  id, repo, update_ref, author, committer,
@@ -337,7 +340,8 @@ int git_commit_amend(
337
340
  git_reference *ref;
338
341
  int error;
339
342
 
340
- assert(id && commit_to_amend);
343
+ GIT_ASSERT_ARG(id);
344
+ GIT_ASSERT_ARG(commit_to_amend);
341
345
 
342
346
  repo = git_commit_owner(commit_to_amend);
343
347
 
@@ -356,7 +360,7 @@ int git_commit_amend(
356
360
  git_oid_cpy(&tree_id, git_tree_id(old_tree));
357
361
  git_tree_free(old_tree);
358
362
  } else {
359
- assert(git_tree_owner(tree) == repo);
363
+ GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
360
364
  git_oid_cpy(&tree_id, git_tree_id(tree));
361
365
  }
362
366
 
@@ -392,7 +396,8 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
392
396
  size_t header_len;
393
397
  git_signature dummy_sig;
394
398
 
395
- assert(commit && data);
399
+ GIT_ASSERT_ARG(commit);
400
+ GIT_ASSERT_ARG(data);
396
401
 
397
402
  buffer = buffer_start;
398
403
 
@@ -506,28 +511,28 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
506
511
  return git_commit__parse_ext(_commit, odb_obj, 0);
507
512
  }
508
513
 
509
- #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
514
+ #define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \
510
515
  _rvalue git_commit_##_name(const git_commit *commit) \
511
516
  {\
512
- assert(commit); \
517
+ GIT_ASSERT_ARG_WITH_RETVAL(commit, _invalid); \
513
518
  return _return; \
514
519
  }
515
520
 
516
- GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
517
- GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
518
- GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message)
519
- GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
520
- GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header)
521
- GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
522
- GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
523
- GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids))
524
- GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id)
521
+ GIT_COMMIT_GETTER(const git_signature *, author, commit->author, NULL)
522
+ GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer, NULL)
523
+ GIT_COMMIT_GETTER(const char *, message_raw, commit->raw_message, NULL)
524
+ GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding, NULL)
525
+ GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header, NULL)
526
+ GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time, INT64_MIN)
527
+ GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset, -1)
528
+ GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids), 0)
529
+ GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id, NULL)
525
530
 
526
531
  const char *git_commit_message(const git_commit *commit)
527
532
  {
528
533
  const char *message;
529
534
 
530
- assert(commit);
535
+ GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
531
536
 
532
537
  message = commit->raw_message;
533
538
 
@@ -544,7 +549,7 @@ const char *git_commit_summary(git_commit *commit)
544
549
  const char *msg, *space;
545
550
  bool space_contains_newline = false;
546
551
 
547
- assert(commit);
552
+ GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
548
553
 
549
554
  if (!commit->summary) {
550
555
  for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) {
@@ -587,7 +592,7 @@ const char *git_commit_body(git_commit *commit)
587
592
  {
588
593
  const char *msg, *end;
589
594
 
590
- assert(commit);
595
+ GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
591
596
 
592
597
  if (!commit->body) {
593
598
  /* search for end of summary */
@@ -612,14 +617,14 @@ const char *git_commit_body(git_commit *commit)
612
617
 
613
618
  int git_commit_tree(git_tree **tree_out, const git_commit *commit)
614
619
  {
615
- assert(commit);
620
+ GIT_ASSERT_ARG(commit);
616
621
  return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id);
617
622
  }
618
623
 
619
624
  const git_oid *git_commit_parent_id(
620
625
  const git_commit *commit, unsigned int n)
621
626
  {
622
- assert(commit);
627
+ GIT_ASSERT_ARG_WITH_RETVAL(commit, NULL);
623
628
 
624
629
  return git_array_get(commit->parent_ids, n);
625
630
  }
@@ -628,7 +633,7 @@ int git_commit_parent(
628
633
  git_commit **parent, const git_commit *commit, unsigned int n)
629
634
  {
630
635
  const git_oid *parent_id;
631
- assert(commit);
636
+ GIT_ASSERT_ARG(commit);
632
637
 
633
638
  parent_id = git_commit_parent_id(commit, n);
634
639
  if (parent_id == NULL) {
@@ -647,7 +652,8 @@ int git_commit_nth_gen_ancestor(
647
652
  git_commit *current, *parent = NULL;
648
653
  int error;
649
654
 
650
- assert(ancestor && commit);
655
+ GIT_ASSERT_ARG(ancestor);
656
+ GIT_ASSERT_ARG(commit);
651
657
 
652
658
  if (git_commit_dup(&current, (git_commit *)commit) < 0)
653
659
  return -1;
@@ -840,7 +846,8 @@ int git_commit_create_buffer(git_buf *out,
840
846
  git_array_oid_t parents_arr = GIT_ARRAY_INIT;
841
847
  const git_oid *tree_id;
842
848
 
843
- assert(tree && git_tree_owner(tree) == repo);
849
+ GIT_ASSERT_ARG(tree);
850
+ GIT_ASSERT_ARG(git_tree_owner(tree) == repo);
844
851
 
845
852
  tree_id = git_tree_id(tree);
846
853
 
@@ -859,11 +866,13 @@ int git_commit_create_buffer(git_buf *out,
859
866
  /**
860
867
  * Append to 'out' properly marking continuations when there's a newline in 'content'
861
868
  */
862
- static void format_header_field(git_buf *out, const char *field, const char *content)
869
+ static int format_header_field(git_buf *out, const char *field, const char *content)
863
870
  {
864
871
  const char *lf;
865
872
 
866
- assert(out && field && content);
873
+ GIT_ASSERT_ARG(out);
874
+ GIT_ASSERT_ARG(field);
875
+ GIT_ASSERT_ARG(content);
867
876
 
868
877
  git_buf_puts(out, field);
869
878
  git_buf_putc(out, ' ');
@@ -876,6 +885,8 @@ static void format_header_field(git_buf *out, const char *field, const char *con
876
885
 
877
886
  git_buf_puts(out, content);
878
887
  git_buf_putc(out, '\n');
888
+
889
+ return git_buf_oom(out) ? -1 : 0;
879
890
  }
880
891
 
881
892
  static const git_oid *commit_parent_from_commit(size_t n, void *payload)
@@ -926,7 +937,9 @@ int git_commit_create_with_signature(
926
937
 
927
938
  if (signature != NULL) {
928
939
  field = signature_field ? signature_field : "gpgsig";
929
- format_header_field(&commit, field, signature);
940
+
941
+ if ((error = format_header_field(&commit, field, signature)) < 0)
942
+ goto cleanup;
930
943
  }
931
944
 
932
945
  git_buf_puts(&commit, header_end);
@@ -0,0 +1,1209 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "commit_graph.h"
9
+
10
+ #include "array.h"
11
+ #include "filebuf.h"
12
+ #include "futils.h"
13
+ #include "hash.h"
14
+ #include "oidarray.h"
15
+ #include "oidmap.h"
16
+ #include "pack.h"
17
+ #include "repository.h"
18
+ #include "revwalk.h"
19
+
20
+ #define GIT_COMMIT_GRAPH_MISSING_PARENT 0x70000000
21
+ #define GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX 0x3FFFFFFF
22
+ #define GIT_COMMIT_GRAPH_GENERATION_NUMBER_INFINITY 0xFFFFFFFF
23
+
24
+ #define COMMIT_GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
25
+ #define COMMIT_GRAPH_VERSION 1
26
+ #define COMMIT_GRAPH_OBJECT_ID_VERSION 1
27
+ struct git_commit_graph_header {
28
+ uint32_t signature;
29
+ uint8_t version;
30
+ uint8_t object_id_version;
31
+ uint8_t chunks;
32
+ uint8_t base_graph_files;
33
+ };
34
+
35
+ #define COMMIT_GRAPH_OID_FANOUT_ID 0x4f494446 /* "OIDF" */
36
+ #define COMMIT_GRAPH_OID_LOOKUP_ID 0x4f49444c /* "OIDL" */
37
+ #define COMMIT_GRAPH_COMMIT_DATA_ID 0x43444154 /* "CDAT" */
38
+ #define COMMIT_GRAPH_EXTRA_EDGE_LIST_ID 0x45444745 /* "EDGE" */
39
+ #define COMMIT_GRAPH_BLOOM_FILTER_INDEX_ID 0x42494458 /* "BIDX" */
40
+ #define COMMIT_GRAPH_BLOOM_FILTER_DATA_ID 0x42444154 /* "BDAT" */
41
+
42
+ struct git_commit_graph_chunk {
43
+ off64_t offset;
44
+ size_t length;
45
+ };
46
+
47
+ typedef git_array_t(size_t) parent_index_array_t;
48
+
49
+ struct packed_commit {
50
+ size_t index;
51
+ git_oid sha1;
52
+ git_oid tree_oid;
53
+ uint32_t generation;
54
+ git_time_t commit_time;
55
+ git_array_oid_t parents;
56
+ parent_index_array_t parent_indices;
57
+ };
58
+
59
+ static void packed_commit_free(struct packed_commit *p)
60
+ {
61
+ if (!p)
62
+ return;
63
+
64
+ git_array_clear(p->parents);
65
+ git_array_clear(p->parent_indices);
66
+ git__free(p);
67
+ }
68
+
69
+ static struct packed_commit *packed_commit_new(git_commit *commit)
70
+ {
71
+ unsigned int i, parentcount = git_commit_parentcount(commit);
72
+ struct packed_commit *p = git__calloc(1, sizeof(struct packed_commit));
73
+ if (!p)
74
+ goto cleanup;
75
+
76
+ git_array_init_to_size(p->parents, parentcount);
77
+ if (parentcount && !p->parents.ptr)
78
+ goto cleanup;
79
+
80
+ if (git_oid_cpy(&p->sha1, git_commit_id(commit)) < 0)
81
+ goto cleanup;
82
+ if (git_oid_cpy(&p->tree_oid, git_commit_tree_id(commit)) < 0)
83
+ goto cleanup;
84
+ p->commit_time = git_commit_time(commit);
85
+
86
+ for (i = 0; i < parentcount; ++i) {
87
+ git_oid *parent_id = git_array_alloc(p->parents);
88
+ if (!parent_id)
89
+ goto cleanup;
90
+ if (git_oid_cpy(parent_id, git_commit_parent_id(commit, i)) < 0)
91
+ goto cleanup;
92
+ }
93
+
94
+ return p;
95
+
96
+ cleanup:
97
+ packed_commit_free(p);
98
+ return NULL;
99
+ }
100
+
101
+ typedef int (*commit_graph_write_cb)(const char *buf, size_t size, void *cb_data);
102
+
103
+ static int commit_graph_error(const char *message)
104
+ {
105
+ git_error_set(GIT_ERROR_ODB, "invalid commit-graph file - %s", message);
106
+ return -1;
107
+ }
108
+
109
+ static int commit_graph_parse_oid_fanout(
110
+ git_commit_graph_file *file,
111
+ const unsigned char *data,
112
+ struct git_commit_graph_chunk *chunk_oid_fanout)
113
+ {
114
+ uint32_t i, nr;
115
+ if (chunk_oid_fanout->offset == 0)
116
+ return commit_graph_error("missing OID Fanout chunk");
117
+ if (chunk_oid_fanout->length == 0)
118
+ return commit_graph_error("empty OID Fanout chunk");
119
+ if (chunk_oid_fanout->length != 256 * 4)
120
+ return commit_graph_error("OID Fanout chunk has wrong length");
121
+
122
+ file->oid_fanout = (const uint32_t *)(data + chunk_oid_fanout->offset);
123
+ nr = 0;
124
+ for (i = 0; i < 256; ++i) {
125
+ uint32_t n = ntohl(file->oid_fanout[i]);
126
+ if (n < nr)
127
+ return commit_graph_error("index is non-monotonic");
128
+ nr = n;
129
+ }
130
+ file->num_commits = nr;
131
+ return 0;
132
+ }
133
+
134
+ static int commit_graph_parse_oid_lookup(
135
+ git_commit_graph_file *file,
136
+ const unsigned char *data,
137
+ struct git_commit_graph_chunk *chunk_oid_lookup)
138
+ {
139
+ uint32_t i;
140
+ git_oid *oid, *prev_oid, zero_oid = {{0}};
141
+
142
+ if (chunk_oid_lookup->offset == 0)
143
+ return commit_graph_error("missing OID Lookup chunk");
144
+ if (chunk_oid_lookup->length == 0)
145
+ return commit_graph_error("empty OID Lookup chunk");
146
+ if (chunk_oid_lookup->length != file->num_commits * GIT_OID_RAWSZ)
147
+ return commit_graph_error("OID Lookup chunk has wrong length");
148
+
149
+ file->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset);
150
+ prev_oid = &zero_oid;
151
+ for (i = 0; i < file->num_commits; ++i, ++oid) {
152
+ if (git_oid_cmp(prev_oid, oid) >= 0)
153
+ return commit_graph_error("OID Lookup index is non-monotonic");
154
+ prev_oid = oid;
155
+ }
156
+
157
+ return 0;
158
+ }
159
+
160
+ static int commit_graph_parse_commit_data(
161
+ git_commit_graph_file *file,
162
+ const unsigned char *data,
163
+ struct git_commit_graph_chunk *chunk_commit_data)
164
+ {
165
+ if (chunk_commit_data->offset == 0)
166
+ return commit_graph_error("missing Commit Data chunk");
167
+ if (chunk_commit_data->length == 0)
168
+ return commit_graph_error("empty Commit Data chunk");
169
+ if (chunk_commit_data->length != file->num_commits * (GIT_OID_RAWSZ + 16))
170
+ return commit_graph_error("Commit Data chunk has wrong length");
171
+
172
+ file->commit_data = data + chunk_commit_data->offset;
173
+
174
+ return 0;
175
+ }
176
+
177
+ static int commit_graph_parse_extra_edge_list(
178
+ git_commit_graph_file *file,
179
+ const unsigned char *data,
180
+ struct git_commit_graph_chunk *chunk_extra_edge_list)
181
+ {
182
+ if (chunk_extra_edge_list->length == 0)
183
+ return 0;
184
+ if (chunk_extra_edge_list->length % 4 != 0)
185
+ return commit_graph_error("malformed Extra Edge List chunk");
186
+
187
+ file->extra_edge_list = data + chunk_extra_edge_list->offset;
188
+ file->num_extra_edge_list = chunk_extra_edge_list->length / 4;
189
+
190
+ return 0;
191
+ }
192
+
193
+ int git_commit_graph_file_parse(
194
+ git_commit_graph_file *file,
195
+ const unsigned char *data,
196
+ size_t size)
197
+ {
198
+ struct git_commit_graph_header *hdr;
199
+ const unsigned char *chunk_hdr;
200
+ struct git_commit_graph_chunk *last_chunk;
201
+ uint32_t i;
202
+ off64_t last_chunk_offset, chunk_offset, trailer_offset;
203
+ git_oid cgraph_checksum = {{0}};
204
+ int error;
205
+ struct git_commit_graph_chunk chunk_oid_fanout = {0}, chunk_oid_lookup = {0},
206
+ chunk_commit_data = {0}, chunk_extra_edge_list = {0},
207
+ chunk_unsupported = {0};
208
+
209
+ GIT_ASSERT_ARG(file);
210
+
211
+ if (size < sizeof(struct git_commit_graph_header) + GIT_OID_RAWSZ)
212
+ return commit_graph_error("commit-graph is too short");
213
+
214
+ hdr = ((struct git_commit_graph_header *)data);
215
+
216
+ if (hdr->signature != htonl(COMMIT_GRAPH_SIGNATURE) || hdr->version != COMMIT_GRAPH_VERSION
217
+ || hdr->object_id_version != COMMIT_GRAPH_OBJECT_ID_VERSION) {
218
+ return commit_graph_error("unsupported commit-graph version");
219
+ }
220
+ if (hdr->chunks == 0)
221
+ return commit_graph_error("no chunks in commit-graph");
222
+
223
+ /*
224
+ * The very first chunk's offset should be after the header, all the chunk
225
+ * headers, and a special zero chunk.
226
+ */
227
+ last_chunk_offset = sizeof(struct git_commit_graph_header) + (1 + hdr->chunks) * 12;
228
+ trailer_offset = size - GIT_OID_RAWSZ;
229
+ if (trailer_offset < last_chunk_offset)
230
+ return commit_graph_error("wrong commit-graph size");
231
+ git_oid_cpy(&file->checksum, (git_oid *)(data + trailer_offset));
232
+
233
+ if (git_hash_buf(&cgraph_checksum, data, (size_t)trailer_offset) < 0)
234
+ return commit_graph_error("could not calculate signature");
235
+ if (!git_oid_equal(&cgraph_checksum, &file->checksum))
236
+ return commit_graph_error("index signature mismatch");
237
+
238
+ chunk_hdr = data + sizeof(struct git_commit_graph_header);
239
+ last_chunk = NULL;
240
+ for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) {
241
+ chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32
242
+ | ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8))));
243
+ if (chunk_offset < last_chunk_offset)
244
+ return commit_graph_error("chunks are non-monotonic");
245
+ if (chunk_offset >= trailer_offset)
246
+ return commit_graph_error("chunks extend beyond the trailer");
247
+ if (last_chunk != NULL)
248
+ last_chunk->length = (size_t)(chunk_offset - last_chunk_offset);
249
+ last_chunk_offset = chunk_offset;
250
+
251
+ switch (ntohl(*((uint32_t *)(chunk_hdr + 0)))) {
252
+ case COMMIT_GRAPH_OID_FANOUT_ID:
253
+ chunk_oid_fanout.offset = last_chunk_offset;
254
+ last_chunk = &chunk_oid_fanout;
255
+ break;
256
+
257
+ case COMMIT_GRAPH_OID_LOOKUP_ID:
258
+ chunk_oid_lookup.offset = last_chunk_offset;
259
+ last_chunk = &chunk_oid_lookup;
260
+ break;
261
+
262
+ case COMMIT_GRAPH_COMMIT_DATA_ID:
263
+ chunk_commit_data.offset = last_chunk_offset;
264
+ last_chunk = &chunk_commit_data;
265
+ break;
266
+
267
+ case COMMIT_GRAPH_EXTRA_EDGE_LIST_ID:
268
+ chunk_extra_edge_list.offset = last_chunk_offset;
269
+ last_chunk = &chunk_extra_edge_list;
270
+ break;
271
+
272
+ case COMMIT_GRAPH_BLOOM_FILTER_INDEX_ID:
273
+ case COMMIT_GRAPH_BLOOM_FILTER_DATA_ID:
274
+ chunk_unsupported.offset = last_chunk_offset;
275
+ last_chunk = &chunk_unsupported;
276
+ break;
277
+
278
+ default:
279
+ return commit_graph_error("unrecognized chunk ID");
280
+ }
281
+ }
282
+ last_chunk->length = (size_t)(trailer_offset - last_chunk_offset);
283
+
284
+ error = commit_graph_parse_oid_fanout(file, data, &chunk_oid_fanout);
285
+ if (error < 0)
286
+ return error;
287
+ error = commit_graph_parse_oid_lookup(file, data, &chunk_oid_lookup);
288
+ if (error < 0)
289
+ return error;
290
+ error = commit_graph_parse_commit_data(file, data, &chunk_commit_data);
291
+ if (error < 0)
292
+ return error;
293
+ error = commit_graph_parse_extra_edge_list(file, data, &chunk_extra_edge_list);
294
+ if (error < 0)
295
+ return error;
296
+
297
+ return 0;
298
+ }
299
+
300
+ int git_commit_graph_new(git_commit_graph **cgraph_out, const char *objects_dir, bool open_file)
301
+ {
302
+ git_commit_graph *cgraph = NULL;
303
+ int error = 0;
304
+
305
+ GIT_ASSERT_ARG(cgraph_out);
306
+ GIT_ASSERT_ARG(objects_dir);
307
+
308
+ cgraph = git__calloc(1, sizeof(git_commit_graph));
309
+ GIT_ERROR_CHECK_ALLOC(cgraph);
310
+
311
+ error = git_buf_joinpath(&cgraph->filename, objects_dir, "info/commit-graph");
312
+ if (error < 0)
313
+ goto error;
314
+
315
+ if (open_file) {
316
+ error = git_commit_graph_file_open(&cgraph->file, git_buf_cstr(&cgraph->filename));
317
+ if (error < 0)
318
+ goto error;
319
+ cgraph->checked = 1;
320
+ }
321
+
322
+ *cgraph_out = cgraph;
323
+ return 0;
324
+
325
+ error:
326
+ git_commit_graph_free(cgraph);
327
+ return error;
328
+ }
329
+
330
+ int git_commit_graph_open(git_commit_graph **cgraph_out, const char *objects_dir)
331
+ {
332
+ return git_commit_graph_new(cgraph_out, objects_dir, true);
333
+ }
334
+
335
+ int git_commit_graph_file_open(git_commit_graph_file **file_out, const char *path)
336
+ {
337
+ git_commit_graph_file *file;
338
+ git_file fd = -1;
339
+ size_t cgraph_size;
340
+ struct stat st;
341
+ int error;
342
+
343
+ /* TODO: properly open the file without access time using O_NOATIME */
344
+ fd = git_futils_open_ro(path);
345
+ if (fd < 0)
346
+ return fd;
347
+
348
+ if (p_fstat(fd, &st) < 0) {
349
+ p_close(fd);
350
+ git_error_set(GIT_ERROR_ODB, "commit-graph file not found - '%s'", path);
351
+ return GIT_ENOTFOUND;
352
+ }
353
+
354
+ if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)) {
355
+ p_close(fd);
356
+ git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path);
357
+ return GIT_ENOTFOUND;
358
+ }
359
+ cgraph_size = (size_t)st.st_size;
360
+
361
+ file = git__calloc(1, sizeof(git_commit_graph_file));
362
+ GIT_ERROR_CHECK_ALLOC(file);
363
+
364
+ error = git_futils_mmap_ro(&file->graph_map, fd, 0, cgraph_size);
365
+ p_close(fd);
366
+ if (error < 0) {
367
+ git_commit_graph_file_free(file);
368
+ return error;
369
+ }
370
+
371
+ if ((error = git_commit_graph_file_parse(file, file->graph_map.data, cgraph_size)) < 0) {
372
+ git_commit_graph_file_free(file);
373
+ return error;
374
+ }
375
+
376
+ *file_out = file;
377
+ return 0;
378
+ }
379
+
380
+ int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph *cgraph)
381
+ {
382
+ if (!cgraph->checked) {
383
+ int error = 0;
384
+ git_commit_graph_file *result = NULL;
385
+
386
+ /* We only check once, no matter the result. */
387
+ cgraph->checked = 1;
388
+
389
+ /* Best effort */
390
+ error = git_commit_graph_file_open(&result, git_buf_cstr(&cgraph->filename));
391
+
392
+ if (error < 0)
393
+ return error;
394
+
395
+ cgraph->file = result;
396
+ }
397
+ if (!cgraph->file)
398
+ return GIT_ENOTFOUND;
399
+
400
+ *file_out = cgraph->file;
401
+ return 0;
402
+ }
403
+
404
+ void git_commit_graph_refresh(git_commit_graph *cgraph)
405
+ {
406
+ if (!cgraph->checked)
407
+ return;
408
+
409
+ if (cgraph->file
410
+ && git_commit_graph_file_needs_refresh(cgraph->file, git_buf_cstr(&cgraph->filename))) {
411
+ /* We just free the commit graph. The next time it is requested, it will be
412
+ * re-loaded. */
413
+ git_commit_graph_file_free(cgraph->file);
414
+ cgraph->file = NULL;
415
+ }
416
+ /* Force a lazy re-check next time it is needed. */
417
+ cgraph->checked = 0;
418
+ }
419
+
420
+ static int git_commit_graph_entry_get_byindex(
421
+ git_commit_graph_entry *e,
422
+ const git_commit_graph_file *file,
423
+ size_t pos)
424
+ {
425
+ const unsigned char *commit_data;
426
+
427
+ GIT_ASSERT_ARG(e);
428
+ GIT_ASSERT_ARG(file);
429
+
430
+ if (pos >= file->num_commits) {
431
+ git_error_set(GIT_ERROR_INVALID, "commit index %zu does not exist", pos);
432
+ return GIT_ENOTFOUND;
433
+ }
434
+
435
+ commit_data = file->commit_data + pos * (GIT_OID_RAWSZ + 4 * sizeof(uint32_t));
436
+ git_oid_cpy(&e->tree_oid, (const git_oid *)commit_data);
437
+ e->parent_indices[0] = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ)));
438
+ e->parent_indices[1] = ntohl(
439
+ *((uint32_t *)(commit_data + GIT_OID_RAWSZ + sizeof(uint32_t))));
440
+ e->parent_count = (e->parent_indices[0] != GIT_COMMIT_GRAPH_MISSING_PARENT)
441
+ + (e->parent_indices[1] != GIT_COMMIT_GRAPH_MISSING_PARENT);
442
+ e->generation = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 2 * sizeof(uint32_t))));
443
+ e->commit_time = ntohl(*((uint32_t *)(commit_data + GIT_OID_RAWSZ + 3 * sizeof(uint32_t))));
444
+
445
+ e->commit_time |= (e->generation & UINT64_C(0x3)) << UINT64_C(32);
446
+ e->generation >>= 2u;
447
+ if (e->parent_indices[1] & 0x80000000u) {
448
+ uint32_t extra_edge_list_pos = e->parent_indices[1] & 0x7fffffff;
449
+
450
+ /* Make sure we're not being sent out of bounds */
451
+ if (extra_edge_list_pos >= file->num_extra_edge_list) {
452
+ git_error_set(GIT_ERROR_INVALID,
453
+ "commit %u does not exist",
454
+ extra_edge_list_pos);
455
+ return GIT_ENOTFOUND;
456
+ }
457
+
458
+ e->extra_parents_index = extra_edge_list_pos;
459
+ while (extra_edge_list_pos < file->num_extra_edge_list
460
+ && (ntohl(*(
461
+ (uint32_t *)(file->extra_edge_list
462
+ + extra_edge_list_pos * sizeof(uint32_t))))
463
+ & 0x80000000u)
464
+ == 0) {
465
+ extra_edge_list_pos++;
466
+ e->parent_count++;
467
+ }
468
+ }
469
+ git_oid_cpy(&e->sha1, &file->oid_lookup[pos]);
470
+ return 0;
471
+ }
472
+
473
+ bool git_commit_graph_file_needs_refresh(const git_commit_graph_file *file, const char *path)
474
+ {
475
+ git_file fd = -1;
476
+ struct stat st;
477
+ ssize_t bytes_read;
478
+ git_oid cgraph_checksum = {{0}};
479
+
480
+ /* TODO: properly open the file without access time using O_NOATIME */
481
+ fd = git_futils_open_ro(path);
482
+ if (fd < 0)
483
+ return true;
484
+
485
+ if (p_fstat(fd, &st) < 0) {
486
+ p_close(fd);
487
+ return true;
488
+ }
489
+
490
+ if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)
491
+ || (size_t)st.st_size != file->graph_map.len) {
492
+ p_close(fd);
493
+ return true;
494
+ }
495
+
496
+ bytes_read = p_pread(fd, cgraph_checksum.id, GIT_OID_RAWSZ, st.st_size - GIT_OID_RAWSZ);
497
+ p_close(fd);
498
+ if (bytes_read != GIT_OID_RAWSZ)
499
+ return true;
500
+
501
+ return !git_oid_equal(&cgraph_checksum, &file->checksum);
502
+ }
503
+
504
+ int git_commit_graph_entry_find(
505
+ git_commit_graph_entry *e,
506
+ const git_commit_graph_file *file,
507
+ const git_oid *short_oid,
508
+ size_t len)
509
+ {
510
+ int pos, found = 0;
511
+ uint32_t hi, lo;
512
+ const git_oid *current = NULL;
513
+
514
+ GIT_ASSERT_ARG(e);
515
+ GIT_ASSERT_ARG(file);
516
+ GIT_ASSERT_ARG(short_oid);
517
+
518
+ hi = ntohl(file->oid_fanout[(int)short_oid->id[0]]);
519
+ lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(file->oid_fanout[(int)short_oid->id[0] - 1]));
520
+
521
+ pos = git_pack__lookup_sha1(file->oid_lookup, GIT_OID_RAWSZ, lo, hi, short_oid->id);
522
+
523
+ if (pos >= 0) {
524
+ /* An object matching exactly the oid was found */
525
+ found = 1;
526
+ current = file->oid_lookup + pos;
527
+ } else {
528
+ /* No object was found */
529
+ /* pos refers to the object with the "closest" oid to short_oid */
530
+ pos = -1 - pos;
531
+ if (pos < (int)file->num_commits) {
532
+ current = file->oid_lookup + pos;
533
+
534
+ if (!git_oid_ncmp(short_oid, current, len))
535
+ found = 1;
536
+ }
537
+ }
538
+
539
+ if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)file->num_commits) {
540
+ /* Check for ambiguousity */
541
+ const git_oid *next = current + 1;
542
+
543
+ if (!git_oid_ncmp(short_oid, next, len)) {
544
+ found = 2;
545
+ }
546
+ }
547
+
548
+ if (!found)
549
+ return git_odb__error_notfound(
550
+ "failed to find offset for commit-graph index entry", short_oid, len);
551
+ if (found > 1)
552
+ return git_odb__error_ambiguous(
553
+ "found multiple offsets for commit-graph index entry");
554
+
555
+ return git_commit_graph_entry_get_byindex(e, file, pos);
556
+ }
557
+
558
+ int git_commit_graph_entry_parent(
559
+ git_commit_graph_entry *parent,
560
+ const git_commit_graph_file *file,
561
+ const git_commit_graph_entry *entry,
562
+ size_t n)
563
+ {
564
+ GIT_ASSERT_ARG(parent);
565
+ GIT_ASSERT_ARG(file);
566
+
567
+ if (n >= entry->parent_count) {
568
+ git_error_set(GIT_ERROR_INVALID, "parent index %zu does not exist", n);
569
+ return GIT_ENOTFOUND;
570
+ }
571
+
572
+ if (n == 0 || (n == 1 && entry->parent_count == 2))
573
+ return git_commit_graph_entry_get_byindex(parent, file, entry->parent_indices[n]);
574
+
575
+ return git_commit_graph_entry_get_byindex(
576
+ parent,
577
+ file,
578
+ ntohl(
579
+ *(uint32_t *)(file->extra_edge_list
580
+ + (entry->extra_parents_index + n - 1)
581
+ * sizeof(uint32_t)))
582
+ & 0x7fffffff);
583
+ }
584
+
585
+ int git_commit_graph_file_close(git_commit_graph_file *file)
586
+ {
587
+ GIT_ASSERT_ARG(file);
588
+
589
+ if (file->graph_map.data)
590
+ git_futils_mmap_free(&file->graph_map);
591
+
592
+ return 0;
593
+ }
594
+
595
+ void git_commit_graph_free(git_commit_graph *cgraph)
596
+ {
597
+ if (!cgraph)
598
+ return;
599
+
600
+ git_buf_dispose(&cgraph->filename);
601
+ git_commit_graph_file_free(cgraph->file);
602
+ git__free(cgraph);
603
+ }
604
+
605
+ void git_commit_graph_file_free(git_commit_graph_file *file)
606
+ {
607
+ if (!file)
608
+ return;
609
+
610
+ git_commit_graph_file_close(file);
611
+ git__free(file);
612
+ }
613
+
614
+ static int packed_commit__cmp(const void *a_, const void *b_)
615
+ {
616
+ const struct packed_commit *a = a_;
617
+ const struct packed_commit *b = b_;
618
+ return git_oid_cmp(&a->sha1, &b->sha1);
619
+ }
620
+
621
+ int git_commit_graph_writer_new(git_commit_graph_writer **out, const char *objects_info_dir)
622
+ {
623
+ git_commit_graph_writer *w = git__calloc(1, sizeof(git_commit_graph_writer));
624
+ GIT_ERROR_CHECK_ALLOC(w);
625
+
626
+ if (git_buf_sets(&w->objects_info_dir, objects_info_dir) < 0) {
627
+ git__free(w);
628
+ return -1;
629
+ }
630
+
631
+ if (git_vector_init(&w->commits, 0, packed_commit__cmp) < 0) {
632
+ git_buf_dispose(&w->objects_info_dir);
633
+ git__free(w);
634
+ return -1;
635
+ }
636
+
637
+ *out = w;
638
+ return 0;
639
+ }
640
+
641
+ void git_commit_graph_writer_free(git_commit_graph_writer *w)
642
+ {
643
+ struct packed_commit *packed_commit;
644
+ size_t i;
645
+
646
+ if (!w)
647
+ return;
648
+
649
+ git_vector_foreach (&w->commits, i, packed_commit)
650
+ packed_commit_free(packed_commit);
651
+ git_vector_free(&w->commits);
652
+ git_buf_dispose(&w->objects_info_dir);
653
+ git__free(w);
654
+ }
655
+
656
+ struct object_entry_cb_state {
657
+ git_repository *repo;
658
+ git_odb *db;
659
+ git_vector *commits;
660
+ };
661
+
662
+ static int object_entry__cb(const git_oid *id, void *data)
663
+ {
664
+ struct object_entry_cb_state *state = (struct object_entry_cb_state *)data;
665
+ git_commit *commit = NULL;
666
+ struct packed_commit *packed_commit = NULL;
667
+ size_t header_len;
668
+ git_object_t header_type;
669
+ int error = 0;
670
+
671
+ error = git_odb_read_header(&header_len, &header_type, state->db, id);
672
+ if (error < 0)
673
+ return error;
674
+
675
+ if (header_type != GIT_OBJECT_COMMIT)
676
+ return 0;
677
+
678
+ error = git_commit_lookup(&commit, state->repo, id);
679
+ if (error < 0)
680
+ return error;
681
+
682
+ packed_commit = packed_commit_new(commit);
683
+ git_commit_free(commit);
684
+ GIT_ERROR_CHECK_ALLOC(packed_commit);
685
+
686
+ error = git_vector_insert(state->commits, packed_commit);
687
+ if (error < 0) {
688
+ packed_commit_free(packed_commit);
689
+ return error;
690
+ }
691
+
692
+ return 0;
693
+ }
694
+
695
+ int git_commit_graph_writer_add_index_file(
696
+ git_commit_graph_writer *w,
697
+ git_repository *repo,
698
+ const char *idx_path)
699
+ {
700
+ int error;
701
+ struct git_pack_file *p = NULL;
702
+ struct object_entry_cb_state state = {0};
703
+ state.repo = repo;
704
+ state.commits = &w->commits;
705
+
706
+ error = git_repository_odb(&state.db, repo);
707
+ if (error < 0)
708
+ goto cleanup;
709
+
710
+ error = git_mwindow_get_pack(&p, idx_path);
711
+ if (error < 0)
712
+ goto cleanup;
713
+
714
+ error = git_pack_foreach_entry(p, object_entry__cb, &state);
715
+ if (error < 0)
716
+ goto cleanup;
717
+
718
+ cleanup:
719
+ if (p)
720
+ git_mwindow_put_pack(p);
721
+ git_odb_free(state.db);
722
+ return error;
723
+ }
724
+
725
+ int git_commit_graph_writer_add_revwalk(git_commit_graph_writer *w, git_revwalk *walk)
726
+ {
727
+ int error;
728
+ git_oid id;
729
+ git_repository *repo = git_revwalk_repository(walk);
730
+ git_commit *commit;
731
+ struct packed_commit* packed_commit;
732
+
733
+ while ((git_revwalk_next(&id, walk)) == 0) {
734
+ error = git_commit_lookup(&commit, repo, &id);
735
+ if (error < 0)
736
+ return error;
737
+
738
+ packed_commit = packed_commit_new(commit);
739
+ git_commit_free(commit);
740
+ GIT_ERROR_CHECK_ALLOC(packed_commit);
741
+
742
+ error = git_vector_insert(&w->commits, packed_commit);
743
+ if (error < 0) {
744
+ packed_commit_free(packed_commit);
745
+ return error;
746
+ }
747
+ }
748
+
749
+ return 0;
750
+ }
751
+
752
+ enum generation_number_commit_state {
753
+ GENERATION_NUMBER_COMMIT_STATE_UNVISITED = 0,
754
+ GENERATION_NUMBER_COMMIT_STATE_ADDED = 1,
755
+ GENERATION_NUMBER_COMMIT_STATE_EXPANDED = 2,
756
+ GENERATION_NUMBER_COMMIT_STATE_VISITED = 3,
757
+ };
758
+
759
+ static int compute_generation_numbers(git_vector *commits)
760
+ {
761
+ git_array_t(size_t) index_stack = GIT_ARRAY_INIT;
762
+ size_t i, j;
763
+ size_t *parent_idx;
764
+ enum generation_number_commit_state *commit_states = NULL;
765
+ struct packed_commit *child_packed_commit;
766
+ git_oidmap *packed_commit_map = NULL;
767
+ int error = 0;
768
+
769
+ /* First populate the parent indices fields */
770
+ error = git_oidmap_new(&packed_commit_map);
771
+ if (error < 0)
772
+ goto cleanup;
773
+ git_vector_foreach (commits, i, child_packed_commit) {
774
+ child_packed_commit->index = i;
775
+ error = git_oidmap_set(
776
+ packed_commit_map, &child_packed_commit->sha1, child_packed_commit);
777
+ if (error < 0)
778
+ goto cleanup;
779
+ }
780
+
781
+ git_vector_foreach (commits, i, child_packed_commit) {
782
+ size_t parent_i, *parent_idx_ptr;
783
+ struct packed_commit *parent_packed_commit;
784
+ git_oid *parent_id;
785
+ git_array_init_to_size(
786
+ child_packed_commit->parent_indices,
787
+ git_array_size(child_packed_commit->parents));
788
+ if (git_array_size(child_packed_commit->parents)
789
+ && !child_packed_commit->parent_indices.ptr) {
790
+ error = -1;
791
+ goto cleanup;
792
+ }
793
+ git_array_foreach (child_packed_commit->parents, parent_i, parent_id) {
794
+ parent_packed_commit = git_oidmap_get(packed_commit_map, parent_id);
795
+ if (!parent_packed_commit) {
796
+ git_error_set(GIT_ERROR_ODB,
797
+ "parent commit %s not found in commit graph",
798
+ git_oid_tostr_s(parent_id));
799
+ error = GIT_ENOTFOUND;
800
+ goto cleanup;
801
+ }
802
+ parent_idx_ptr = git_array_alloc(child_packed_commit->parent_indices);
803
+ if (!parent_idx_ptr) {
804
+ error = -1;
805
+ goto cleanup;
806
+ }
807
+ *parent_idx_ptr = parent_packed_commit->index;
808
+ }
809
+ }
810
+
811
+ /*
812
+ * We copy all the commits to the stack and then during visitation,
813
+ * each node can be added up to two times to the stack.
814
+ */
815
+ git_array_init_to_size(index_stack, 3 * git_vector_length(commits));
816
+ if (!index_stack.ptr) {
817
+ error = -1;
818
+ goto cleanup;
819
+ }
820
+
821
+ commit_states = (enum generation_number_commit_state *)git__calloc(
822
+ git_vector_length(commits), sizeof(enum generation_number_commit_state));
823
+ if (!commit_states) {
824
+ error = -1;
825
+ goto cleanup;
826
+ }
827
+
828
+ /*
829
+ * Perform a Post-Order traversal so that all parent nodes are fully
830
+ * visited before the child node.
831
+ */
832
+ git_vector_foreach (commits, i, child_packed_commit)
833
+ *(size_t *)git_array_alloc(index_stack) = i;
834
+
835
+ while (git_array_size(index_stack)) {
836
+ size_t *index_ptr = git_array_pop(index_stack);
837
+ i = *index_ptr;
838
+ child_packed_commit = git_vector_get(commits, i);
839
+
840
+ if (commit_states[i] == GENERATION_NUMBER_COMMIT_STATE_VISITED) {
841
+ /* This commit has already been fully visited. */
842
+ continue;
843
+ }
844
+ if (commit_states[i] == GENERATION_NUMBER_COMMIT_STATE_EXPANDED) {
845
+ /* All of the commits parents have been visited. */
846
+ child_packed_commit->generation = 0;
847
+ git_array_foreach (child_packed_commit->parent_indices, j, parent_idx) {
848
+ struct packed_commit *parent = git_vector_get(commits, *parent_idx);
849
+ if (child_packed_commit->generation < parent->generation)
850
+ child_packed_commit->generation = parent->generation;
851
+ }
852
+ if (child_packed_commit->generation
853
+ < GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX) {
854
+ ++child_packed_commit->generation;
855
+ }
856
+ commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_VISITED;
857
+ continue;
858
+ }
859
+
860
+ /*
861
+ * This is the first time we see this commit. We need
862
+ * to visit all its parents before we can fully visit
863
+ * it.
864
+ */
865
+ if (git_array_size(child_packed_commit->parent_indices) == 0) {
866
+ /*
867
+ * Special case: if the commit has no parents, there's
868
+ * no need to add it to the stack just to immediately
869
+ * remove it.
870
+ */
871
+ commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_VISITED;
872
+ child_packed_commit->generation = 1;
873
+ continue;
874
+ }
875
+
876
+ /*
877
+ * Add this current commit again so that it is visited
878
+ * again once all its children have been visited.
879
+ */
880
+ *(size_t *)git_array_alloc(index_stack) = i;
881
+ git_array_foreach (child_packed_commit->parent_indices, j, parent_idx) {
882
+ if (commit_states[*parent_idx]
883
+ != GENERATION_NUMBER_COMMIT_STATE_UNVISITED) {
884
+ /* This commit has already been considered. */
885
+ continue;
886
+ }
887
+
888
+ commit_states[*parent_idx] = GENERATION_NUMBER_COMMIT_STATE_ADDED;
889
+ *(size_t *)git_array_alloc(index_stack) = *parent_idx;
890
+ }
891
+ commit_states[i] = GENERATION_NUMBER_COMMIT_STATE_EXPANDED;
892
+ }
893
+
894
+ cleanup:
895
+ git_oidmap_free(packed_commit_map);
896
+ git__free(commit_states);
897
+ git_array_clear(index_stack);
898
+
899
+ return error;
900
+ }
901
+
902
+ static int write_offset(off64_t offset, commit_graph_write_cb write_cb, void *cb_data)
903
+ {
904
+ int error;
905
+ uint32_t word;
906
+
907
+ word = htonl((uint32_t)((offset >> 32) & 0xffffffffu));
908
+ error = write_cb((const char *)&word, sizeof(word), cb_data);
909
+ if (error < 0)
910
+ return error;
911
+ word = htonl((uint32_t)((offset >> 0) & 0xffffffffu));
912
+ error = write_cb((const char *)&word, sizeof(word), cb_data);
913
+ if (error < 0)
914
+ return error;
915
+
916
+ return 0;
917
+ }
918
+
919
+ static int write_chunk_header(
920
+ int chunk_id,
921
+ off64_t offset,
922
+ commit_graph_write_cb write_cb,
923
+ void *cb_data)
924
+ {
925
+ uint32_t word = htonl(chunk_id);
926
+ int error = write_cb((const char *)&word, sizeof(word), cb_data);
927
+ if (error < 0)
928
+ return error;
929
+ return write_offset(offset, write_cb, cb_data);
930
+ }
931
+
932
+ static int commit_graph_write_buf(const char *buf, size_t size, void *data)
933
+ {
934
+ git_buf *b = (git_buf *)data;
935
+ return git_buf_put(b, buf, size);
936
+ }
937
+
938
+ struct commit_graph_write_hash_context {
939
+ commit_graph_write_cb write_cb;
940
+ void *cb_data;
941
+ git_hash_ctx *ctx;
942
+ };
943
+
944
+ static int commit_graph_write_hash(const char *buf, size_t size, void *data)
945
+ {
946
+ struct commit_graph_write_hash_context *ctx = data;
947
+ int error;
948
+
949
+ error = git_hash_update(ctx->ctx, buf, size);
950
+ if (error < 0)
951
+ return error;
952
+
953
+ return ctx->write_cb(buf, size, ctx->cb_data);
954
+ }
955
+
956
+ static void packed_commit_free_dup(void *packed_commit)
957
+ {
958
+ packed_commit_free(packed_commit);
959
+ }
960
+
961
+ static int commit_graph_write(
962
+ git_commit_graph_writer *w,
963
+ commit_graph_write_cb write_cb,
964
+ void *cb_data)
965
+ {
966
+ int error = 0;
967
+ size_t i;
968
+ struct packed_commit *packed_commit;
969
+ struct git_commit_graph_header hdr = {0};
970
+ uint32_t oid_fanout_count;
971
+ uint32_t extra_edge_list_count;
972
+ uint32_t oid_fanout[256];
973
+ off64_t offset;
974
+ git_buf oid_lookup = GIT_BUF_INIT, commit_data = GIT_BUF_INIT,
975
+ extra_edge_list = GIT_BUF_INIT;
976
+ git_oid cgraph_checksum = {{0}};
977
+ git_hash_ctx ctx;
978
+ struct commit_graph_write_hash_context hash_cb_data = {0};
979
+
980
+ hdr.signature = htonl(COMMIT_GRAPH_SIGNATURE);
981
+ hdr.version = COMMIT_GRAPH_VERSION;
982
+ hdr.object_id_version = COMMIT_GRAPH_OBJECT_ID_VERSION;
983
+ hdr.chunks = 0;
984
+ hdr.base_graph_files = 0;
985
+ hash_cb_data.write_cb = write_cb;
986
+ hash_cb_data.cb_data = cb_data;
987
+ hash_cb_data.ctx = &ctx;
988
+
989
+ error = git_hash_ctx_init(&ctx);
990
+ if (error < 0)
991
+ return error;
992
+ cb_data = &hash_cb_data;
993
+ write_cb = commit_graph_write_hash;
994
+
995
+ /* Sort the commits. */
996
+ git_vector_sort(&w->commits);
997
+ git_vector_uniq(&w->commits, packed_commit_free_dup);
998
+ error = compute_generation_numbers(&w->commits);
999
+ if (error < 0)
1000
+ goto cleanup;
1001
+
1002
+ /* Fill the OID Fanout table. */
1003
+ oid_fanout_count = 0;
1004
+ for (i = 0; i < 256; i++) {
1005
+ while (oid_fanout_count < git_vector_length(&w->commits) &&
1006
+ (packed_commit = (struct packed_commit *)git_vector_get(&w->commits, oid_fanout_count)) &&
1007
+ packed_commit->sha1.id[0] <= i)
1008
+ ++oid_fanout_count;
1009
+ oid_fanout[i] = htonl(oid_fanout_count);
1010
+ }
1011
+
1012
+ /* Fill the OID Lookup table. */
1013
+ git_vector_foreach (&w->commits, i, packed_commit) {
1014
+ error = git_buf_put(&oid_lookup,
1015
+ (const char *)&packed_commit->sha1, sizeof(git_oid));
1016
+ if (error < 0)
1017
+ goto cleanup;
1018
+ }
1019
+
1020
+ /* Fill the Commit Data and Extra Edge List tables. */
1021
+ extra_edge_list_count = 0;
1022
+ git_vector_foreach (&w->commits, i, packed_commit) {
1023
+ uint64_t commit_time;
1024
+ uint32_t generation;
1025
+ uint32_t word;
1026
+ size_t *packed_index;
1027
+ unsigned int parentcount = (unsigned int)git_array_size(packed_commit->parents);
1028
+
1029
+ error = git_buf_put(&commit_data,
1030
+ (const char *)&packed_commit->tree_oid,
1031
+ sizeof(git_oid));
1032
+ if (error < 0)
1033
+ goto cleanup;
1034
+
1035
+ if (parentcount == 0) {
1036
+ word = htonl(GIT_COMMIT_GRAPH_MISSING_PARENT);
1037
+ } else {
1038
+ packed_index = git_array_get(packed_commit->parent_indices, 0);
1039
+ word = htonl((uint32_t)*packed_index);
1040
+ }
1041
+ error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
1042
+ if (error < 0)
1043
+ goto cleanup;
1044
+
1045
+ if (parentcount < 2) {
1046
+ word = htonl(GIT_COMMIT_GRAPH_MISSING_PARENT);
1047
+ } else if (parentcount == 2) {
1048
+ packed_index = git_array_get(packed_commit->parent_indices, 1);
1049
+ word = htonl((uint32_t)*packed_index);
1050
+ } else {
1051
+ word = htonl(0x80000000u | extra_edge_list_count);
1052
+ }
1053
+ error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
1054
+ if (error < 0)
1055
+ goto cleanup;
1056
+
1057
+ if (parentcount > 2) {
1058
+ unsigned int parent_i;
1059
+ for (parent_i = 1; parent_i < parentcount; ++parent_i) {
1060
+ packed_index = git_array_get(
1061
+ packed_commit->parent_indices, parent_i);
1062
+ word = htonl((uint32_t)(*packed_index | (parent_i + 1 == parentcount ? 0x80000000u : 0)));
1063
+
1064
+ error = git_buf_put(&extra_edge_list,
1065
+ (const char *)&word,
1066
+ sizeof(word));
1067
+ if (error < 0)
1068
+ goto cleanup;
1069
+ }
1070
+ extra_edge_list_count += parentcount - 1;
1071
+ }
1072
+
1073
+ generation = packed_commit->generation;
1074
+ commit_time = (uint64_t)packed_commit->commit_time;
1075
+ if (generation > GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX)
1076
+ generation = GIT_COMMIT_GRAPH_GENERATION_NUMBER_MAX;
1077
+ word = ntohl((uint32_t)((generation << 2) | ((commit_time >> 32ull) & 0x3ull)));
1078
+ error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
1079
+ if (error < 0)
1080
+ goto cleanup;
1081
+ word = ntohl((uint32_t)(commit_time & 0xffffffffull));
1082
+ error = git_buf_put(&commit_data, (const char *)&word, sizeof(word));
1083
+ if (error < 0)
1084
+ goto cleanup;
1085
+ }
1086
+
1087
+ /* Write the header. */
1088
+ hdr.chunks = 3;
1089
+ if (git_buf_len(&extra_edge_list) > 0)
1090
+ hdr.chunks++;
1091
+ error = write_cb((const char *)&hdr, sizeof(hdr), cb_data);
1092
+ if (error < 0)
1093
+ goto cleanup;
1094
+
1095
+ /* Write the chunk headers. */
1096
+ offset = sizeof(hdr) + (hdr.chunks + 1) * 12;
1097
+ error = write_chunk_header(COMMIT_GRAPH_OID_FANOUT_ID, offset, write_cb, cb_data);
1098
+ if (error < 0)
1099
+ goto cleanup;
1100
+ offset += sizeof(oid_fanout);
1101
+ error = write_chunk_header(COMMIT_GRAPH_OID_LOOKUP_ID, offset, write_cb, cb_data);
1102
+ if (error < 0)
1103
+ goto cleanup;
1104
+ offset += git_buf_len(&oid_lookup);
1105
+ error = write_chunk_header(COMMIT_GRAPH_COMMIT_DATA_ID, offset, write_cb, cb_data);
1106
+ if (error < 0)
1107
+ goto cleanup;
1108
+ offset += git_buf_len(&commit_data);
1109
+ if (git_buf_len(&extra_edge_list) > 0) {
1110
+ error = write_chunk_header(
1111
+ COMMIT_GRAPH_EXTRA_EDGE_LIST_ID, offset, write_cb, cb_data);
1112
+ if (error < 0)
1113
+ goto cleanup;
1114
+ offset += git_buf_len(&extra_edge_list);
1115
+ }
1116
+ error = write_chunk_header(0, offset, write_cb, cb_data);
1117
+ if (error < 0)
1118
+ goto cleanup;
1119
+
1120
+ /* Write all the chunks. */
1121
+ error = write_cb((const char *)oid_fanout, sizeof(oid_fanout), cb_data);
1122
+ if (error < 0)
1123
+ goto cleanup;
1124
+ error = write_cb(git_buf_cstr(&oid_lookup), git_buf_len(&oid_lookup), cb_data);
1125
+ if (error < 0)
1126
+ goto cleanup;
1127
+ error = write_cb(git_buf_cstr(&commit_data), git_buf_len(&commit_data), cb_data);
1128
+ if (error < 0)
1129
+ goto cleanup;
1130
+ error = write_cb(git_buf_cstr(&extra_edge_list), git_buf_len(&extra_edge_list), cb_data);
1131
+ if (error < 0)
1132
+ goto cleanup;
1133
+
1134
+ /* Finalize the checksum and write the trailer. */
1135
+ error = git_hash_final(&cgraph_checksum, &ctx);
1136
+ if (error < 0)
1137
+ goto cleanup;
1138
+ error = write_cb((const char *)&cgraph_checksum, sizeof(cgraph_checksum), cb_data);
1139
+ if (error < 0)
1140
+ goto cleanup;
1141
+
1142
+ cleanup:
1143
+ git_buf_dispose(&oid_lookup);
1144
+ git_buf_dispose(&commit_data);
1145
+ git_buf_dispose(&extra_edge_list);
1146
+ git_hash_ctx_cleanup(&ctx);
1147
+ return error;
1148
+ }
1149
+
1150
+ static int commit_graph_write_filebuf(const char *buf, size_t size, void *data)
1151
+ {
1152
+ git_filebuf *f = (git_filebuf *)data;
1153
+ return git_filebuf_write(f, buf, size);
1154
+ }
1155
+
1156
+ int git_commit_graph_writer_options_init(
1157
+ git_commit_graph_writer_options *opts,
1158
+ unsigned int version)
1159
+ {
1160
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1161
+ opts,
1162
+ version,
1163
+ git_commit_graph_writer_options,
1164
+ GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT);
1165
+ return 0;
1166
+ }
1167
+
1168
+ int git_commit_graph_writer_commit(
1169
+ git_commit_graph_writer *w,
1170
+ git_commit_graph_writer_options *opts)
1171
+ {
1172
+ int error;
1173
+ int filebuf_flags = GIT_FILEBUF_DO_NOT_BUFFER;
1174
+ git_buf commit_graph_path = GIT_BUF_INIT;
1175
+ git_filebuf output = GIT_FILEBUF_INIT;
1176
+
1177
+ /* TODO: support options and fill in defaults. */
1178
+ GIT_UNUSED(opts);
1179
+
1180
+ error = git_buf_joinpath(
1181
+ &commit_graph_path, git_buf_cstr(&w->objects_info_dir), "commit-graph");
1182
+ if (error < 0)
1183
+ return error;
1184
+
1185
+ if (git_repository__fsync_gitdir)
1186
+ filebuf_flags |= GIT_FILEBUF_FSYNC;
1187
+ error = git_filebuf_open(&output, git_buf_cstr(&commit_graph_path), filebuf_flags, 0644);
1188
+ git_buf_dispose(&commit_graph_path);
1189
+ if (error < 0)
1190
+ return error;
1191
+
1192
+ error = commit_graph_write(w, commit_graph_write_filebuf, &output);
1193
+ if (error < 0) {
1194
+ git_filebuf_cleanup(&output);
1195
+ return error;
1196
+ }
1197
+
1198
+ return git_filebuf_commit(&output);
1199
+ }
1200
+
1201
+ int git_commit_graph_writer_dump(
1202
+ git_buf *cgraph,
1203
+ git_commit_graph_writer *w,
1204
+ git_commit_graph_writer_options *opts)
1205
+ {
1206
+ /* TODO: support options. */
1207
+ GIT_UNUSED(opts);
1208
+ return commit_graph_write(w, commit_graph_write_buf, cgraph);
1209
+ }