rugged 0.1.2 → 0.16.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (277) hide show
  1. data/README.md +25 -36
  2. data/Rakefile +20 -98
  3. data/ext/rugged/extconf.rb +44 -4
  4. data/ext/rugged/remote.c +215 -0
  5. data/ext/rugged/rugged.c +171 -0
  6. data/ext/rugged/rugged.h +126 -0
  7. data/ext/rugged/rugged_blob.c +99 -0
  8. data/ext/rugged/rugged_commit.c +224 -0
  9. data/ext/rugged/rugged_config.c +238 -0
  10. data/ext/rugged/rugged_index.c +440 -0
  11. data/ext/rugged/rugged_object.c +203 -0
  12. data/ext/rugged/rugged_reference.c +401 -0
  13. data/ext/rugged/rugged_repo.c +482 -0
  14. data/ext/rugged/rugged_revwalk.c +138 -0
  15. data/ext/rugged/rugged_signature.c +80 -0
  16. data/ext/rugged/rugged_tag.c +216 -0
  17. data/ext/rugged/rugged_tree.c +322 -0
  18. data/ext/rugged/vendor/libgit2-dist.tar.gz +0 -0
  19. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.c +1778 -0
  20. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.h +267 -0
  21. data/ext/rugged/vendor/libgit2-dist/deps/zlib/adler32.c +169 -0
  22. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.c +442 -0
  23. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.h +441 -0
  24. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.c +1834 -0
  25. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.h +342 -0
  26. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.c +340 -0
  27. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.h +11 -0
  28. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffixed.h +94 -0
  29. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.c +1480 -0
  30. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.h +122 -0
  31. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.c +330 -0
  32. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.h +62 -0
  33. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.c +1244 -0
  34. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.h +128 -0
  35. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zconf.h +54 -0
  36. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zlib.h +1613 -0
  37. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.c +318 -0
  38. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.h +274 -0
  39. data/ext/rugged/vendor/libgit2-dist/examples/general.c +451 -0
  40. data/ext/rugged/vendor/libgit2-dist/examples/network/common.h +14 -0
  41. data/ext/rugged/vendor/libgit2-dist/examples/network/fetch.c +97 -0
  42. data/ext/rugged/vendor/libgit2-dist/examples/network/git2.c +58 -0
  43. data/ext/rugged/vendor/libgit2-dist/examples/network/index-pack.c +47 -0
  44. data/ext/rugged/vendor/libgit2-dist/examples/network/ls-remote.c +76 -0
  45. data/ext/rugged/vendor/libgit2-dist/examples/showindex.c +43 -0
  46. data/ext/rugged/vendor/libgit2-dist/include/git2.h +44 -0
  47. data/ext/rugged/vendor/libgit2-dist/include/git2/blob.h +120 -0
  48. data/ext/rugged/vendor/libgit2-dist/include/git2/branch.h +15 -0
  49. data/ext/rugged/vendor/libgit2-dist/include/git2/commit.h +263 -0
  50. data/ext/rugged/vendor/libgit2-dist/include/git2/common.h +103 -0
  51. data/ext/rugged/vendor/libgit2-dist/include/git2/config.h +278 -0
  52. data/ext/rugged/vendor/libgit2-dist/include/git2/errors.h +144 -0
  53. data/ext/rugged/vendor/libgit2-dist/include/git2/index.h +306 -0
  54. data/ext/rugged/vendor/libgit2-dist/include/git2/indexer.h +76 -0
  55. data/ext/rugged/vendor/libgit2-dist/include/git2/inttypes.h +305 -0
  56. data/ext/rugged/vendor/libgit2-dist/include/git2/net.h +51 -0
  57. data/ext/rugged/vendor/libgit2-dist/include/git2/object.h +173 -0
  58. data/ext/rugged/vendor/libgit2-dist/include/git2/odb.h +331 -0
  59. data/ext/rugged/vendor/libgit2-dist/include/git2/odb_backend.h +100 -0
  60. data/ext/rugged/vendor/libgit2-dist/include/git2/oid.h +218 -0
  61. data/ext/rugged/vendor/libgit2-dist/include/git2/reflog.h +128 -0
  62. data/ext/rugged/vendor/libgit2-dist/include/git2/refs.h +309 -0
  63. data/ext/rugged/vendor/libgit2-dist/include/git2/refspec.h +60 -0
  64. data/ext/rugged/vendor/libgit2-dist/include/git2/remote.h +176 -0
  65. data/ext/rugged/vendor/libgit2-dist/include/git2/repository.h +290 -0
  66. data/ext/rugged/vendor/libgit2-dist/include/git2/revwalk.h +169 -0
  67. data/ext/rugged/vendor/libgit2-dist/include/git2/signature.h +65 -0
  68. data/ext/rugged/vendor/libgit2-dist/include/git2/status.h +63 -0
  69. data/ext/rugged/vendor/libgit2-dist/include/git2/stdint.h +247 -0
  70. data/ext/rugged/vendor/libgit2-dist/include/git2/tag.h +279 -0
  71. data/ext/rugged/vendor/libgit2-dist/include/git2/threads.h +48 -0
  72. data/ext/rugged/vendor/libgit2-dist/include/git2/tree.h +318 -0
  73. data/ext/rugged/vendor/libgit2-dist/include/git2/types.h +169 -0
  74. data/ext/rugged/vendor/libgit2-dist/include/git2/version.h +15 -0
  75. data/ext/rugged/vendor/libgit2-dist/include/git2/windows.h +59 -0
  76. data/ext/rugged/vendor/libgit2-dist/include/git2/zlib.h +40 -0
  77. data/ext/rugged/vendor/libgit2-dist/src/blob.c +135 -0
  78. data/ext/rugged/vendor/libgit2-dist/src/blob.h +23 -0
  79. data/ext/rugged/vendor/libgit2-dist/src/bswap.h +97 -0
  80. data/ext/rugged/vendor/libgit2-dist/src/buffer.c +113 -0
  81. data/ext/rugged/vendor/libgit2-dist/src/buffer.h +32 -0
  82. data/ext/rugged/vendor/libgit2-dist/src/cache.c +111 -0
  83. data/ext/rugged/vendor/libgit2-dist/src/cache.h +64 -0
  84. data/ext/rugged/vendor/libgit2-dist/src/cc-compat.h +67 -0
  85. data/ext/rugged/vendor/libgit2-dist/src/commit.c +299 -0
  86. data/ext/rugged/vendor/libgit2-dist/src/commit.h +34 -0
  87. data/ext/rugged/vendor/libgit2-dist/src/common.h +64 -0
  88. data/ext/rugged/vendor/libgit2-dist/src/config.c +418 -0
  89. data/ext/rugged/vendor/libgit2-dist/src/config.h +24 -0
  90. data/ext/rugged/vendor/libgit2-dist/src/config_file.c +1210 -0
  91. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.c +115 -0
  92. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.h +33 -0
  93. data/ext/rugged/vendor/libgit2-dist/src/dir.h +47 -0
  94. data/ext/rugged/vendor/libgit2-dist/src/errors.c +104 -0
  95. data/ext/rugged/vendor/libgit2-dist/src/fetch.c +172 -0
  96. data/ext/rugged/vendor/libgit2-dist/src/fetch.h +18 -0
  97. data/ext/rugged/vendor/libgit2-dist/src/filebuf.c +400 -0
  98. data/ext/rugged/vendor/libgit2-dist/src/filebuf.h +72 -0
  99. data/ext/rugged/vendor/libgit2-dist/src/fileops.c +358 -0
  100. data/ext/rugged/vendor/libgit2-dist/src/fileops.h +151 -0
  101. data/ext/rugged/vendor/libgit2-dist/src/global.c +134 -0
  102. data/ext/rugged/vendor/libgit2-dist/src/global.h +24 -0
  103. data/ext/rugged/vendor/libgit2-dist/src/hash.c +74 -0
  104. data/ext/rugged/vendor/libgit2-dist/src/hash.h +29 -0
  105. data/ext/rugged/vendor/libgit2-dist/src/hashtable.c +243 -0
  106. data/ext/rugged/vendor/libgit2-dist/src/hashtable.h +80 -0
  107. data/ext/rugged/vendor/libgit2-dist/src/index.c +918 -0
  108. data/ext/rugged/vendor/libgit2-dist/src/index.h +34 -0
  109. data/ext/rugged/vendor/libgit2-dist/src/indexer.c +401 -0
  110. data/ext/rugged/vendor/libgit2-dist/src/map.h +37 -0
  111. data/ext/rugged/vendor/libgit2-dist/src/mwindow.c +272 -0
  112. data/ext/rugged/vendor/libgit2-dist/src/mwindow.h +45 -0
  113. data/ext/rugged/vendor/libgit2-dist/src/netops.c +198 -0
  114. data/ext/rugged/vendor/libgit2-dist/src/netops.h +36 -0
  115. data/ext/rugged/vendor/libgit2-dist/src/object.c +295 -0
  116. data/ext/rugged/vendor/libgit2-dist/src/odb.c +672 -0
  117. data/ext/rugged/vendor/libgit2-dist/src/odb.h +43 -0
  118. data/ext/rugged/vendor/libgit2-dist/src/odb_loose.c +855 -0
  119. data/ext/rugged/vendor/libgit2-dist/src/odb_pack.c +485 -0
  120. data/ext/rugged/vendor/libgit2-dist/src/oid.c +388 -0
  121. data/ext/rugged/vendor/libgit2-dist/src/pack.c +788 -0
  122. data/ext/rugged/vendor/libgit2-dist/src/pack.h +99 -0
  123. data/ext/rugged/vendor/libgit2-dist/src/path.c +270 -0
  124. data/ext/rugged/vendor/libgit2-dist/src/path.h +84 -0
  125. data/ext/rugged/vendor/libgit2-dist/src/pkt.c +426 -0
  126. data/ext/rugged/vendor/libgit2-dist/src/pkt.h +77 -0
  127. data/ext/rugged/vendor/libgit2-dist/src/posix.c +94 -0
  128. data/ext/rugged/vendor/libgit2-dist/src/posix.h +69 -0
  129. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.c +70 -0
  130. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.h +26 -0
  131. data/ext/rugged/vendor/libgit2-dist/src/pqueue.c +141 -0
  132. data/ext/rugged/vendor/libgit2-dist/src/pqueue.h +81 -0
  133. data/ext/rugged/vendor/libgit2-dist/src/protocol.c +50 -0
  134. data/ext/rugged/vendor/libgit2-dist/src/protocol.h +23 -0
  135. data/ext/rugged/vendor/libgit2-dist/src/reflog.c +318 -0
  136. data/ext/rugged/vendor/libgit2-dist/src/reflog.h +34 -0
  137. data/ext/rugged/vendor/libgit2-dist/src/refs.c +1693 -0
  138. data/ext/rugged/vendor/libgit2-dist/src/refs.h +58 -0
  139. data/ext/rugged/vendor/libgit2-dist/src/refspec.c +95 -0
  140. data/ext/rugged/vendor/libgit2-dist/src/refspec.h +23 -0
  141. data/ext/rugged/vendor/libgit2-dist/src/remote.c +339 -0
  142. data/ext/rugged/vendor/libgit2-dist/src/remote.h +25 -0
  143. data/ext/rugged/vendor/libgit2-dist/src/repository.c +849 -0
  144. data/ext/rugged/vendor/libgit2-dist/src/repository.h +60 -0
  145. data/ext/rugged/vendor/libgit2-dist/src/revwalk.c +569 -0
  146. data/ext/rugged/vendor/libgit2-dist/src/sha1.c +280 -0
  147. data/ext/rugged/vendor/libgit2-dist/src/sha1.h +21 -0
  148. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.c +177 -0
  149. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.h +18 -0
  150. data/ext/rugged/vendor/libgit2-dist/src/signature.c +335 -0
  151. data/ext/rugged/vendor/libgit2-dist/src/signature.h +18 -0
  152. data/ext/rugged/vendor/libgit2-dist/src/status.c +696 -0
  153. data/ext/rugged/vendor/libgit2-dist/src/tag.c +446 -0
  154. data/ext/rugged/vendor/libgit2-dist/src/tag.h +28 -0
  155. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.c +55 -0
  156. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.h +108 -0
  157. data/ext/rugged/vendor/libgit2-dist/src/transport.c +85 -0
  158. data/ext/rugged/vendor/libgit2-dist/src/transport.h +110 -0
  159. data/ext/rugged/vendor/libgit2-dist/src/transports/git.c +502 -0
  160. data/ext/rugged/vendor/libgit2-dist/src/transports/http.c +756 -0
  161. data/ext/rugged/vendor/libgit2-dist/src/transports/local.c +235 -0
  162. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.c +201 -0
  163. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.h +31 -0
  164. data/ext/rugged/vendor/libgit2-dist/src/tree.c +758 -0
  165. data/ext/rugged/vendor/libgit2-dist/src/tree.h +37 -0
  166. data/ext/rugged/vendor/libgit2-dist/src/tsort.c +365 -0
  167. data/ext/rugged/vendor/libgit2-dist/src/unix/map.c +70 -0
  168. data/ext/rugged/vendor/libgit2-dist/src/unix/posix.h +25 -0
  169. data/ext/rugged/vendor/libgit2-dist/src/util.c +381 -0
  170. data/ext/rugged/vendor/libgit2-dist/src/util.h +137 -0
  171. data/ext/rugged/vendor/libgit2-dist/src/vector.c +174 -0
  172. data/ext/rugged/vendor/libgit2-dist/src/vector.h +45 -0
  173. data/ext/rugged/vendor/libgit2-dist/src/win32/dir.c +115 -0
  174. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.c +180 -0
  175. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.h +27 -0
  176. data/ext/rugged/vendor/libgit2-dist/src/win32/map.c +131 -0
  177. data/ext/rugged/vendor/libgit2-dist/src/win32/mingw-compat.h +24 -0
  178. data/ext/rugged/vendor/libgit2-dist/src/win32/msvc-compat.h +38 -0
  179. data/ext/rugged/vendor/libgit2-dist/src/win32/posix.h +53 -0
  180. data/ext/rugged/vendor/libgit2-dist/src/win32/posix_w32.c +404 -0
  181. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.c +65 -0
  182. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.h +40 -0
  183. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.c +88 -0
  184. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.h +17 -0
  185. data/ext/rugged/vendor/libgit2-dist/tests-clay/buf/basic.c +29 -0
  186. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay.h +187 -0
  187. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_libgit2.h +28 -0
  188. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_main.c +1073 -0
  189. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/add.c +37 -0
  190. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/new.c +36 -0
  191. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/read.c +209 -0
  192. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/stress.c +39 -0
  193. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/write.c +77 -0
  194. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/dirent.c +222 -0
  195. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/filebuf.c +106 -0
  196. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/oid.c +18 -0
  197. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/path.c +139 -0
  198. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/rmdir.c +50 -0
  199. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/string.c +28 -0
  200. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/strtol.c +37 -0
  201. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/vector.c +66 -0
  202. data/ext/rugged/vendor/libgit2-dist/tests-clay/index/rename.c +60 -0
  203. data/ext/rugged/vendor/libgit2-dist/tests-clay/network/remotes.c +50 -0
  204. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/chars.c +52 -0
  205. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/compare.c +124 -0
  206. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/convert.c +75 -0
  207. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/data.h +323 -0
  208. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/fromstr.c +30 -0
  209. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/hash.c +162 -0
  210. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/short.c +94 -0
  211. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/size.c +13 -0
  212. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/type2string.c +54 -0
  213. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/tree/frompath.c +75 -0
  214. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose.c +84 -0
  215. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose_data.h +522 -0
  216. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/pack_data.h +151 -0
  217. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/packed.c +78 -0
  218. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/sorting.c +71 -0
  219. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/getters.c +68 -0
  220. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/init.c +104 -0
  221. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/open.c +54 -0
  222. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/single.c +38 -0
  223. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/status_data.h +48 -0
  224. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/worktree.c +124 -0
  225. data/ext/rugged/vendor/libgit2-dist/tests/t00-core.c +628 -0
  226. data/ext/rugged/vendor/libgit2-dist/tests/t01-data.h +322 -0
  227. data/ext/rugged/vendor/libgit2-dist/tests/t01-rawobj.c +638 -0
  228. data/ext/rugged/vendor/libgit2-dist/tests/t03-data.h +344 -0
  229. data/ext/rugged/vendor/libgit2-dist/tests/t03-objwrite.c +255 -0
  230. data/ext/rugged/vendor/libgit2-dist/tests/t04-commit.c +788 -0
  231. data/ext/rugged/vendor/libgit2-dist/tests/t05-revwalk.c +140 -0
  232. data/ext/rugged/vendor/libgit2-dist/tests/t06-index.c +219 -0
  233. data/ext/rugged/vendor/libgit2-dist/tests/t07-hashtable.c +192 -0
  234. data/ext/rugged/vendor/libgit2-dist/tests/t08-tag.c +357 -0
  235. data/ext/rugged/vendor/libgit2-dist/tests/t09-tree.c +221 -0
  236. data/ext/rugged/vendor/libgit2-dist/tests/t10-refs.c +1294 -0
  237. data/ext/rugged/vendor/libgit2-dist/tests/t12-repo.c +174 -0
  238. data/ext/rugged/vendor/libgit2-dist/tests/t13-threads.c +41 -0
  239. data/ext/rugged/vendor/libgit2-dist/tests/t17-bufs.c +61 -0
  240. data/ext/rugged/vendor/libgit2-dist/tests/t18-status.c +448 -0
  241. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.c +310 -0
  242. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.h +83 -0
  243. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.c +198 -0
  244. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.h +54 -0
  245. data/ext/rugged/vendor/libgit2-dist/tests/test_main.c +89 -0
  246. data/lib/rugged.rb +4 -3
  247. data/lib/rugged/index.rb +0 -8
  248. data/lib/rugged/objects.rb +45 -0
  249. data/lib/rugged/repository.rb +29 -0
  250. data/lib/rugged/tree.rb +16 -6
  251. data/lib/rugged/version.rb +1 -1
  252. data/lib/rugged/walker.rb +5 -0
  253. data/test/blob_test.rb +18 -14
  254. data/test/commit_test.rb +28 -26
  255. data/test/coverage/HEAD.json +1 -0
  256. data/test/coverage/cover.rb +106 -0
  257. data/test/fixtures/testrepo.git/refs/heads/new_name +1 -0
  258. data/test/index_test.rb +101 -78
  259. data/test/lib_test.rb +4 -4
  260. data/test/object_test.rb +3 -3
  261. data/test/reference_test.rb +75 -0
  262. data/test/remote_test.rb +19 -0
  263. data/test/repo_pack_test.rb +4 -4
  264. data/test/repo_test.rb +44 -15
  265. data/test/tag_test.rb +7 -17
  266. data/test/test_helper.rb +24 -5
  267. data/test/tree_test.rb +30 -12
  268. data/test/walker_test.rb +40 -31
  269. metadata +273 -50
  270. data/lib/rugged/person.rb +0 -20
  271. data/lib/rugged/tree_entry.rb +0 -9
  272. data/test/fixtures/testrepo.git/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae +0 -0
  273. data/test/fixtures/testrepo.git/objects/2f/3321418db5b2a841375b8b70880a8ab5a4148f +0 -0
  274. data/test/fixtures/testrepo.git/objects/36/9b00a7700cca3a506d79e301d6ad8bf735d9ee +0 -3
  275. data/test/fixtures/testrepo.git/objects/3d/b1b5ceace59ff65279757003763046fd4cbbe6 +0 -0
  276. data/test/fixtures/testrepo.git/objects/4c/d1604907792e2c43e03dcec1216f99d63e68c4 +0 -3
  277. data/test/fixtures/testrepo.git/objects/e0/f46d77041c149296549b01ed4a18b02c4b7400 +0 -0
@@ -0,0 +1,388 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
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 "common.h"
9
+ #include "git2/oid.h"
10
+ #include "repository.h"
11
+ #include <string.h>
12
+ #include <limits.h>
13
+
14
+ static signed char from_hex[] = {
15
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
16
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
17
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */
18
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */
19
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */
20
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */
21
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */
22
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */
23
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
24
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
25
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */
26
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */
27
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */
28
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */
29
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */
30
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */
31
+ };
32
+ static char to_hex[] = "0123456789abcdef";
33
+
34
+ int git_oid_fromstrn(git_oid *out, const char *str, size_t length)
35
+ {
36
+ size_t p;
37
+ int v;
38
+
39
+ if (length < 4)
40
+ return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is too short");
41
+
42
+ if (length > GIT_OID_HEXSZ)
43
+ length = GIT_OID_HEXSZ;
44
+
45
+ for (p = 0; p < length - 1; p += 2) {
46
+ v = (from_hex[(unsigned char)str[p + 0]] << 4)
47
+ | from_hex[(unsigned char)str[p + 1]];
48
+
49
+ if (v < 0)
50
+ return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is not a valid sha1 hash");
51
+
52
+ out->id[p / 2] = (unsigned char)v;
53
+ }
54
+
55
+ if (length % 2) {
56
+ v = (from_hex[(unsigned char)str[p + 0]] << 4);
57
+ if (v < 0)
58
+ return git__throw(GIT_ENOTOID, "Failed to generate sha1. Given string is not a valid sha1 hash");
59
+
60
+ out->id[p / 2] = (unsigned char)v;
61
+ p += 2;
62
+ }
63
+
64
+ memset(out->id + p / 2, 0, (GIT_OID_HEXSZ - p) / 2);
65
+
66
+ return GIT_SUCCESS;
67
+ }
68
+
69
+ int git_oid_fromstr(git_oid *out, const char *str)
70
+ {
71
+ return git_oid_fromstrn(out, str, GIT_OID_HEXSZ);
72
+ }
73
+
74
+ GIT_INLINE(char) *fmt_one(char *str, unsigned int val)
75
+ {
76
+ *str++ = to_hex[val >> 4];
77
+ *str++ = to_hex[val & 0xf];
78
+ return str;
79
+ }
80
+
81
+ void git_oid_fmt(char *str, const git_oid *oid)
82
+ {
83
+ size_t i;
84
+
85
+ for (i = 0; i < sizeof(oid->id); i++)
86
+ str = fmt_one(str, oid->id[i]);
87
+ }
88
+
89
+ void git_oid_pathfmt(char *str, const git_oid *oid)
90
+ {
91
+ size_t i;
92
+
93
+ str = fmt_one(str, oid->id[0]);
94
+ *str++ = '/';
95
+ for (i = 1; i < sizeof(oid->id); i++)
96
+ str = fmt_one(str, oid->id[i]);
97
+ }
98
+
99
+ char *git_oid_allocfmt(const git_oid *oid)
100
+ {
101
+ char *str = git__malloc(GIT_OID_HEXSZ + 1);
102
+ if (!str)
103
+ return NULL;
104
+ git_oid_fmt(str, oid);
105
+ str[GIT_OID_HEXSZ] = '\0';
106
+ return str;
107
+ }
108
+
109
+ char *git_oid_to_string(char *out, size_t n, const git_oid *oid)
110
+ {
111
+ char str[GIT_OID_HEXSZ];
112
+
113
+ if (!out || n == 0 || !oid)
114
+ return "";
115
+
116
+ n--; /* allow room for terminating NUL */
117
+
118
+ if (n > 0) {
119
+ git_oid_fmt(str, oid);
120
+ if (n > GIT_OID_HEXSZ)
121
+ n = GIT_OID_HEXSZ;
122
+ memcpy(out, str, n);
123
+ }
124
+
125
+ out[n] = '\0';
126
+
127
+ return out;
128
+ }
129
+
130
+ int git_oid__parse(git_oid *oid, const char **buffer_out,
131
+ const char *buffer_end, const char *header)
132
+ {
133
+ const size_t sha_len = GIT_OID_HEXSZ;
134
+ const size_t header_len = strlen(header);
135
+
136
+ const char *buffer = *buffer_out;
137
+
138
+ if (buffer + (header_len + sha_len + 1) > buffer_end)
139
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse OID. Buffer too small");
140
+
141
+ if (memcmp(buffer, header, header_len) != 0)
142
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse OID. Buffer and header do not match");
143
+
144
+ if (buffer[header_len + sha_len] != '\n')
145
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse OID. Buffer not terminated correctly");
146
+
147
+ if (git_oid_fromstr(oid, buffer + header_len) < GIT_SUCCESS)
148
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to parse OID. Failed to generate sha1");
149
+
150
+ *buffer_out = buffer + (header_len + sha_len + 1);
151
+
152
+ return GIT_SUCCESS;
153
+ }
154
+
155
+ void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid)
156
+ {
157
+ char hex_oid[GIT_OID_HEXSZ];
158
+
159
+ git_oid_fmt(hex_oid, oid);
160
+ git_buf_puts(buf, header);
161
+ git_buf_put(buf, hex_oid, GIT_OID_HEXSZ);
162
+ git_buf_putc(buf, '\n');
163
+ }
164
+
165
+ void git_oid_fromraw(git_oid *out, const unsigned char *raw)
166
+ {
167
+ memcpy(out->id, raw, sizeof(out->id));
168
+ }
169
+
170
+ void git_oid_cpy(git_oid *out, const git_oid *src)
171
+ {
172
+ memcpy(out->id, src->id, sizeof(out->id));
173
+ }
174
+
175
+ int git_oid_cmp(const git_oid *a, const git_oid *b)
176
+ {
177
+ return memcmp(a->id, b->id, sizeof(a->id));
178
+ }
179
+
180
+ int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, unsigned int len)
181
+ {
182
+ const unsigned char *a = oid_a->id;
183
+ const unsigned char *b = oid_b->id;
184
+
185
+ do {
186
+ if (*a != *b)
187
+ return 1;
188
+ a++;
189
+ b++;
190
+ len -= 2;
191
+ } while (len > 1);
192
+
193
+ if (len)
194
+ if ((*a ^ *b) & 0xf0)
195
+ return 1;
196
+
197
+ return 0;
198
+ }
199
+
200
+ int git_oid_streq(const git_oid *a, const char *str)
201
+ {
202
+ git_oid id;
203
+ int error;
204
+
205
+ if ((error = git_oid_fromstr(&id, str)) < GIT_SUCCESS)
206
+ return git__rethrow(error, "Failed to convert '%s' to oid.", str);
207
+
208
+ return git_oid_cmp(a, &id) == 0 ? GIT_SUCCESS : GIT_ERROR;
209
+ }
210
+
211
+ typedef short node_index;
212
+
213
+ typedef union {
214
+ const char *tail;
215
+ node_index children[16];
216
+ } trie_node;
217
+
218
+ struct git_oid_shorten {
219
+ trie_node *nodes;
220
+ size_t node_count, size;
221
+ int min_length, full;
222
+ };
223
+
224
+ static int resize_trie(git_oid_shorten *self, size_t new_size)
225
+ {
226
+ self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node));
227
+ if (self->nodes == NULL)
228
+ return GIT_ENOMEM;
229
+
230
+ if (new_size > self->size) {
231
+ memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(trie_node));
232
+ }
233
+
234
+ self->size = new_size;
235
+ return GIT_SUCCESS;
236
+ }
237
+
238
+ static trie_node *push_leaf(git_oid_shorten *os, node_index idx, int push_at, const char *oid)
239
+ {
240
+ trie_node *node, *leaf;
241
+ node_index idx_leaf;
242
+
243
+ if (os->node_count >= os->size) {
244
+ if (resize_trie(os, os->size * 2) < GIT_SUCCESS)
245
+ return NULL;
246
+ }
247
+
248
+ idx_leaf = (node_index)os->node_count++;
249
+
250
+ if (os->node_count == SHRT_MAX)
251
+ os->full = 1;
252
+
253
+ node = &os->nodes[idx];
254
+ node->children[push_at] = -idx_leaf;
255
+
256
+ leaf = &os->nodes[idx_leaf];
257
+ leaf->tail = oid;
258
+
259
+ return node;
260
+ }
261
+
262
+ git_oid_shorten *git_oid_shorten_new(size_t min_length)
263
+ {
264
+ git_oid_shorten *os;
265
+
266
+ os = git__malloc(sizeof(git_oid_shorten));
267
+ if (os == NULL)
268
+ return NULL;
269
+
270
+ memset(os, 0x0, sizeof(git_oid_shorten));
271
+
272
+ if (resize_trie(os, 16) < GIT_SUCCESS) {
273
+ git__free(os);
274
+ return NULL;
275
+ }
276
+
277
+ os->node_count = 1;
278
+ os->min_length = min_length;
279
+
280
+ return os;
281
+ }
282
+
283
+ void git_oid_shorten_free(git_oid_shorten *os)
284
+ {
285
+ git__free(os->nodes);
286
+ git__free(os);
287
+ }
288
+
289
+
290
+ /*
291
+ * What wizardry is this?
292
+ *
293
+ * This is just a memory-optimized trie: basically a very fancy
294
+ * 16-ary tree, which is used to store the prefixes of the OID
295
+ * strings.
296
+ *
297
+ * Read more: http://en.wikipedia.org/wiki/Trie
298
+ *
299
+ * Magic that happens in this method:
300
+ *
301
+ * - Each node in the trie is an union, so it can work both as
302
+ * a normal node, or as a leaf.
303
+ *
304
+ * - Each normal node points to 16 children (one for each possible
305
+ * character in the oid). This is *not* stored in an array of
306
+ * pointers, because in a 64-bit arch this would be sucking
307
+ * 16*sizeof(void*) = 128 bytes of memory per node, which is fucking
308
+ * insane. What we do is store Node Indexes, and use these indexes
309
+ * to look up each node in the om->index array. These indexes are
310
+ * signed shorts, so this limits the amount of unique OIDs that
311
+ * fit in the structure to about 20000 (assuming a more or less uniform
312
+ * distribution).
313
+ *
314
+ * - All the nodes in om->index array are stored contiguously in
315
+ * memory, and each of them is 32 bytes, so we fit 2x nodes per
316
+ * cache line. Convenient for speed.
317
+ *
318
+ * - To differentiate the leafs from the normal nodes, we store all
319
+ * the indexes towards a leaf as a negative index (indexes to normal
320
+ * nodes are positives). When we find that one of the children for
321
+ * a node has a negative value, that means it's going to be a leaf.
322
+ * This reduces the amount of indexes we have by two, but also reduces
323
+ * the size of each node by 1-4 bytes (the amount we would need to
324
+ * add a `is_leaf` field): this is good because it allows the nodes
325
+ * to fit cleanly in cache lines.
326
+ *
327
+ * - Once we reach an empty children, instead of continuing to insert
328
+ * new nodes for each remaining character of the OID, we store a pointer
329
+ * to the tail in the leaf; if the leaf is reached again, we turn it
330
+ * into a normal node and use the tail to create a new leaf.
331
+ *
332
+ * This is a pretty good balance between performance and memory usage.
333
+ */
334
+ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid)
335
+ {
336
+ int i, is_leaf;
337
+ node_index idx;
338
+
339
+ if (os->full)
340
+ return GIT_ENOMEM;
341
+
342
+ if (text_oid == NULL)
343
+ return os->min_length;
344
+
345
+ idx = 0;
346
+ is_leaf = 0;
347
+
348
+ for (i = 0; i < GIT_OID_HEXSZ; ++i) {
349
+ int c = from_hex[(int)text_oid[i]];
350
+ trie_node *node;
351
+
352
+ if (c == -1)
353
+ return git__throw(GIT_ENOTOID, "Failed to shorten OID. Invalid hex value");
354
+
355
+ node = &os->nodes[idx];
356
+
357
+ if (is_leaf) {
358
+ const char *tail;
359
+
360
+ tail = node->tail;
361
+ node->tail = NULL;
362
+
363
+ node = push_leaf(os, idx, from_hex[(int)tail[0]], &tail[1]);
364
+ if (node == NULL)
365
+ return GIT_ENOMEM;
366
+ }
367
+
368
+ if (node->children[c] == 0) {
369
+ if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL)
370
+ return GIT_ENOMEM;
371
+ break;
372
+ }
373
+
374
+ idx = node->children[c];
375
+ is_leaf = 0;
376
+
377
+ if (idx < 0) {
378
+ node->children[c] = idx = -idx;
379
+ is_leaf = 1;
380
+ }
381
+ }
382
+
383
+ if (++i > os->min_length)
384
+ os->min_length = i;
385
+
386
+ return os->min_length;
387
+ }
388
+
@@ -0,0 +1,788 @@
1
+ /*
2
+ * Copyright (C) 2009-2011 the libgit2 contributors
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 "common.h"
9
+ #include "odb.h"
10
+ #include "pack.h"
11
+ #include "delta-apply.h"
12
+ #include "sha1_lookup.h"
13
+ #include "mwindow.h"
14
+ #include "fileops.h"
15
+
16
+ #include "git2/oid.h"
17
+ #include "git2/zlib.h"
18
+
19
+ static int packfile_open(struct git_pack_file *p);
20
+ static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
21
+ int packfile_unpack_compressed(
22
+ git_rawobj *obj,
23
+ struct git_pack_file *p,
24
+ git_mwindow **w_curs,
25
+ off_t *curpos,
26
+ size_t size,
27
+ git_otype type);
28
+
29
+ /* Can find the offset of an object given
30
+ * a prefix of an identifier.
31
+ * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
32
+ * is ambiguous within the pack.
33
+ * This method assumes that len is between
34
+ * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
35
+ */
36
+ static int pack_entry_find_offset(
37
+ off_t *offset_out,
38
+ git_oid *found_oid,
39
+ struct git_pack_file *p,
40
+ const git_oid *short_oid,
41
+ unsigned int len);
42
+
43
+ /***********************************************************
44
+ *
45
+ * PACK INDEX METHODS
46
+ *
47
+ ***********************************************************/
48
+
49
+ static void pack_index_free(struct git_pack_file *p)
50
+ {
51
+ if (p->index_map.data) {
52
+ git_futils_mmap_free(&p->index_map);
53
+ p->index_map.data = NULL;
54
+ }
55
+ }
56
+
57
+ static int pack_index_check(const char *path, struct git_pack_file *p)
58
+ {
59
+ struct git_pack_idx_header *hdr;
60
+ uint32_t version, nr, i, *index;
61
+
62
+ void *idx_map;
63
+ size_t idx_size;
64
+
65
+ struct stat st;
66
+
67
+ /* TODO: properly open the file without access time */
68
+ git_file fd = p_open(path, O_RDONLY /*| O_NOATIME */);
69
+
70
+ int error;
71
+
72
+ if (fd < 0)
73
+ return git__throw(GIT_EOSERR, "Failed to check index. File missing or corrupted");
74
+
75
+ if (p_fstat(fd, &st) < GIT_SUCCESS) {
76
+ p_close(fd);
77
+ return git__throw(GIT_EOSERR, "Failed to check index. File appears to be corrupted");
78
+ }
79
+
80
+ if (!git__is_sizet(st.st_size))
81
+ return GIT_ENOMEM;
82
+
83
+ idx_size = (size_t)st.st_size;
84
+
85
+ if (idx_size < 4 * 256 + 20 + 20) {
86
+ p_close(fd);
87
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted");
88
+ }
89
+
90
+ error = git_futils_mmap_ro(&p->index_map, fd, 0, idx_size);
91
+ p_close(fd);
92
+
93
+ if (error < GIT_SUCCESS)
94
+ return git__rethrow(error, "Failed to check index");
95
+
96
+ hdr = idx_map = p->index_map.data;
97
+
98
+ if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
99
+ version = ntohl(hdr->idx_version);
100
+
101
+ if (version < 2 || version > 2) {
102
+ git_futils_mmap_free(&p->index_map);
103
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Unsupported index version");
104
+ }
105
+
106
+ } else
107
+ version = 1;
108
+
109
+ nr = 0;
110
+ index = idx_map;
111
+
112
+ if (version > 1)
113
+ index += 2; /* skip index header */
114
+
115
+ for (i = 0; i < 256; i++) {
116
+ uint32_t n = ntohl(index[i]);
117
+ if (n < nr) {
118
+ git_futils_mmap_free(&p->index_map);
119
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Index is non-monotonic");
120
+ }
121
+ nr = n;
122
+ }
123
+
124
+ if (version == 1) {
125
+ /*
126
+ * Total size:
127
+ * - 256 index entries 4 bytes each
128
+ * - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
129
+ * - 20-byte SHA1 of the packfile
130
+ * - 20-byte SHA1 file checksum
131
+ */
132
+ if (idx_size != 4*256 + nr * 24 + 20 + 20) {
133
+ git_futils_mmap_free(&p->index_map);
134
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted");
135
+ }
136
+ } else if (version == 2) {
137
+ /*
138
+ * Minimum size:
139
+ * - 8 bytes of header
140
+ * - 256 index entries 4 bytes each
141
+ * - 20-byte sha1 entry * nr
142
+ * - 4-byte crc entry * nr
143
+ * - 4-byte offset entry * nr
144
+ * - 20-byte SHA1 of the packfile
145
+ * - 20-byte SHA1 file checksum
146
+ * And after the 4-byte offset table might be a
147
+ * variable sized table containing 8-byte entries
148
+ * for offsets larger than 2^31.
149
+ */
150
+ unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
151
+ unsigned long max_size = min_size;
152
+
153
+ if (nr)
154
+ max_size += (nr - 1)*8;
155
+
156
+ if (idx_size < min_size || idx_size > max_size) {
157
+ git_futils_mmap_free(&p->index_map);
158
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Wrong index size");
159
+ }
160
+
161
+ /* Make sure that off_t is big enough to access the whole pack...
162
+ * Is this an issue in libgit2? It shouldn't. */
163
+ if (idx_size != min_size && (sizeof(off_t) <= 4)) {
164
+ git_futils_mmap_free(&p->index_map);
165
+ return git__throw(GIT_EOSERR, "Failed to check index. off_t not big enough to access the whole pack");
166
+ }
167
+ }
168
+
169
+ p->index_version = version;
170
+ p->num_objects = nr;
171
+ return GIT_SUCCESS;
172
+ }
173
+
174
+ static int pack_index_open(struct git_pack_file *p)
175
+ {
176
+ char *idx_name;
177
+ int error;
178
+
179
+ if (p->index_map.data)
180
+ return GIT_SUCCESS;
181
+
182
+ idx_name = git__strdup(p->pack_name);
183
+ strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
184
+
185
+ error = pack_index_check(idx_name, p);
186
+ git__free(idx_name);
187
+
188
+ return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to open index");
189
+ }
190
+
191
+ static unsigned char *pack_window_open(
192
+ struct git_pack_file *p,
193
+ git_mwindow **w_cursor,
194
+ off_t offset,
195
+ unsigned int *left)
196
+ {
197
+ if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS)
198
+ return NULL;
199
+
200
+ /* Since packfiles end in a hash of their content and it's
201
+ * pointless to ask for an offset into the middle of that
202
+ * hash, and the pack_window_contains function above wouldn't match
203
+ * don't allow an offset too close to the end of the file.
204
+ */
205
+ if (offset > (p->mwf.size - 20))
206
+ return NULL;
207
+
208
+ return git_mwindow_open(&p->mwf, w_cursor, offset, 20, left);
209
+ }
210
+
211
+ static unsigned long packfile_unpack_header1(
212
+ size_t *sizep,
213
+ git_otype *type,
214
+ const unsigned char *buf,
215
+ unsigned long len)
216
+ {
217
+ unsigned shift;
218
+ unsigned long size, c;
219
+ unsigned long used = 0;
220
+
221
+ c = buf[used++];
222
+ *type = (c >> 4) & 7;
223
+ size = c & 15;
224
+ shift = 4;
225
+ while (c & 0x80) {
226
+ if (len <= used || bitsizeof(long) <= shift)
227
+ return 0;
228
+
229
+ c = buf[used++];
230
+ size += (c & 0x7f) << shift;
231
+ shift += 7;
232
+ }
233
+
234
+ *sizep = (size_t)size;
235
+ return used;
236
+ }
237
+
238
+ int git_packfile_unpack_header(
239
+ size_t *size_p,
240
+ git_otype *type_p,
241
+ git_mwindow_file *mwf,
242
+ git_mwindow **w_curs,
243
+ off_t *curpos)
244
+ {
245
+ unsigned char *base;
246
+ unsigned int left;
247
+ unsigned long used;
248
+
249
+ /* pack_window_open() assures us we have [base, base + 20) available
250
+ * as a range that we can look at at. (Its actually the hash
251
+ * size that is assured.) With our object header encoding
252
+ * the maximum deflated object size is 2^137, which is just
253
+ * insane, so we know won't exceed what we have been given.
254
+ */
255
+ // base = pack_window_open(p, w_curs, *curpos, &left);
256
+ base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
257
+ if (base == NULL)
258
+ return GIT_ENOMEM;
259
+
260
+ used = packfile_unpack_header1(size_p, type_p, base, left);
261
+
262
+ if (used == 0)
263
+ return git__throw(GIT_EOBJCORRUPTED, "Header length is zero");
264
+
265
+ *curpos += used;
266
+ return GIT_SUCCESS;
267
+ }
268
+
269
+ static int packfile_unpack_delta(
270
+ git_rawobj *obj,
271
+ struct git_pack_file *p,
272
+ git_mwindow **w_curs,
273
+ off_t *curpos,
274
+ size_t delta_size,
275
+ git_otype delta_type,
276
+ off_t obj_offset)
277
+ {
278
+ off_t base_offset;
279
+ git_rawobj base, delta;
280
+ int error;
281
+
282
+ base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset);
283
+ if (base_offset == 0)
284
+ return git__throw(GIT_EOBJCORRUPTED, "Delta offset is zero");
285
+ if (base_offset < 0)
286
+ return git__rethrow(base_offset, "Failed to get delta base");
287
+
288
+ git_mwindow_close(w_curs);
289
+ error = git_packfile_unpack(&base, p, &base_offset);
290
+
291
+ /*
292
+ * TODO: git.git tries to load the base from other packfiles
293
+ * or loose objects.
294
+ *
295
+ * We'll need to do this in order to support thin packs.
296
+ */
297
+ if (error < GIT_SUCCESS)
298
+ return git__rethrow(error, "Corrupted delta");
299
+
300
+ error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type);
301
+ if (error < GIT_SUCCESS) {
302
+ git__free(base.data);
303
+ return git__rethrow(error, "Corrupted delta");
304
+ }
305
+
306
+ obj->type = base.type;
307
+ error = git__delta_apply(obj,
308
+ base.data, base.len,
309
+ delta.data, delta.len);
310
+
311
+ git__free(base.data);
312
+ git__free(delta.data);
313
+
314
+ /* TODO: we might want to cache this shit. eventually */
315
+ //add_delta_base_cache(p, base_offset, base, base_size, *type);
316
+ return error; /* error set by git__delta_apply */
317
+ }
318
+
319
+ int git_packfile_unpack(
320
+ git_rawobj *obj,
321
+ struct git_pack_file *p,
322
+ off_t *obj_offset)
323
+ {
324
+ git_mwindow *w_curs = NULL;
325
+ off_t curpos = *obj_offset;
326
+ int error;
327
+
328
+ size_t size = 0;
329
+ git_otype type;
330
+
331
+ /*
332
+ * TODO: optionally check the CRC on the packfile
333
+ */
334
+
335
+ obj->data = NULL;
336
+ obj->len = 0;
337
+ obj->type = GIT_OBJ_BAD;
338
+
339
+ error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
340
+ if (error < GIT_SUCCESS)
341
+ return git__rethrow(error, "Failed to unpack packfile");
342
+
343
+ switch (type) {
344
+ case GIT_OBJ_OFS_DELTA:
345
+ case GIT_OBJ_REF_DELTA:
346
+ error = packfile_unpack_delta(
347
+ obj, p, &w_curs, &curpos,
348
+ size, type, *obj_offset);
349
+ break;
350
+
351
+ case GIT_OBJ_COMMIT:
352
+ case GIT_OBJ_TREE:
353
+ case GIT_OBJ_BLOB:
354
+ case GIT_OBJ_TAG:
355
+ error = packfile_unpack_compressed(
356
+ obj, p, &w_curs, &curpos,
357
+ size, type);
358
+ break;
359
+
360
+ default:
361
+ error = GIT_EOBJCORRUPTED;
362
+ break;
363
+ }
364
+
365
+ git_mwindow_close(&w_curs);
366
+
367
+ if (error < GIT_SUCCESS)
368
+ return git__rethrow(error, "Failed to unpack object");
369
+
370
+ *obj_offset = curpos;
371
+ return GIT_SUCCESS;
372
+ }
373
+
374
+ int packfile_unpack_compressed(
375
+ git_rawobj *obj,
376
+ struct git_pack_file *p,
377
+ git_mwindow **w_curs,
378
+ off_t *curpos,
379
+ size_t size,
380
+ git_otype type)
381
+ {
382
+ int st;
383
+ z_stream stream;
384
+ unsigned char *buffer, *in;
385
+
386
+ buffer = git__malloc(size + 1);
387
+ memset(buffer, 0x0, size + 1);
388
+
389
+ memset(&stream, 0, sizeof(stream));
390
+ stream.next_out = buffer;
391
+ stream.avail_out = (uInt)size + 1;
392
+
393
+ st = inflateInit(&stream);
394
+ if (st != Z_OK) {
395
+ git__free(buffer);
396
+ return git__throw(GIT_EZLIB, "Error in zlib");
397
+ }
398
+
399
+ do {
400
+ in = pack_window_open(p, w_curs, *curpos, &stream.avail_in);
401
+ stream.next_in = in;
402
+ st = inflate(&stream, Z_FINISH);
403
+
404
+ if (!stream.avail_out)
405
+ break; /* the payload is larger than it should be */
406
+
407
+ *curpos += stream.next_in - in;
408
+ } while (st == Z_OK || st == Z_BUF_ERROR);
409
+
410
+ inflateEnd(&stream);
411
+
412
+ if ((st != Z_STREAM_END) || stream.total_out != size) {
413
+ git__free(buffer);
414
+ return git__throw(GIT_EZLIB, "Error in zlib");
415
+ }
416
+
417
+ obj->type = type;
418
+ obj->len = size;
419
+ obj->data = buffer;
420
+ return GIT_SUCCESS;
421
+ }
422
+
423
+ /*
424
+ * curpos is where the data starts, delta_obj_offset is the where the
425
+ * header starts
426
+ */
427
+ off_t get_delta_base(
428
+ struct git_pack_file *p,
429
+ git_mwindow **w_curs,
430
+ off_t *curpos,
431
+ git_otype type,
432
+ off_t delta_obj_offset)
433
+ {
434
+ unsigned char *base_info = pack_window_open(p, w_curs, *curpos, NULL);
435
+ off_t base_offset;
436
+ git_oid unused;
437
+
438
+ /* pack_window_open() assured us we have [base_info, base_info + 20)
439
+ * as a range that we can look at without walking off the
440
+ * end of the mapped window. Its actually the hash size
441
+ * that is assured. An OFS_DELTA longer than the hash size
442
+ * is stupid, as then a REF_DELTA would be smaller to store.
443
+ */
444
+ if (type == GIT_OBJ_OFS_DELTA) {
445
+ unsigned used = 0;
446
+ unsigned char c = base_info[used++];
447
+ base_offset = c & 127;
448
+ while (c & 128) {
449
+ base_offset += 1;
450
+ if (!base_offset || MSB(base_offset, 7))
451
+ return 0; /* overflow */
452
+ c = base_info[used++];
453
+ base_offset = (base_offset << 7) + (c & 127);
454
+ }
455
+ base_offset = delta_obj_offset - base_offset;
456
+ if (base_offset <= 0 || base_offset >= delta_obj_offset)
457
+ return 0; /* out of bound */
458
+ *curpos += used;
459
+ } else if (type == GIT_OBJ_REF_DELTA) {
460
+ /* If we have the cooperative cache, search in it first */
461
+ if (p->has_cache) {
462
+ int pos;
463
+ struct git_pack_entry key;
464
+
465
+ git_oid_fromraw(&key.sha1, base_info);
466
+ pos = git_vector_bsearch(&p->cache, &key);
467
+ if (pos >= 0) {
468
+ *curpos += 20;
469
+ return ((struct git_pack_entry *)git_vector_get(&p->cache, pos))->offset;
470
+ }
471
+ }
472
+ /* The base entry _must_ be in the same pack */
473
+ if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < GIT_SUCCESS)
474
+ return git__rethrow(GIT_EPACKCORRUPTED, "Base entry delta is not in the same pack");
475
+ *curpos += 20;
476
+ } else
477
+ return 0;
478
+
479
+ return base_offset;
480
+ }
481
+
482
+ /***********************************************************
483
+ *
484
+ * PACKFILE METHODS
485
+ *
486
+ ***********************************************************/
487
+
488
+ static struct git_pack_file *packfile_alloc(int extra)
489
+ {
490
+ struct git_pack_file *p = git__malloc(sizeof(*p) + extra);
491
+ memset(p, 0, sizeof(*p));
492
+ p->mwf.fd = -1;
493
+ return p;
494
+ }
495
+
496
+
497
+ void packfile_free(struct git_pack_file *p)
498
+ {
499
+ assert(p);
500
+
501
+ /* clear_delta_base_cache(); */
502
+ git_mwindow_free_all(&p->mwf);
503
+
504
+ if (p->mwf.fd != -1)
505
+ p_close(p->mwf.fd);
506
+
507
+ pack_index_free(p);
508
+
509
+ git__free(p->bad_object_sha1);
510
+ git__free(p);
511
+ }
512
+
513
+ static int packfile_open(struct git_pack_file *p)
514
+ {
515
+ struct stat st;
516
+ struct git_pack_header hdr;
517
+ git_oid sha1;
518
+ unsigned char *idx_sha1;
519
+
520
+ if (!p->index_map.data && pack_index_open(p) < GIT_SUCCESS)
521
+ return git__throw(GIT_ENOTFOUND, "Failed to open packfile. File not found");
522
+
523
+ /* TODO: open with noatime */
524
+ p->mwf.fd = p_open(p->pack_name, O_RDONLY);
525
+ if (p->mwf.fd < 0 || p_fstat(p->mwf.fd, &st) < GIT_SUCCESS)
526
+ return git__throw(GIT_EOSERR, "Failed to open packfile. File appears to be corrupted");
527
+
528
+ if (git_mwindow_file_register(&p->mwf) < GIT_SUCCESS) {
529
+ p_close(p->mwf.fd);
530
+ return git__throw(GIT_ERROR, "Failed to register packfile windows");
531
+ }
532
+
533
+ /* If we created the struct before we had the pack we lack size. */
534
+ if (!p->mwf.size) {
535
+ if (!S_ISREG(st.st_mode))
536
+ goto cleanup;
537
+ p->mwf.size = (off_t)st.st_size;
538
+ } else if (p->mwf.size != st.st_size)
539
+ goto cleanup;
540
+
541
+ #if 0
542
+ /* We leave these file descriptors open with sliding mmap;
543
+ * there is no point keeping them open across exec(), though.
544
+ */
545
+ fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
546
+ if (fd_flag < 0)
547
+ return error("cannot determine file descriptor flags");
548
+
549
+ fd_flag |= FD_CLOEXEC;
550
+ if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
551
+ return GIT_EOSERR;
552
+ #endif
553
+
554
+ /* Verify we recognize this pack file format. */
555
+ if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < GIT_SUCCESS)
556
+ goto cleanup;
557
+
558
+ if (hdr.hdr_signature != htonl(PACK_SIGNATURE))
559
+ goto cleanup;
560
+
561
+ if (!pack_version_ok(hdr.hdr_version))
562
+ goto cleanup;
563
+
564
+ /* Verify the pack matches its index. */
565
+ if (p->num_objects != ntohl(hdr.hdr_entries))
566
+ goto cleanup;
567
+
568
+ if (p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1)
569
+ goto cleanup;
570
+
571
+ if (p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < GIT_SUCCESS)
572
+ goto cleanup;
573
+
574
+ idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
575
+
576
+ if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) != 0)
577
+ goto cleanup;
578
+
579
+ return GIT_SUCCESS;
580
+
581
+ cleanup:
582
+ p_close(p->mwf.fd);
583
+ p->mwf.fd = -1;
584
+ return git__throw(GIT_EPACKCORRUPTED, "Failed to open packfile. Pack is corrupted");
585
+ }
586
+
587
+ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
588
+ {
589
+ struct stat st;
590
+ struct git_pack_file *p;
591
+ size_t path_len;
592
+
593
+ *pack_out = NULL;
594
+ path_len = strlen(path);
595
+ p = packfile_alloc(path_len + 2);
596
+
597
+ /*
598
+ * Make sure a corresponding .pack file exists and that
599
+ * the index looks sane.
600
+ */
601
+ path_len -= strlen(".idx");
602
+ if (path_len < 1) {
603
+ git__free(p);
604
+ return git__throw(GIT_ENOTFOUND, "Failed to check packfile. Wrong path name");
605
+ }
606
+
607
+ memcpy(p->pack_name, path, path_len);
608
+
609
+ strcpy(p->pack_name + path_len, ".keep");
610
+ if (git_futils_exists(p->pack_name) == GIT_SUCCESS)
611
+ p->pack_keep = 1;
612
+
613
+ strcpy(p->pack_name + path_len, ".pack");
614
+ if (p_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) {
615
+ git__free(p);
616
+ return git__throw(GIT_ENOTFOUND, "Failed to check packfile. File not found");
617
+ }
618
+
619
+ /* ok, it looks sane as far as we can check without
620
+ * actually mapping the pack file.
621
+ */
622
+ p->mwf.size = (off_t)st.st_size;
623
+ p->pack_local = 1;
624
+ p->mtime = (git_time_t)st.st_mtime;
625
+
626
+ /* see if we can parse the sha1 oid in the packfile name */
627
+ if (path_len < 40 ||
628
+ git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < GIT_SUCCESS)
629
+ memset(&p->sha1, 0x0, GIT_OID_RAWSZ);
630
+
631
+ *pack_out = p;
632
+ return GIT_SUCCESS;
633
+ }
634
+
635
+ /***********************************************************
636
+ *
637
+ * PACKFILE ENTRY SEARCH INTERNALS
638
+ *
639
+ ***********************************************************/
640
+
641
+ static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
642
+ {
643
+ const unsigned char *index = p->index_map.data;
644
+ index += 4 * 256;
645
+ if (p->index_version == 1) {
646
+ return ntohl(*((uint32_t *)(index + 24 * n)));
647
+ } else {
648
+ uint32_t off;
649
+ index += 8 + p->num_objects * (20 + 4);
650
+ off = ntohl(*((uint32_t *)(index + 4 * n)));
651
+ if (!(off & 0x80000000))
652
+ return off;
653
+ index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
654
+ return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
655
+ ntohl(*((uint32_t *)(index + 4)));
656
+ }
657
+ }
658
+
659
+ static int pack_entry_find_offset(
660
+ off_t *offset_out,
661
+ git_oid *found_oid,
662
+ struct git_pack_file *p,
663
+ const git_oid *short_oid,
664
+ unsigned int len)
665
+ {
666
+ const uint32_t *level1_ofs = p->index_map.data;
667
+ const unsigned char *index = p->index_map.data;
668
+ unsigned hi, lo, stride;
669
+ int pos, found = 0;
670
+ const unsigned char *current = 0;
671
+
672
+ *offset_out = 0;
673
+
674
+ if (index == NULL) {
675
+ int error;
676
+
677
+ if ((error = pack_index_open(p)) < GIT_SUCCESS)
678
+ return git__rethrow(error, "Failed to find offset for pack entry");
679
+
680
+ assert(p->index_map.data);
681
+
682
+ index = p->index_map.data;
683
+ level1_ofs = p->index_map.data;
684
+ }
685
+
686
+ if (p->index_version > 1) {
687
+ level1_ofs += 2;
688
+ index += 8;
689
+ }
690
+
691
+ index += 4 * 256;
692
+ hi = ntohl(level1_ofs[(int)short_oid->id[0]]);
693
+ lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)short_oid->id[0] - 1]));
694
+
695
+ if (p->index_version > 1) {
696
+ stride = 20;
697
+ } else {
698
+ stride = 24;
699
+ index += 4;
700
+ }
701
+
702
+ #ifdef INDEX_DEBUG_LOOKUP
703
+ printf("%02x%02x%02x... lo %u hi %u nr %d\n",
704
+ short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects);
705
+ #endif
706
+
707
+ /* Use git.git lookup code */
708
+ pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id);
709
+
710
+ if (pos >= 0) {
711
+ /* An object matching exactly the oid was found */
712
+ found = 1;
713
+ current = index + pos * stride;
714
+ } else {
715
+ /* No object was found */
716
+ /* pos refers to the object with the "closest" oid to short_oid */
717
+ pos = - 1 - pos;
718
+ if (pos < (int)p->num_objects) {
719
+ current = index + pos * stride;
720
+
721
+ if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) {
722
+ found = 1;
723
+ }
724
+ }
725
+ }
726
+
727
+ if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)p->num_objects) {
728
+ /* Check for ambiguousity */
729
+ const unsigned char *next = current + stride;
730
+
731
+ if (!git_oid_ncmp(short_oid, (const git_oid *)next, len)) {
732
+ found = 2;
733
+ }
734
+ }
735
+
736
+ if (!found) {
737
+ return git__throw(GIT_ENOTFOUND, "Failed to find offset for pack entry. Entry not found");
738
+ } else if (found > 1) {
739
+ return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find offset for pack entry. Ambiguous sha1 prefix within pack");
740
+ } else {
741
+ *offset_out = nth_packed_object_offset(p, pos);
742
+ git_oid_fromraw(found_oid, current);
743
+
744
+ #ifdef INDEX_DEBUG_LOOKUP
745
+ unsigned char hex_sha1[GIT_OID_HEXSZ + 1];
746
+ git_oid_fmt(hex_sha1, found_oid);
747
+ hex_sha1[GIT_OID_HEXSZ] = '\0';
748
+ printf("found lo=%d %s\n", lo, hex_sha1);
749
+ #endif
750
+ return GIT_SUCCESS;
751
+ }
752
+ }
753
+
754
+ int git_pack_entry_find(
755
+ struct git_pack_entry *e,
756
+ struct git_pack_file *p,
757
+ const git_oid *short_oid,
758
+ unsigned int len)
759
+ {
760
+ off_t offset;
761
+ git_oid found_oid;
762
+ int error;
763
+
764
+ assert(p);
765
+
766
+ if (len == GIT_OID_HEXSZ && p->num_bad_objects) {
767
+ unsigned i;
768
+ for (i = 0; i < p->num_bad_objects; i++)
769
+ if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0)
770
+ return git__throw(GIT_ERROR, "Failed to find pack entry. Bad object found");
771
+ }
772
+
773
+ error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len);
774
+ if (error < GIT_SUCCESS)
775
+ return git__rethrow(error, "Failed to find pack entry. Couldn't find offset");
776
+
777
+ /* we found a unique entry in the index;
778
+ * make sure the packfile backing the index
779
+ * still exists on disk */
780
+ if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS)
781
+ return git__throw(GIT_EOSERR, "Failed to find pack entry. Packfile doesn't exist on disk");
782
+
783
+ e->offset = offset;
784
+ e->p = p;
785
+
786
+ git_oid_cpy(&e->sha1, &found_oid);
787
+ return GIT_SUCCESS;
788
+ }