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,43 @@
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
+ #ifndef INCLUDE_odb_h__
8
+ #define INCLUDE_odb_h__
9
+
10
+ #include "git2/odb.h"
11
+ #include "git2/oid.h"
12
+ #include "git2/types.h"
13
+
14
+ #include "vector.h"
15
+ #include "cache.h"
16
+
17
+ #define GIT_OBJECTS_DIR "objects/"
18
+ #define GIT_OBJECT_DIR_MODE 0777
19
+ #define GIT_OBJECT_FILE_MODE 0444
20
+
21
+ /* DO NOT EXPORT */
22
+ typedef struct {
23
+ void *data; /**< Raw, decompressed object data. */
24
+ size_t len; /**< Total number of bytes in data. */
25
+ git_otype type; /**< Type of this object. */
26
+ } git_rawobj;
27
+
28
+ /* EXPORT */
29
+ struct git_odb_object {
30
+ git_cached_obj cached;
31
+ git_rawobj raw;
32
+ };
33
+
34
+ /* EXPORT */
35
+ struct git_odb {
36
+ git_refcount rc;
37
+ git_vector backends;
38
+ git_cache cache;
39
+ };
40
+
41
+ int git_odb__hash_obj(git_oid *id, git_rawobj *obj);
42
+
43
+ #endif
@@ -0,0 +1,855 @@
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/zlib.h"
10
+ #include "git2/object.h"
11
+ #include "git2/oid.h"
12
+ #include "fileops.h"
13
+ #include "hash.h"
14
+ #include "odb.h"
15
+ #include "delta-apply.h"
16
+ #include "filebuf.h"
17
+
18
+ #include "git2/odb_backend.h"
19
+ #include "git2/types.h"
20
+
21
+ typedef struct { /* object header data */
22
+ git_otype type; /* object type */
23
+ size_t size; /* object size */
24
+ } obj_hdr;
25
+
26
+ typedef struct {
27
+ git_odb_stream stream;
28
+ git_filebuf fbuf;
29
+ int finished;
30
+ } loose_writestream;
31
+
32
+ typedef struct loose_backend {
33
+ git_odb_backend parent;
34
+
35
+ int object_zlib_level; /** loose object zlib compression level. */
36
+ int fsync_object_files; /** loose object file fsync flag. */
37
+ char *objects_dir;
38
+ } loose_backend;
39
+
40
+ /* State structure for exploring directories,
41
+ * in order to locate objects matching a short oid.
42
+ */
43
+ typedef struct {
44
+ size_t dir_len;
45
+ unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */
46
+ unsigned int short_oid_len;
47
+ int found; /* number of matching
48
+ * objects already found */
49
+ unsigned char res_oid[GIT_OID_HEXSZ]; /* hex formatted oid of
50
+ * the object found */
51
+ } loose_locate_object_state;
52
+
53
+
54
+
55
+ /***********************************************************
56
+ *
57
+ * MISCELANEOUS HELPER FUNCTIONS
58
+ *
59
+ ***********************************************************/
60
+
61
+ static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
62
+ {
63
+ size_t len = strlen(dir);
64
+
65
+ /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
66
+ if (len+43 > n)
67
+ return len+43;
68
+
69
+ /* the object dir: eg $GIT_DIR/objects */
70
+ strcpy(name, dir);
71
+ if (name[len-1] != '/')
72
+ name[len++] = '/';
73
+
74
+ /* loose object filename: aa/aaa... (41 bytes) */
75
+ git_oid_pathfmt(&name[len], id);
76
+ name[len+41] = '\0';
77
+
78
+ return 0;
79
+ }
80
+
81
+
82
+ static size_t get_binary_object_header(obj_hdr *hdr, git_fbuffer *obj)
83
+ {
84
+ unsigned char c;
85
+ unsigned char *data = obj->data;
86
+ size_t shift, size, used = 0;
87
+
88
+ if (obj->len == 0)
89
+ return 0;
90
+
91
+ c = data[used++];
92
+ hdr->type = (c >> 4) & 7;
93
+
94
+ size = c & 15;
95
+ shift = 4;
96
+ while (c & 0x80) {
97
+ if (obj->len <= used)
98
+ return 0;
99
+ if (sizeof(size_t) * 8 <= shift)
100
+ return 0;
101
+ c = data[used++];
102
+ size += (c & 0x7f) << shift;
103
+ shift += 7;
104
+ }
105
+ hdr->size = size;
106
+
107
+ return used;
108
+ }
109
+
110
+ static size_t get_object_header(obj_hdr *hdr, unsigned char *data)
111
+ {
112
+ char c, typename[10];
113
+ size_t size, used = 0;
114
+
115
+ /*
116
+ * type name string followed by space.
117
+ */
118
+ while ((c = data[used]) != ' ') {
119
+ typename[used++] = c;
120
+ if (used >= sizeof(typename))
121
+ return 0;
122
+ }
123
+ typename[used] = 0;
124
+ if (used == 0)
125
+ return 0;
126
+ hdr->type = git_object_string2type(typename);
127
+ used++; /* consume the space */
128
+
129
+ /*
130
+ * length follows immediately in decimal (without
131
+ * leading zeros).
132
+ */
133
+ size = data[used++] - '0';
134
+ if (size > 9)
135
+ return 0;
136
+ if (size) {
137
+ while ((c = data[used]) != '\0') {
138
+ size_t d = c - '0';
139
+ if (d > 9)
140
+ break;
141
+ used++;
142
+ size = size * 10 + d;
143
+ }
144
+ }
145
+ hdr->size = size;
146
+
147
+ /*
148
+ * the length must be followed by a zero byte
149
+ */
150
+ if (data[used++] != '\0')
151
+ return 0;
152
+
153
+ return used;
154
+ }
155
+
156
+
157
+
158
+ /***********************************************************
159
+ *
160
+ * ZLIB RELATED FUNCTIONS
161
+ *
162
+ ***********************************************************/
163
+
164
+ static void init_stream(z_stream *s, void *out, size_t len)
165
+ {
166
+ memset(s, 0, sizeof(*s));
167
+ s->next_out = out;
168
+ s->avail_out = (uInt)len;
169
+ }
170
+
171
+ static void set_stream_input(z_stream *s, void *in, size_t len)
172
+ {
173
+ s->next_in = in;
174
+ s->avail_in = (uInt)len;
175
+ }
176
+
177
+ static void set_stream_output(z_stream *s, void *out, size_t len)
178
+ {
179
+ s->next_out = out;
180
+ s->avail_out = (uInt)len;
181
+ }
182
+
183
+
184
+ static int start_inflate(z_stream *s, git_fbuffer *obj, void *out, size_t len)
185
+ {
186
+ int status;
187
+
188
+ init_stream(s, out, len);
189
+ set_stream_input(s, obj->data, obj->len);
190
+
191
+ if ((status = inflateInit(s)) < Z_OK)
192
+ return status;
193
+
194
+ return inflate(s, 0);
195
+ }
196
+
197
+ static int finish_inflate(z_stream *s)
198
+ {
199
+ int status = Z_OK;
200
+
201
+ while (status == Z_OK)
202
+ status = inflate(s, Z_FINISH);
203
+
204
+ inflateEnd(s);
205
+
206
+ if ((status != Z_STREAM_END) || (s->avail_in != 0))
207
+ return git__throw(GIT_ERROR, "Failed to finish inflation. Stream aborted prematurely");
208
+
209
+ return GIT_SUCCESS;
210
+ }
211
+
212
+ static int is_zlib_compressed_data(unsigned char *data)
213
+ {
214
+ unsigned int w;
215
+
216
+ w = ((unsigned int)(data[0]) << 8) + data[1];
217
+ return (data[0] & 0x8F) == 0x08 && !(w % 31);
218
+ }
219
+
220
+ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
221
+ {
222
+ z_stream zs;
223
+ int status = Z_OK;
224
+
225
+ memset(&zs, 0x0, sizeof(zs));
226
+
227
+ zs.next_out = out;
228
+ zs.avail_out = (uInt)outlen;
229
+
230
+ zs.next_in = in;
231
+ zs.avail_in = (uInt)inlen;
232
+
233
+ if (inflateInit(&zs) < Z_OK)
234
+ return git__throw(GIT_ERROR, "Failed to inflate buffer");
235
+
236
+ while (status == Z_OK)
237
+ status = inflate(&zs, Z_FINISH);
238
+
239
+ inflateEnd(&zs);
240
+
241
+ if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
242
+ return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
243
+
244
+ if (zs.total_out != outlen)
245
+ return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
246
+
247
+ return GIT_SUCCESS;
248
+ }
249
+
250
+ static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
251
+ {
252
+ unsigned char *buf, *head = hb;
253
+ size_t tail;
254
+
255
+ /*
256
+ * allocate a buffer to hold the inflated data and copy the
257
+ * initial sequence of inflated data from the tail of the
258
+ * head buffer, if any.
259
+ */
260
+ if ((buf = git__malloc(hdr->size + 1)) == NULL) {
261
+ inflateEnd(s);
262
+ return NULL;
263
+ }
264
+ tail = s->total_out - used;
265
+ if (used > 0 && tail > 0) {
266
+ if (tail > hdr->size)
267
+ tail = hdr->size;
268
+ memcpy(buf, head + used, tail);
269
+ }
270
+ used = tail;
271
+
272
+ /*
273
+ * inflate the remainder of the object data, if any
274
+ */
275
+ if (hdr->size < used)
276
+ inflateEnd(s);
277
+ else {
278
+ set_stream_output(s, buf + used, hdr->size - used);
279
+ if (finish_inflate(s)) {
280
+ git__free(buf);
281
+ return NULL;
282
+ }
283
+ }
284
+
285
+ return buf;
286
+ }
287
+
288
+ /*
289
+ * At one point, there was a loose object format that was intended to
290
+ * mimic the format used in pack-files. This was to allow easy copying
291
+ * of loose object data into packs. This format is no longer used, but
292
+ * we must still read it.
293
+ */
294
+ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_fbuffer *obj)
295
+ {
296
+ unsigned char *in, *buf;
297
+ obj_hdr hdr;
298
+ size_t len, used;
299
+
300
+ /*
301
+ * read the object header, which is an (uncompressed)
302
+ * binary encoding of the object type and size.
303
+ */
304
+ if ((used = get_binary_object_header(&hdr, obj)) == 0)
305
+ return git__throw(GIT_ERROR, "Failed to inflate loose object. Object has no header");
306
+
307
+ if (!git_object_typeisloose(hdr.type))
308
+ return git__throw(GIT_ERROR, "Failed to inflate loose object. Wrong object type");
309
+
310
+ /*
311
+ * allocate a buffer and inflate the data into it
312
+ */
313
+ buf = git__malloc(hdr.size + 1);
314
+ if (!buf)
315
+ return GIT_ENOMEM;
316
+
317
+ in = ((unsigned char *)obj->data) + used;
318
+ len = obj->len - used;
319
+ if (inflate_buffer(in, len, buf, hdr.size)) {
320
+ git__free(buf);
321
+ return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer");
322
+ }
323
+ buf[hdr.size] = '\0';
324
+
325
+ out->data = buf;
326
+ out->len = hdr.size;
327
+ out->type = hdr.type;
328
+
329
+ return GIT_SUCCESS;
330
+ }
331
+
332
+ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
333
+ {
334
+ unsigned char head[64], *buf;
335
+ z_stream zs;
336
+ obj_hdr hdr;
337
+ size_t used;
338
+
339
+ /*
340
+ * check for a pack-like loose object
341
+ */
342
+ if (!is_zlib_compressed_data(obj->data))
343
+ return inflate_packlike_loose_disk_obj(out, obj);
344
+
345
+ /*
346
+ * inflate the initial part of the io buffer in order
347
+ * to parse the object header (type and size).
348
+ */
349
+ if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK)
350
+ return git__throw(GIT_ERROR, "Failed to inflate disk object. Could not inflate buffer");
351
+
352
+ if ((used = get_object_header(&hdr, head)) == 0)
353
+ return git__throw(GIT_ERROR, "Failed to inflate disk object. Object has no header");
354
+
355
+ if (!git_object_typeisloose(hdr.type))
356
+ return git__throw(GIT_ERROR, "Failed to inflate disk object. Wrong object type");
357
+
358
+ /*
359
+ * allocate a buffer and inflate the object data into it
360
+ * (including the initial sequence in the head buffer).
361
+ */
362
+ if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
363
+ return GIT_ENOMEM;
364
+ buf[hdr.size] = '\0';
365
+
366
+ out->data = buf;
367
+ out->len = hdr.size;
368
+ out->type = hdr.type;
369
+
370
+ return GIT_SUCCESS;
371
+ }
372
+
373
+
374
+
375
+
376
+
377
+
378
+ /***********************************************************
379
+ *
380
+ * ODB OBJECT READING & WRITING
381
+ *
382
+ * Backend for the public API; read headers and full objects
383
+ * from the ODB. Write raw data to the ODB.
384
+ *
385
+ ***********************************************************/
386
+
387
+ static int read_loose(git_rawobj *out, const char *loc)
388
+ {
389
+ int error;
390
+ git_fbuffer obj = GIT_FBUFFER_INIT;
391
+
392
+ assert(out && loc);
393
+
394
+ out->data = NULL;
395
+ out->len = 0;
396
+ out->type = GIT_OBJ_BAD;
397
+
398
+ if (git_futils_readbuffer(&obj, loc) < 0)
399
+ return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
400
+
401
+ error = inflate_disk_obj(out, &obj);
402
+ git_futils_freebuffer(&obj);
403
+
404
+ return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object");
405
+ }
406
+
407
+ static int read_header_loose(git_rawobj *out, const char *loc)
408
+ {
409
+ int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;
410
+ git_file fd;
411
+ z_stream zs;
412
+ obj_hdr header_obj;
413
+ unsigned char raw_buffer[16], inflated_buffer[64];
414
+
415
+ assert(out && loc);
416
+
417
+ out->data = NULL;
418
+
419
+ if ((fd = p_open(loc, O_RDONLY)) < 0)
420
+ return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found");
421
+
422
+ init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
423
+
424
+ if (inflateInit(&zs) < Z_OK) {
425
+ error = GIT_EZLIB;
426
+ goto cleanup;
427
+ }
428
+
429
+ do {
430
+ if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
431
+ set_stream_input(&zs, raw_buffer, read_bytes);
432
+ z_return = inflate(&zs, 0);
433
+ } else {
434
+ z_return = Z_STREAM_END;
435
+ break;
436
+ }
437
+ } while (z_return == Z_OK);
438
+
439
+ if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
440
+ || get_object_header(&header_obj, inflated_buffer) == 0
441
+ || git_object_typeisloose(header_obj.type) == 0) {
442
+ error = GIT_EOBJCORRUPTED;
443
+ goto cleanup;
444
+ }
445
+
446
+ out->len = header_obj.size;
447
+ out->type = header_obj.type;
448
+
449
+ cleanup:
450
+ finish_inflate(&zs);
451
+ p_close(fd);
452
+
453
+ if (error < GIT_SUCCESS)
454
+ return git__throw(error, "Failed to read loose object header. Header is corrupted");
455
+
456
+ return GIT_SUCCESS;
457
+ }
458
+
459
+ static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
460
+ {
461
+ object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
462
+ return git_futils_exists(object_location);
463
+ }
464
+
465
+ /* Explore an entry of a directory and see if it matches a short oid */
466
+ static int fn_locate_object_short_oid(void *state, char *pathbuf) {
467
+ loose_locate_object_state *sstate = (loose_locate_object_state *)state;
468
+
469
+ size_t pathbuf_len = strlen(pathbuf);
470
+ if (pathbuf_len - sstate->dir_len != GIT_OID_HEXSZ - 2) {
471
+ /* Entry cannot be an object. Continue to next entry */
472
+ return GIT_SUCCESS;
473
+ }
474
+
475
+ if (!git_futils_exists(pathbuf) && git_futils_isdir(pathbuf)) {
476
+ /* We are already in the directory matching the 2 first hex characters,
477
+ * compare the first ncmp characters of the oids */
478
+ if (!memcmp(sstate->short_oid + 2,
479
+ (unsigned char *)pathbuf + sstate->dir_len,
480
+ sstate->short_oid_len - 2)) {
481
+
482
+ if (!sstate->found) {
483
+ sstate->res_oid[0] = sstate->short_oid[0];
484
+ sstate->res_oid[1] = sstate->short_oid[1];
485
+ memcpy(sstate->res_oid+2, pathbuf+sstate->dir_len, GIT_OID_HEXSZ-2);
486
+ }
487
+ sstate->found++;
488
+ }
489
+ }
490
+ if (sstate->found > 1)
491
+ return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Ambiguous sha1 prefix within loose objects");
492
+
493
+ return GIT_SUCCESS;
494
+ }
495
+
496
+ /* Locate an object matching a given short oid */
497
+ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, unsigned int len)
498
+ {
499
+ char *objects_dir = backend->objects_dir;
500
+ size_t dir_len = strlen(objects_dir);
501
+ loose_locate_object_state state;
502
+ int error;
503
+
504
+ if (dir_len+43 > GIT_PATH_MAX)
505
+ return git__throw(GIT_ERROR, "Failed to locate object from short oid. Object path too long");
506
+
507
+ strcpy(object_location, objects_dir);
508
+
509
+ /* Add a separator if not already there */
510
+ if (object_location[dir_len-1] != '/')
511
+ object_location[dir_len++] = '/';
512
+
513
+ /* Convert raw oid to hex formatted oid */
514
+ git_oid_fmt((char *)state.short_oid, short_oid);
515
+ /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
516
+ sprintf(object_location+dir_len, "%.2s/", state.short_oid);
517
+
518
+ /* Check that directory exists */
519
+ if (git_futils_exists(object_location) || git_futils_isdir(object_location))
520
+ return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
521
+
522
+ state.dir_len = dir_len+3;
523
+ state.short_oid_len = len;
524
+ state.found = 0;
525
+ /* Explore directory to find a unique object matching short_oid */
526
+ error = git_futils_direach(object_location, GIT_PATH_MAX, fn_locate_object_short_oid, &state);
527
+ if (error) {
528
+ return git__rethrow(error, "Failed to locate object from short oid");
529
+ }
530
+ if (!state.found) {
531
+ return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
532
+ }
533
+
534
+ /* Convert obtained hex formatted oid to raw */
535
+ error = git_oid_fromstr(res_oid, (char *)state.res_oid);
536
+ if (error) {
537
+ return git__rethrow(error, "Failed to locate object from short oid");
538
+ }
539
+
540
+ /* Update the location according to the oid obtained */
541
+ git_oid_pathfmt(object_location+dir_len, res_oid);
542
+
543
+ return GIT_SUCCESS;
544
+ }
545
+
546
+
547
+
548
+
549
+
550
+
551
+
552
+
553
+
554
+ /***********************************************************
555
+ *
556
+ * LOOSE BACKEND PUBLIC API
557
+ *
558
+ * Implement the git_odb_backend API calls
559
+ *
560
+ ***********************************************************/
561
+
562
+ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
563
+ {
564
+ char object_path[GIT_PATH_MAX];
565
+ git_rawobj raw;
566
+ int error;
567
+
568
+ assert(backend && oid);
569
+
570
+ raw.len = 0;
571
+ raw.type = GIT_OBJ_BAD;
572
+
573
+ if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
574
+ return git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
575
+
576
+ if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
577
+ return error;
578
+
579
+ *len_p = raw.len;
580
+ *type_p = raw.type;
581
+ return GIT_SUCCESS;
582
+ }
583
+
584
+ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
585
+ {
586
+ char object_path[GIT_PATH_MAX];
587
+ git_rawobj raw;
588
+ int error;
589
+
590
+ assert(backend && oid);
591
+
592
+ if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
593
+ return git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
594
+
595
+ if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
596
+ return git__rethrow(error, "Failed to read loose backend");
597
+
598
+ *buffer_p = raw.data;
599
+ *len_p = raw.len;
600
+ *type_p = raw.type;
601
+
602
+ return GIT_SUCCESS;
603
+ }
604
+
605
+ static int loose_backend__read_prefix(
606
+ git_oid *out_oid,
607
+ void **buffer_p,
608
+ size_t *len_p,
609
+ git_otype *type_p,
610
+ git_odb_backend *backend,
611
+ const git_oid *short_oid,
612
+ unsigned int len)
613
+ {
614
+ if (len < GIT_OID_MINPREFIXLEN)
615
+ return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
616
+
617
+ if (len >= GIT_OID_HEXSZ) {
618
+ /* We can fall back to regular read method */
619
+ int error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
620
+ if (error == GIT_SUCCESS)
621
+ git_oid_cpy(out_oid, short_oid);
622
+
623
+ return error;
624
+ } else {
625
+ char object_path[GIT_PATH_MAX];
626
+ git_rawobj raw;
627
+ int error;
628
+
629
+ assert(backend && short_oid);
630
+
631
+ if ((error = locate_object_short_oid(object_path, out_oid, (loose_backend *)backend, short_oid, len)) < 0) {
632
+ return git__rethrow(error, "Failed to read loose backend");
633
+ }
634
+
635
+ if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
636
+ return git__rethrow(error, "Failed to read loose backend");
637
+
638
+ *buffer_p = raw.data;
639
+ *len_p = raw.len;
640
+ *type_p = raw.type;
641
+ }
642
+
643
+ return GIT_SUCCESS;
644
+ }
645
+
646
+ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
647
+ {
648
+ char object_path[GIT_PATH_MAX];
649
+
650
+ assert(backend && oid);
651
+
652
+ return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
653
+ }
654
+
655
+ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
656
+ {
657
+ loose_writestream *stream = (loose_writestream *)_stream;
658
+ loose_backend *backend = (loose_backend *)_stream->backend;
659
+
660
+ int error;
661
+ char final_path[GIT_PATH_MAX];
662
+
663
+ if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
664
+ return git__rethrow(error, "Failed to write loose backend");
665
+
666
+ if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
667
+ return GIT_ENOMEM;
668
+
669
+ if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
670
+ return git__rethrow(error, "Failed to write loose backend");
671
+
672
+ stream->finished = 1;
673
+
674
+ /*
675
+ * Don't try to add an existing object to the repository. This
676
+ * is what git does and allows us to sidestep the fact that
677
+ * we're not allowed to overwrite a read-only file on Windows.
678
+ */
679
+ if (git_futils_exists(final_path) == GIT_SUCCESS) {
680
+ git_filebuf_cleanup(&stream->fbuf);
681
+ return GIT_SUCCESS;
682
+ }
683
+
684
+ return git_filebuf_commit_at(&stream->fbuf, final_path, GIT_OBJECT_FILE_MODE);
685
+ }
686
+
687
+ static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
688
+ {
689
+ loose_writestream *stream = (loose_writestream *)_stream;
690
+ return git_filebuf_write(&stream->fbuf, data, len);
691
+ }
692
+
693
+ static void loose_backend__stream_free(git_odb_stream *_stream)
694
+ {
695
+ loose_writestream *stream = (loose_writestream *)_stream;
696
+
697
+ if (!stream->finished)
698
+ git_filebuf_cleanup(&stream->fbuf);
699
+
700
+ git__free(stream);
701
+ }
702
+
703
+ static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
704
+ {
705
+ const char *type_str = git_object_type2string(obj_type);
706
+ int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
707
+
708
+ assert(len > 0); /* otherwise snprintf() is broken */
709
+ assert(((size_t) len) < n); /* otherwise the caller is broken! */
710
+
711
+ if (len < 0 || ((size_t) len) >= n)
712
+ return git__throw(GIT_ERROR, "Failed to format object header. Length is out of bounds");
713
+ return len+1;
714
+ }
715
+
716
+ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
717
+ {
718
+ loose_backend *backend;
719
+ loose_writestream *stream;
720
+
721
+ char hdr[64], tmp_path[GIT_PATH_MAX];
722
+ int hdrlen;
723
+ int error;
724
+
725
+ assert(_backend);
726
+
727
+ backend = (loose_backend *)_backend;
728
+ *stream_out = NULL;
729
+
730
+ hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
731
+ if (hdrlen < GIT_SUCCESS)
732
+ return git__throw(GIT_EOBJCORRUPTED, "Failed to create loose backend stream. Object is corrupted");
733
+
734
+ stream = git__calloc(1, sizeof(loose_writestream));
735
+ if (stream == NULL)
736
+ return GIT_ENOMEM;
737
+
738
+ stream->stream.backend = _backend;
739
+ stream->stream.read = NULL; /* read only */
740
+ stream->stream.write = &loose_backend__stream_write;
741
+ stream->stream.finalize_write = &loose_backend__stream_fwrite;
742
+ stream->stream.free = &loose_backend__stream_free;
743
+ stream->stream.mode = GIT_STREAM_WRONLY;
744
+
745
+ git_path_join(tmp_path, backend->objects_dir, "tmp_object");
746
+
747
+ error = git_filebuf_open(&stream->fbuf, tmp_path,
748
+ GIT_FILEBUF_HASH_CONTENTS |
749
+ GIT_FILEBUF_TEMPORARY |
750
+ (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
751
+
752
+ if (error < GIT_SUCCESS) {
753
+ git__free(stream);
754
+ return git__rethrow(error, "Failed to create loose backend stream");
755
+ }
756
+
757
+ error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
758
+ if (error < GIT_SUCCESS) {
759
+ git_filebuf_cleanup(&stream->fbuf);
760
+ git__free(stream);
761
+ return git__rethrow(error, "Failed to create loose backend stream");
762
+ }
763
+
764
+ *stream_out = (git_odb_stream *)stream;
765
+ return GIT_SUCCESS;
766
+ }
767
+
768
+ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type)
769
+ {
770
+ int error, header_len;
771
+ char final_path[GIT_PATH_MAX], header[64];
772
+ git_filebuf fbuf = GIT_FILEBUF_INIT;
773
+ loose_backend *backend;
774
+
775
+ backend = (loose_backend *)_backend;
776
+
777
+ /* prepare the header for the file */
778
+ {
779
+ header_len = format_object_header(header, sizeof(header), len, type);
780
+ if (header_len < GIT_SUCCESS)
781
+ return GIT_EOBJCORRUPTED;
782
+ }
783
+
784
+ git_path_join(final_path, backend->objects_dir, "tmp_object");
785
+
786
+ error = git_filebuf_open(&fbuf, final_path,
787
+ GIT_FILEBUF_HASH_CONTENTS |
788
+ GIT_FILEBUF_TEMPORARY |
789
+ (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
790
+
791
+ if (error < GIT_SUCCESS)
792
+ return error;
793
+
794
+ git_filebuf_write(&fbuf, header, header_len);
795
+ git_filebuf_write(&fbuf, data, len);
796
+ git_filebuf_hash(oid, &fbuf);
797
+
798
+ if ((error = object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) < GIT_SUCCESS)
799
+ goto cleanup;
800
+
801
+ if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
802
+ goto cleanup;
803
+
804
+ return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE);
805
+
806
+ cleanup:
807
+ git_filebuf_cleanup(&fbuf);
808
+ return error;
809
+ }
810
+
811
+ static void loose_backend__free(git_odb_backend *_backend)
812
+ {
813
+ loose_backend *backend;
814
+ assert(_backend);
815
+ backend = (loose_backend *)_backend;
816
+
817
+ git__free(backend->objects_dir);
818
+ git__free(backend);
819
+ }
820
+
821
+ int git_odb_backend_loose(
822
+ git_odb_backend **backend_out,
823
+ const char *objects_dir,
824
+ int compression_level,
825
+ int do_fsync)
826
+ {
827
+ loose_backend *backend;
828
+
829
+ backend = git__calloc(1, sizeof(loose_backend));
830
+ if (backend == NULL)
831
+ return GIT_ENOMEM;
832
+
833
+ backend->objects_dir = git__strdup(objects_dir);
834
+ if (backend->objects_dir == NULL) {
835
+ git__free(backend);
836
+ return GIT_ENOMEM;
837
+ }
838
+
839
+ if (compression_level < 0)
840
+ compression_level = Z_BEST_SPEED;
841
+
842
+ backend->object_zlib_level = compression_level;
843
+ backend->fsync_object_files = do_fsync;
844
+
845
+ backend->parent.read = &loose_backend__read;
846
+ backend->parent.write = &loose_backend__write;
847
+ backend->parent.read_prefix = &loose_backend__read_prefix;
848
+ backend->parent.read_header = &loose_backend__read_header;
849
+ backend->parent.writestream = &loose_backend__stream;
850
+ backend->parent.exists = &loose_backend__exists;
851
+ backend->parent.free = &loose_backend__free;
852
+
853
+ *backend_out = (git_odb_backend *)backend;
854
+ return GIT_SUCCESS;
855
+ }