rugged 0.19.0 → 0.28.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (668) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/README.md +184 -33
  4. data/ext/rugged/extconf.rb +111 -28
  5. data/ext/rugged/rugged.c +327 -89
  6. data/ext/rugged/rugged.h +64 -28
  7. data/ext/rugged/rugged_allocator.c +89 -0
  8. data/ext/rugged/rugged_backend.c +17 -0
  9. data/ext/rugged/rugged_blame.c +278 -0
  10. data/ext/rugged/rugged_blob.c +301 -75
  11. data/ext/rugged/rugged_branch.c +92 -242
  12. data/ext/rugged/rugged_branch_collection.c +388 -0
  13. data/ext/rugged/rugged_commit.c +575 -79
  14. data/ext/rugged/rugged_config.c +129 -36
  15. data/ext/rugged/rugged_cred.c +131 -0
  16. data/ext/rugged/rugged_diff.c +291 -122
  17. data/ext/rugged/rugged_diff_delta.c +16 -22
  18. data/ext/rugged/rugged_diff_hunk.c +35 -51
  19. data/ext/rugged/rugged_diff_line.c +23 -36
  20. data/ext/rugged/rugged_index.c +289 -152
  21. data/ext/rugged/rugged_note.c +50 -60
  22. data/ext/rugged/rugged_object.c +13 -30
  23. data/ext/rugged/rugged_patch.c +400 -0
  24. data/ext/rugged/rugged_rebase.c +397 -0
  25. data/ext/rugged/rugged_reference.c +76 -346
  26. data/ext/rugged/rugged_reference_collection.c +423 -0
  27. data/ext/rugged/rugged_remote.c +438 -461
  28. data/ext/rugged/rugged_remote_collection.c +435 -0
  29. data/ext/rugged/rugged_repo.c +1548 -365
  30. data/ext/rugged/rugged_revwalk.c +378 -99
  31. data/ext/rugged/rugged_settings.c +86 -23
  32. data/ext/rugged/rugged_signature.c +47 -37
  33. data/ext/rugged/rugged_submodule.c +835 -0
  34. data/ext/rugged/rugged_submodule_collection.c +366 -0
  35. data/ext/rugged/rugged_tag.c +88 -210
  36. data/ext/rugged/rugged_tag_collection.c +326 -0
  37. data/ext/rugged/rugged_tree.c +460 -217
  38. data/lib/rugged/attributes.rb +46 -0
  39. data/lib/rugged/blob.rb +33 -0
  40. data/lib/rugged/branch.rb +12 -16
  41. data/lib/rugged/commit.rb +9 -0
  42. data/lib/rugged/console.rb +5 -0
  43. data/lib/rugged/credentials.rb +48 -0
  44. data/lib/rugged/diff/delta.rb +6 -2
  45. data/lib/rugged/diff/hunk.rb +9 -9
  46. data/lib/rugged/diff/line.rb +28 -5
  47. data/lib/rugged/diff.rb +7 -1
  48. data/lib/rugged/index.rb +120 -0
  49. data/lib/rugged/object.rb +5 -0
  50. data/lib/rugged/patch.rb +41 -0
  51. data/lib/rugged/reference.rb +6 -3
  52. data/lib/rugged/remote.rb +5 -9
  53. data/lib/rugged/repository.rb +126 -14
  54. data/lib/rugged/submodule_collection.rb +53 -0
  55. data/lib/rugged/tag.rb +45 -16
  56. data/lib/rugged/tree.rb +163 -1
  57. data/lib/rugged/version.rb +6 -1
  58. data/lib/rugged/walker.rb +5 -0
  59. data/lib/rugged.rb +16 -1
  60. data/vendor/libgit2/AUTHORS +77 -0
  61. data/vendor/libgit2/CMakeLists.txt +317 -0
  62. data/vendor/libgit2/COPYING +993 -0
  63. data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +30 -0
  64. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +29 -0
  65. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +96 -0
  66. data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +11 -0
  67. data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +26 -0
  68. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  69. data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
  70. data/vendor/libgit2/cmake/Modules/FindIconv.cmake +45 -0
  71. data/vendor/libgit2/cmake/Modules/FindPkgLibraries.cmake +28 -0
  72. data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +28 -0
  73. data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
  74. data/vendor/libgit2/cmake/Modules/FindmbedTLS.cmake +93 -0
  75. data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
  76. data/vendor/libgit2/deps/http-parser/CMakeLists.txt +5 -0
  77. data/vendor/libgit2/deps/http-parser/COPYING +23 -0
  78. data/vendor/libgit2/deps/http-parser/http_parser.c +5 -2
  79. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  80. data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
  81. data/vendor/libgit2/deps/regex/COPYING +502 -0
  82. data/vendor/libgit2/deps/regex/regex.c +10 -3
  83. data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
  84. data/vendor/libgit2/deps/winhttp/COPYING.GPL +993 -0
  85. data/vendor/libgit2/deps/winhttp/COPYING.LGPL +502 -0
  86. data/vendor/libgit2/deps/winhttp/urlmon.h +45 -0
  87. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -0
  88. data/vendor/libgit2/deps/winhttp/winhttp.h +594 -0
  89. data/vendor/libgit2/deps/winhttp/winhttp64.def +29 -0
  90. data/vendor/libgit2/deps/zlib/CMakeLists.txt +5 -0
  91. data/vendor/libgit2/deps/zlib/COPYING +27 -0
  92. data/vendor/libgit2/deps/zlib/adler32.c +51 -34
  93. data/vendor/libgit2/deps/zlib/crc32.c +61 -61
  94. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  95. data/vendor/libgit2/deps/zlib/deflate.c +681 -352
  96. data/vendor/libgit2/deps/zlib/deflate.h +25 -18
  97. data/vendor/libgit2/deps/zlib/gzguts.h +218 -0
  98. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  99. data/vendor/libgit2/deps/zlib/inffast.c +36 -53
  100. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  101. data/vendor/libgit2/deps/zlib/inflate.c +167 -86
  102. data/vendor/libgit2/deps/zlib/inflate.h +7 -4
  103. data/vendor/libgit2/deps/zlib/inftrees.c +24 -50
  104. data/vendor/libgit2/deps/zlib/trees.c +55 -96
  105. data/vendor/libgit2/deps/zlib/zconf.h +499 -19
  106. data/vendor/libgit2/deps/zlib/zlib.h +526 -227
  107. data/vendor/libgit2/deps/zlib/zutil.c +39 -32
  108. data/vendor/libgit2/deps/zlib/zutil.h +75 -78
  109. data/vendor/libgit2/include/git2/annotated_commit.h +125 -0
  110. data/vendor/libgit2/include/git2/apply.h +129 -0
  111. data/vendor/libgit2/include/git2/attr.h +36 -21
  112. data/vendor/libgit2/include/git2/blame.h +229 -0
  113. data/vendor/libgit2/include/git2/blob.h +81 -44
  114. data/vendor/libgit2/include/git2/branch.h +81 -42
  115. data/vendor/libgit2/include/git2/buffer.h +128 -0
  116. data/vendor/libgit2/include/git2/checkout.h +141 -67
  117. data/vendor/libgit2/include/git2/cherrypick.h +92 -0
  118. data/vendor/libgit2/include/git2/clone.h +157 -58
  119. data/vendor/libgit2/include/git2/commit.h +231 -12
  120. data/vendor/libgit2/include/git2/common.h +216 -30
  121. data/vendor/libgit2/include/git2/config.h +274 -48
  122. data/vendor/libgit2/include/git2/cred_helpers.h +4 -4
  123. data/vendor/libgit2/include/git2/deprecated.h +253 -0
  124. data/vendor/libgit2/include/git2/describe.h +189 -0
  125. data/vendor/libgit2/include/git2/diff.h +985 -575
  126. data/vendor/libgit2/include/git2/errors.h +93 -52
  127. data/vendor/libgit2/include/git2/filter.h +217 -0
  128. data/vendor/libgit2/include/git2/global.h +44 -0
  129. data/vendor/libgit2/include/git2/graph.h +17 -0
  130. data/vendor/libgit2/include/git2/ignore.h +2 -2
  131. data/vendor/libgit2/include/git2/index.h +269 -94
  132. data/vendor/libgit2/include/git2/indexer.h +44 -12
  133. data/vendor/libgit2/include/git2/mailmap.h +115 -0
  134. data/vendor/libgit2/include/git2/merge.h +501 -64
  135. data/vendor/libgit2/include/git2/message.h +52 -17
  136. data/vendor/libgit2/include/git2/net.h +11 -5
  137. data/vendor/libgit2/include/git2/notes.h +120 -16
  138. data/vendor/libgit2/include/git2/object.h +62 -23
  139. data/vendor/libgit2/include/git2/odb.h +140 -24
  140. data/vendor/libgit2/include/git2/odb_backend.h +56 -12
  141. data/vendor/libgit2/include/git2/oid.h +17 -18
  142. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  143. data/vendor/libgit2/include/git2/pack.h +86 -7
  144. data/vendor/libgit2/include/git2/patch.h +274 -0
  145. data/vendor/libgit2/include/git2/pathspec.h +280 -0
  146. data/vendor/libgit2/include/git2/proxy.h +96 -0
  147. data/vendor/libgit2/include/git2/rebase.h +323 -0
  148. data/vendor/libgit2/include/git2/reflog.h +12 -9
  149. data/vendor/libgit2/include/git2/refs.h +241 -46
  150. data/vendor/libgit2/include/git2/refspec.h +20 -4
  151. data/vendor/libgit2/include/git2/remote.h +636 -209
  152. data/vendor/libgit2/include/git2/repository.h +267 -57
  153. data/vendor/libgit2/include/git2/reset.h +36 -6
  154. data/vendor/libgit2/include/git2/revert.h +91 -0
  155. data/vendor/libgit2/include/git2/revparse.h +27 -16
  156. data/vendor/libgit2/include/git2/revwalk.h +78 -35
  157. data/vendor/libgit2/include/git2/signature.h +32 -5
  158. data/vendor/libgit2/include/git2/stash.h +160 -21
  159. data/vendor/libgit2/include/git2/status.h +92 -30
  160. data/vendor/libgit2/include/git2/submodule.h +226 -133
  161. data/vendor/libgit2/include/git2/sys/alloc.h +101 -0
  162. data/vendor/libgit2/include/git2/sys/commit.h +38 -4
  163. data/vendor/libgit2/include/git2/sys/config.h +68 -9
  164. data/vendor/libgit2/include/git2/sys/diff.h +94 -0
  165. data/vendor/libgit2/include/git2/sys/filter.h +332 -0
  166. data/vendor/libgit2/include/git2/sys/hashsig.h +106 -0
  167. data/vendor/libgit2/include/git2/sys/index.h +6 -5
  168. data/vendor/libgit2/include/git2/sys/mempack.h +86 -0
  169. data/vendor/libgit2/include/git2/sys/merge.h +182 -0
  170. data/vendor/libgit2/include/git2/sys/odb_backend.h +66 -28
  171. data/vendor/libgit2/include/git2/sys/openssl.h +38 -0
  172. data/vendor/libgit2/include/git2/sys/path.h +64 -0
  173. data/vendor/libgit2/include/git2/sys/refdb_backend.h +79 -19
  174. data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
  175. data/vendor/libgit2/include/git2/sys/refs.h +13 -2
  176. data/vendor/libgit2/include/git2/sys/repository.h +64 -1
  177. data/vendor/libgit2/include/git2/sys/stream.h +138 -0
  178. data/vendor/libgit2/include/git2/sys/time.h +31 -0
  179. data/vendor/libgit2/include/git2/sys/transport.h +439 -0
  180. data/vendor/libgit2/include/git2/tag.h +11 -2
  181. data/vendor/libgit2/include/git2/trace.h +1 -1
  182. data/vendor/libgit2/include/git2/transaction.h +121 -0
  183. data/vendor/libgit2/include/git2/transport.h +261 -292
  184. data/vendor/libgit2/include/git2/tree.h +111 -21
  185. data/vendor/libgit2/include/git2/types.h +244 -32
  186. data/vendor/libgit2/include/git2/version.h +5 -2
  187. data/vendor/libgit2/include/git2/worktree.h +255 -0
  188. data/vendor/libgit2/include/git2.h +50 -40
  189. data/vendor/libgit2/libgit2.pc.in +13 -0
  190. data/vendor/libgit2/src/CMakeLists.txt +525 -0
  191. data/vendor/libgit2/src/alloc.c +55 -0
  192. data/vendor/libgit2/src/alloc.h +40 -0
  193. data/vendor/libgit2/src/annotated_commit.c +228 -0
  194. data/vendor/libgit2/src/annotated_commit.h +52 -0
  195. data/vendor/libgit2/src/apply.c +855 -0
  196. data/vendor/libgit2/src/apply.h +25 -0
  197. data/vendor/libgit2/src/array.h +74 -16
  198. data/vendor/libgit2/src/attr.c +239 -408
  199. data/vendor/libgit2/src/attr.h +3 -33
  200. data/vendor/libgit2/src/attr_file.c +424 -156
  201. data/vendor/libgit2/src/attr_file.h +95 -23
  202. data/vendor/libgit2/src/attrcache.c +469 -0
  203. data/vendor/libgit2/src/attrcache.h +37 -5
  204. data/vendor/libgit2/src/bitvec.h +75 -0
  205. data/vendor/libgit2/src/blame.c +532 -0
  206. data/vendor/libgit2/src/blame.h +95 -0
  207. data/vendor/libgit2/src/blame_git.c +668 -0
  208. data/vendor/libgit2/src/blame_git.h +22 -0
  209. data/vendor/libgit2/src/blob.c +233 -129
  210. data/vendor/libgit2/src/blob.h +29 -1
  211. data/vendor/libgit2/src/branch.c +295 -197
  212. data/vendor/libgit2/src/branch.h +2 -0
  213. data/vendor/libgit2/src/buf_text.c +52 -27
  214. data/vendor/libgit2/src/buf_text.h +7 -7
  215. data/vendor/libgit2/src/buffer.c +609 -52
  216. data/vendor/libgit2/src/buffer.h +68 -23
  217. data/vendor/libgit2/src/cache.c +48 -51
  218. data/vendor/libgit2/src/cache.h +6 -4
  219. data/vendor/libgit2/src/cc-compat.h +35 -7
  220. data/vendor/libgit2/src/checkout.c +1827 -483
  221. data/vendor/libgit2/src/checkout.h +4 -1
  222. data/vendor/libgit2/src/cherrypick.c +230 -0
  223. data/vendor/libgit2/src/clone.c +338 -258
  224. data/vendor/libgit2/src/{compress.h → clone.h} +5 -5
  225. data/vendor/libgit2/src/commit.c +711 -124
  226. data/vendor/libgit2/src/commit.h +10 -3
  227. data/vendor/libgit2/src/commit_list.c +21 -14
  228. data/vendor/libgit2/src/commit_list.h +9 -3
  229. data/vendor/libgit2/src/common.h +153 -13
  230. data/vendor/libgit2/src/config.c +871 -242
  231. data/vendor/libgit2/src/config.h +58 -14
  232. data/vendor/libgit2/src/config_backend.h +84 -0
  233. data/vendor/libgit2/src/config_cache.c +44 -18
  234. data/vendor/libgit2/src/config_entries.c +259 -0
  235. data/vendor/libgit2/src/config_entries.h +23 -0
  236. data/vendor/libgit2/src/config_file.c +837 -1113
  237. data/vendor/libgit2/src/config_mem.c +224 -0
  238. data/vendor/libgit2/src/config_parse.c +558 -0
  239. data/vendor/libgit2/src/config_parse.h +64 -0
  240. data/vendor/libgit2/src/crlf.c +290 -195
  241. data/vendor/libgit2/src/date.c +35 -7
  242. data/vendor/libgit2/src/delta.c +275 -71
  243. data/vendor/libgit2/src/delta.h +80 -58
  244. data/vendor/libgit2/src/describe.c +893 -0
  245. data/vendor/libgit2/src/diff.c +330 -1128
  246. data/vendor/libgit2/src/diff.h +25 -67
  247. data/vendor/libgit2/src/diff_driver.c +225 -109
  248. data/vendor/libgit2/src/diff_driver.h +5 -2
  249. data/vendor/libgit2/src/diff_file.c +128 -103
  250. data/vendor/libgit2/src/diff_file.h +17 -12
  251. data/vendor/libgit2/src/diff_generate.c +1622 -0
  252. data/vendor/libgit2/src/diff_generate.h +128 -0
  253. data/vendor/libgit2/src/diff_parse.c +108 -0
  254. data/vendor/libgit2/src/diff_parse.h +20 -0
  255. data/vendor/libgit2/src/diff_print.c +578 -218
  256. data/vendor/libgit2/src/diff_stats.c +362 -0
  257. data/vendor/libgit2/src/diff_tform.c +429 -257
  258. data/vendor/libgit2/src/diff_tform.h +25 -0
  259. data/vendor/libgit2/src/diff_xdiff.c +143 -46
  260. data/vendor/libgit2/src/diff_xdiff.h +12 -5
  261. data/vendor/libgit2/src/errors.c +150 -34
  262. data/vendor/libgit2/src/features.h.in +37 -0
  263. data/vendor/libgit2/src/fetch.c +69 -46
  264. data/vendor/libgit2/src/fetch.h +6 -12
  265. data/vendor/libgit2/src/fetchhead.c +40 -33
  266. data/vendor/libgit2/src/fetchhead.h +5 -4
  267. data/vendor/libgit2/src/filebuf.c +163 -61
  268. data/vendor/libgit2/src/filebuf.h +13 -7
  269. data/vendor/libgit2/src/fileops.c +549 -407
  270. data/vendor/libgit2/src/fileops.h +97 -106
  271. data/vendor/libgit2/src/filter.c +989 -46
  272. data/vendor/libgit2/src/filter.h +21 -70
  273. data/vendor/libgit2/src/fnmatch.c +67 -11
  274. data/vendor/libgit2/src/fnmatch.h +27 -7
  275. data/vendor/libgit2/src/global.c +257 -63
  276. data/vendor/libgit2/src/global.h +19 -0
  277. data/vendor/libgit2/src/graph.c +39 -23
  278. data/vendor/libgit2/src/hash/hash_collisiondetect.h +51 -0
  279. data/vendor/libgit2/src/hash/hash_common_crypto.h +61 -0
  280. data/vendor/libgit2/src/hash/hash_generic.c +3 -3
  281. data/vendor/libgit2/src/hash/hash_generic.h +10 -5
  282. data/vendor/libgit2/src/hash/hash_mbedtls.c +38 -0
  283. data/vendor/libgit2/src/hash/hash_mbedtls.h +24 -0
  284. data/vendor/libgit2/src/hash/hash_openssl.h +26 -8
  285. data/vendor/libgit2/src/hash/hash_win32.c +71 -43
  286. data/vendor/libgit2/src/hash/hash_win32.h +4 -3
  287. data/vendor/libgit2/src/hash/sha1dc/sha1.c +1900 -0
  288. data/vendor/libgit2/src/hash/sha1dc/sha1.h +110 -0
  289. data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +372 -0
  290. data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +52 -0
  291. data/vendor/libgit2/src/hash.c +0 -1
  292. data/vendor/libgit2/src/hash.h +13 -6
  293. data/vendor/libgit2/src/hashsig.c +121 -126
  294. data/vendor/libgit2/src/ident.c +129 -0
  295. data/vendor/libgit2/src/idxmap.c +153 -0
  296. data/vendor/libgit2/src/idxmap.h +41 -0
  297. data/vendor/libgit2/src/ignore.c +362 -123
  298. data/vendor/libgit2/src/ignore.h +16 -4
  299. data/vendor/libgit2/src/index.c +2131 -692
  300. data/vendor/libgit2/src/index.h +138 -6
  301. data/vendor/libgit2/src/indexer.c +866 -266
  302. data/vendor/libgit2/src/indexer.h +16 -0
  303. data/vendor/libgit2/src/integer.h +106 -0
  304. data/vendor/libgit2/src/iterator.c +1888 -967
  305. data/vendor/libgit2/src/iterator.h +130 -67
  306. data/vendor/libgit2/src/khash.h +43 -29
  307. data/vendor/libgit2/src/mailmap.c +485 -0
  308. data/vendor/libgit2/src/mailmap.h +35 -0
  309. data/vendor/libgit2/src/map.h +1 -1
  310. data/vendor/libgit2/src/merge.c +1679 -479
  311. data/vendor/libgit2/src/merge.h +89 -22
  312. data/vendor/libgit2/src/merge_driver.c +426 -0
  313. data/vendor/libgit2/src/merge_driver.h +62 -0
  314. data/vendor/libgit2/src/merge_file.c +238 -101
  315. data/vendor/libgit2/src/message.c +4 -28
  316. data/vendor/libgit2/src/message.h +3 -1
  317. data/vendor/libgit2/src/mwindow.c +123 -15
  318. data/vendor/libgit2/src/mwindow.h +10 -1
  319. data/vendor/libgit2/src/netops.c +178 -499
  320. data/vendor/libgit2/src/netops.h +51 -27
  321. data/vendor/libgit2/src/notes.c +251 -94
  322. data/vendor/libgit2/src/notes.h +5 -2
  323. data/vendor/libgit2/src/object.c +253 -67
  324. data/vendor/libgit2/src/object.h +40 -2
  325. data/vendor/libgit2/src/object_api.c +30 -11
  326. data/vendor/libgit2/src/odb.c +765 -201
  327. data/vendor/libgit2/src/odb.h +40 -8
  328. data/vendor/libgit2/src/odb_loose.c +560 -346
  329. data/vendor/libgit2/src/odb_mempack.c +185 -0
  330. data/vendor/libgit2/src/odb_pack.c +117 -73
  331. data/vendor/libgit2/src/offmap.c +113 -0
  332. data/vendor/libgit2/src/offmap.h +32 -42
  333. data/vendor/libgit2/src/oid.c +45 -25
  334. data/vendor/libgit2/src/oid.h +26 -8
  335. data/vendor/libgit2/src/oidarray.c +34 -0
  336. data/vendor/libgit2/src/oidarray.h +20 -0
  337. data/vendor/libgit2/src/oidmap.c +125 -0
  338. data/vendor/libgit2/src/oidmap.h +30 -17
  339. data/vendor/libgit2/src/pack-objects.c +688 -265
  340. data/vendor/libgit2/src/pack-objects.h +27 -13
  341. data/vendor/libgit2/src/pack.c +418 -202
  342. data/vendor/libgit2/src/pack.h +25 -16
  343. data/vendor/libgit2/src/parse.c +124 -0
  344. data/vendor/libgit2/src/parse.h +61 -0
  345. data/vendor/libgit2/src/patch.c +223 -0
  346. data/vendor/libgit2/src/patch.h +68 -0
  347. data/vendor/libgit2/src/patch_generate.c +901 -0
  348. data/vendor/libgit2/src/patch_generate.h +69 -0
  349. data/vendor/libgit2/src/patch_parse.c +1136 -0
  350. data/vendor/libgit2/src/patch_parse.h +51 -0
  351. data/vendor/libgit2/src/path.c +1247 -241
  352. data/vendor/libgit2/src/path.h +353 -57
  353. data/vendor/libgit2/src/pathspec.c +586 -58
  354. data/vendor/libgit2/src/pathspec.h +37 -15
  355. data/vendor/libgit2/src/pool.c +134 -221
  356. data/vendor/libgit2/src/pool.h +38 -50
  357. data/vendor/libgit2/src/posix.c +76 -10
  358. data/vendor/libgit2/src/posix.h +74 -32
  359. data/vendor/libgit2/src/pqueue.c +79 -117
  360. data/vendor/libgit2/src/pqueue.h +38 -82
  361. data/vendor/libgit2/src/proxy.c +39 -0
  362. data/vendor/libgit2/src/proxy.h +17 -0
  363. data/vendor/libgit2/src/push.c +178 -279
  364. data/vendor/libgit2/src/push.h +93 -4
  365. data/vendor/libgit2/src/reader.c +265 -0
  366. data/vendor/libgit2/src/reader.h +107 -0
  367. data/vendor/libgit2/src/rebase.c +1364 -0
  368. data/vendor/libgit2/src/refdb.c +74 -19
  369. data/vendor/libgit2/src/refdb.h +16 -3
  370. data/vendor/libgit2/src/refdb_fs.c +1472 -603
  371. data/vendor/libgit2/src/refdb_fs.h +4 -0
  372. data/vendor/libgit2/src/reflog.c +40 -330
  373. data/vendor/libgit2/src/reflog.h +8 -2
  374. data/vendor/libgit2/src/refs.c +641 -225
  375. data/vendor/libgit2/src/refs.h +53 -6
  376. data/vendor/libgit2/src/refspec.c +175 -62
  377. data/vendor/libgit2/src/refspec.h +10 -25
  378. data/vendor/libgit2/src/remote.c +1741 -723
  379. data/vendor/libgit2/src/remote.h +17 -5
  380. data/vendor/libgit2/src/repository.c +1505 -421
  381. data/vendor/libgit2/src/repository.h +95 -15
  382. data/vendor/libgit2/src/reset.c +63 -26
  383. data/vendor/libgit2/src/revert.c +232 -0
  384. data/vendor/libgit2/src/revparse.c +94 -80
  385. data/vendor/libgit2/src/revwalk.c +427 -194
  386. data/vendor/libgit2/src/revwalk.h +14 -5
  387. data/vendor/libgit2/src/settings.c +290 -0
  388. data/vendor/libgit2/src/sha1_lookup.c +16 -159
  389. data/vendor/libgit2/src/sha1_lookup.h +5 -4
  390. data/vendor/libgit2/src/signature.c +138 -26
  391. data/vendor/libgit2/src/signature.h +5 -0
  392. data/vendor/libgit2/src/sortedcache.c +395 -0
  393. data/vendor/libgit2/src/sortedcache.h +180 -0
  394. data/vendor/libgit2/src/stash.c +629 -168
  395. data/vendor/libgit2/src/status.c +125 -75
  396. data/vendor/libgit2/src/status.h +4 -2
  397. data/vendor/libgit2/src/stdalloc.c +120 -0
  398. data/vendor/libgit2/src/stdalloc.h +17 -0
  399. data/vendor/libgit2/src/stream.h +86 -0
  400. data/vendor/libgit2/src/streams/mbedtls.c +483 -0
  401. data/vendor/libgit2/src/streams/mbedtls.h +23 -0
  402. data/vendor/libgit2/src/streams/openssl.c +789 -0
  403. data/vendor/libgit2/src/streams/openssl.h +23 -0
  404. data/vendor/libgit2/src/streams/registry.c +118 -0
  405. data/vendor/libgit2/src/streams/registry.h +19 -0
  406. data/vendor/libgit2/src/streams/socket.c +235 -0
  407. data/vendor/libgit2/src/streams/socket.h +23 -0
  408. data/vendor/libgit2/src/streams/stransport.c +323 -0
  409. data/vendor/libgit2/src/streams/stransport.h +21 -0
  410. data/vendor/libgit2/src/streams/tls.c +73 -0
  411. data/vendor/libgit2/src/streams/tls.h +31 -0
  412. data/vendor/libgit2/src/strmap.c +147 -0
  413. data/vendor/libgit2/src/strmap.h +46 -51
  414. data/vendor/libgit2/src/strnlen.h +24 -0
  415. data/vendor/libgit2/src/submodule.c +1633 -877
  416. data/vendor/libgit2/src/submodule.h +83 -21
  417. data/vendor/libgit2/src/sysdir.c +355 -0
  418. data/vendor/libgit2/src/sysdir.h +119 -0
  419. data/vendor/libgit2/src/tag.c +87 -62
  420. data/vendor/libgit2/src/tag.h +4 -1
  421. data/vendor/libgit2/src/thread-utils.c +3 -0
  422. data/vendor/libgit2/src/thread-utils.h +71 -35
  423. data/vendor/libgit2/src/trace.c +4 -4
  424. data/vendor/libgit2/src/trace.h +11 -3
  425. data/vendor/libgit2/src/trailer.c +416 -0
  426. data/vendor/libgit2/src/transaction.c +382 -0
  427. data/vendor/libgit2/src/transaction.h +14 -0
  428. data/vendor/libgit2/src/transport.c +133 -67
  429. data/vendor/libgit2/src/transports/auth.c +75 -0
  430. data/vendor/libgit2/src/transports/auth.h +64 -0
  431. data/vendor/libgit2/src/transports/auth_negotiate.c +277 -0
  432. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  433. data/vendor/libgit2/src/transports/cred.c +296 -68
  434. data/vendor/libgit2/src/transports/cred.h +16 -0
  435. data/vendor/libgit2/src/transports/cred_helpers.c +4 -0
  436. data/vendor/libgit2/src/transports/git.c +108 -90
  437. data/vendor/libgit2/src/transports/http.c +803 -258
  438. data/vendor/libgit2/src/transports/http.h +25 -0
  439. data/vendor/libgit2/src/transports/local.c +265 -169
  440. data/vendor/libgit2/src/transports/smart.c +255 -45
  441. data/vendor/libgit2/src/transports/smart.h +42 -22
  442. data/vendor/libgit2/src/transports/smart_pkt.c +250 -159
  443. data/vendor/libgit2/src/transports/smart_protocol.c +414 -196
  444. data/vendor/libgit2/src/transports/ssh.c +645 -236
  445. data/vendor/libgit2/src/transports/ssh.h +14 -0
  446. data/vendor/libgit2/src/transports/winhttp.c +809 -353
  447. data/vendor/libgit2/src/tree-cache.c +138 -52
  448. data/vendor/libgit2/src/tree-cache.h +14 -7
  449. data/vendor/libgit2/src/tree.c +620 -259
  450. data/vendor/libgit2/src/tree.h +12 -19
  451. data/vendor/libgit2/src/tsort.c +3 -2
  452. data/vendor/libgit2/src/unix/map.c +25 -7
  453. data/vendor/libgit2/src/unix/posix.h +77 -12
  454. data/vendor/libgit2/src/unix/pthread.h +56 -0
  455. data/vendor/libgit2/src/unix/realpath.c +12 -8
  456. data/vendor/libgit2/src/userdiff.h +208 -0
  457. data/vendor/libgit2/src/util.c +349 -165
  458. data/vendor/libgit2/src/util.h +167 -85
  459. data/vendor/libgit2/src/varint.c +43 -0
  460. data/vendor/libgit2/src/varint.h +17 -0
  461. data/vendor/libgit2/src/vector.c +156 -33
  462. data/vendor/libgit2/src/vector.h +41 -5
  463. data/vendor/libgit2/src/win32/dir.c +22 -42
  464. data/vendor/libgit2/src/win32/dir.h +7 -5
  465. data/vendor/libgit2/src/win32/error.c +6 -32
  466. data/vendor/libgit2/src/win32/error.h +4 -2
  467. data/vendor/libgit2/src/win32/findfile.c +62 -69
  468. data/vendor/libgit2/src/win32/findfile.h +5 -13
  469. data/vendor/libgit2/src/win32/git2.rc +44 -0
  470. data/vendor/libgit2/src/win32/map.c +39 -11
  471. data/vendor/libgit2/src/win32/mingw-compat.h +10 -11
  472. data/vendor/libgit2/src/win32/msvc-compat.h +10 -33
  473. data/vendor/libgit2/src/win32/path_w32.c +476 -0
  474. data/vendor/libgit2/src/win32/path_w32.h +104 -0
  475. data/vendor/libgit2/src/win32/posix.h +35 -30
  476. data/vendor/libgit2/src/win32/posix_w32.c +659 -327
  477. data/vendor/libgit2/src/win32/precompiled.h +7 -2
  478. data/vendor/libgit2/src/win32/reparse.h +57 -0
  479. data/vendor/libgit2/src/win32/thread.c +258 -0
  480. data/vendor/libgit2/src/win32/thread.h +64 -0
  481. data/vendor/libgit2/src/win32/utf-conv.c +127 -62
  482. data/vendor/libgit2/src/win32/utf-conv.h +47 -6
  483. data/vendor/libgit2/src/win32/version.h +21 -4
  484. data/vendor/libgit2/src/win32/w32_buffer.c +54 -0
  485. data/vendor/libgit2/src/win32/w32_buffer.h +20 -0
  486. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +438 -0
  487. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +129 -0
  488. data/vendor/libgit2/src/win32/w32_stack.c +193 -0
  489. data/vendor/libgit2/src/win32/w32_stack.h +140 -0
  490. data/vendor/libgit2/src/win32/w32_util.c +95 -0
  491. data/vendor/libgit2/src/win32/w32_util.h +170 -0
  492. data/vendor/libgit2/src/win32/win32-compat.h +52 -0
  493. data/vendor/libgit2/src/worktree.c +578 -0
  494. data/vendor/libgit2/src/worktree.h +39 -0
  495. data/vendor/libgit2/src/xdiff/xdiff.h +33 -18
  496. data/vendor/libgit2/src/xdiff/xdiffi.c +578 -88
  497. data/vendor/libgit2/src/xdiff/xdiffi.h +3 -2
  498. data/vendor/libgit2/src/xdiff/xemit.c +106 -45
  499. data/vendor/libgit2/src/xdiff/xemit.h +3 -3
  500. data/vendor/libgit2/src/xdiff/xhistogram.c +5 -4
  501. data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
  502. data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
  503. data/vendor/libgit2/src/xdiff/xmerge.c +167 -48
  504. data/vendor/libgit2/src/xdiff/xpatience.c +42 -10
  505. data/vendor/libgit2/src/xdiff/xprepare.c +14 -14
  506. data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
  507. data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
  508. data/vendor/libgit2/src/xdiff/xutils.c +60 -56
  509. data/vendor/libgit2/src/xdiff/xutils.h +3 -5
  510. data/vendor/libgit2/src/zstream.c +205 -0
  511. data/vendor/libgit2/src/zstream.h +53 -0
  512. metadata +281 -233
  513. data/Rakefile +0 -61
  514. data/ext/rugged/rugged_diff_patch.c +0 -169
  515. data/lib/rugged/diff/patch.rb +0 -28
  516. data/test/blob_test.rb +0 -341
  517. data/test/branch_test.rb +0 -199
  518. data/test/commit_test.rb +0 -104
  519. data/test/config_test.rb +0 -45
  520. data/test/coverage/cover.rb +0 -133
  521. data/test/diff_test.rb +0 -777
  522. data/test/errors_test.rb +0 -34
  523. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  524. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  525. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  526. data/test/fixtures/archive.tar.gz +0 -0
  527. data/test/fixtures/attr/attr0 +0 -1
  528. data/test/fixtures/attr/attr1 +0 -29
  529. data/test/fixtures/attr/attr2 +0 -21
  530. data/test/fixtures/attr/attr3 +0 -4
  531. data/test/fixtures/attr/binfile +0 -1
  532. data/test/fixtures/attr/dir/file +0 -0
  533. data/test/fixtures/attr/file +0 -1
  534. data/test/fixtures/attr/gitattributes +0 -29
  535. data/test/fixtures/attr/gitignore +0 -2
  536. data/test/fixtures/attr/ign +0 -1
  537. data/test/fixtures/attr/macro_bad +0 -1
  538. data/test/fixtures/attr/macro_test +0 -1
  539. data/test/fixtures/attr/root_test1 +0 -1
  540. data/test/fixtures/attr/root_test2 +0 -6
  541. data/test/fixtures/attr/root_test3 +0 -19
  542. data/test/fixtures/attr/root_test4.txt +0 -14
  543. data/test/fixtures/attr/sub/abc +0 -37
  544. data/test/fixtures/attr/sub/dir/file +0 -0
  545. data/test/fixtures/attr/sub/file +0 -1
  546. data/test/fixtures/attr/sub/ign/file +0 -1
  547. data/test/fixtures/attr/sub/ign/sub/file +0 -1
  548. data/test/fixtures/attr/sub/sub/dir +0 -0
  549. data/test/fixtures/attr/sub/sub/file +0 -1
  550. data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
  551. data/test/fixtures/attr/sub/subdir_test1 +0 -2
  552. data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
  553. data/test/fixtures/diff/another.txt +0 -38
  554. data/test/fixtures/diff/readme.txt +0 -36
  555. data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
  556. data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
  557. data/test/fixtures/mergedrepo/one.txt +0 -10
  558. data/test/fixtures/mergedrepo/two.txt +0 -12
  559. data/test/fixtures/status/current_file +0 -1
  560. data/test/fixtures/status/ignored_file +0 -1
  561. data/test/fixtures/status/modified_file +0 -2
  562. data/test/fixtures/status/new_file +0 -1
  563. data/test/fixtures/status/staged_changes +0 -2
  564. data/test/fixtures/status/staged_changes_modified_file +0 -3
  565. data/test/fixtures/status/staged_delete_modified_file +0 -1
  566. data/test/fixtures/status/staged_new_file +0 -1
  567. data/test/fixtures/status/staged_new_file_modified_file +0 -2
  568. data/test/fixtures/status/subdir/current_file +0 -1
  569. data/test/fixtures/status/subdir/modified_file +0 -2
  570. data/test/fixtures/status/subdir/new_file +0 -1
  571. data/test/fixtures/status/subdir.txt +0 -2
  572. data/test/fixtures/status//350/277/231 +0 -1
  573. data/test/fixtures/testrepo.git/HEAD +0 -1
  574. data/test/fixtures/testrepo.git/config +0 -13
  575. data/test/fixtures/testrepo.git/description +0 -1
  576. data/test/fixtures/testrepo.git/index +0 -0
  577. data/test/fixtures/testrepo.git/info/exclude +0 -6
  578. data/test/fixtures/testrepo.git/logs/HEAD +0 -3
  579. data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
  580. data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
  581. data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
  582. data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
  583. data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
  584. data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
  585. data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
  586. data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
  587. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
  588. data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
  589. data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
  590. data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
  591. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  592. data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
  593. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
  594. data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
  595. data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
  596. data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
  597. data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -0
  598. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  599. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  600. data/test/fixtures/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
  601. data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
  602. data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
  603. data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
  604. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
  605. data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
  606. data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
  607. data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
  608. data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  609. data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
  610. data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
  611. data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
  612. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
  613. data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
  614. data/test/fixtures/testrepo.git/packed-refs +0 -2
  615. data/test/fixtures/testrepo.git/refs/heads/master +0 -1
  616. data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
  617. data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
  618. data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
  619. data/test/fixtures/text_file.md +0 -464
  620. data/test/fixtures/unsymlinked.git/HEAD +0 -1
  621. data/test/fixtures/unsymlinked.git/config +0 -6
  622. data/test/fixtures/unsymlinked.git/description +0 -1
  623. data/test/fixtures/unsymlinked.git/info/exclude +0 -2
  624. data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
  625. data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
  626. data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
  627. data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
  628. data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
  629. data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
  630. data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
  631. data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
  632. data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
  633. data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
  634. data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
  635. data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
  636. data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
  637. data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
  638. data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
  639. data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
  640. data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
  641. data/test/index_test.rb +0 -333
  642. data/test/lib_test.rb +0 -127
  643. data/test/note_test.rb +0 -158
  644. data/test/object_test.rb +0 -43
  645. data/test/reference_test.rb +0 -207
  646. data/test/remote_test.rb +0 -324
  647. data/test/repo_pack_test.rb +0 -24
  648. data/test/repo_reset_test.rb +0 -82
  649. data/test/repo_test.rb +0 -402
  650. data/test/tag_test.rb +0 -68
  651. data/test/test_helper.rb +0 -92
  652. data/test/tree_test.rb +0 -91
  653. data/test/walker_test.rb +0 -88
  654. data/vendor/libgit2/Makefile.embed +0 -42
  655. data/vendor/libgit2/include/git2/push.h +0 -131
  656. data/vendor/libgit2/include/git2/threads.h +0 -50
  657. data/vendor/libgit2/src/amiga/map.c +0 -48
  658. data/vendor/libgit2/src/bswap.h +0 -97
  659. data/vendor/libgit2/src/compress.c +0 -53
  660. data/vendor/libgit2/src/config_file.h +0 -60
  661. data/vendor/libgit2/src/delta-apply.c +0 -134
  662. data/vendor/libgit2/src/delta-apply.h +0 -50
  663. data/vendor/libgit2/src/diff_patch.c +0 -995
  664. data/vendor/libgit2/src/diff_patch.h +0 -46
  665. data/vendor/libgit2/src/hashsig.h +0 -72
  666. data/vendor/libgit2/src/merge_file.h +0 -71
  667. data/vendor/libgit2/src/win32/pthread.c +0 -144
  668. data/vendor/libgit2/src/win32/pthread.h +0 -50
@@ -4,16 +4,19 @@
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
- #include "common.h"
7
+
8
8
  #include "path.h"
9
+
9
10
  #include "posix.h"
11
+ #include "repository.h"
10
12
  #ifdef GIT_WIN32
11
- #include "win32/dir.h"
12
13
  #include "win32/posix.h"
14
+ #include "win32/w32_buffer.h"
15
+ #include "win32/w32_util.h"
16
+ #include "win32/version.h"
13
17
  #else
14
18
  #include <dirent.h>
15
19
  #endif
16
- #include <stdarg.h>
17
20
  #include <stdio.h>
18
21
  #include <ctype.h>
19
22
 
@@ -108,6 +111,34 @@ Exit:
108
111
  return result;
109
112
  }
110
113
 
114
+ /*
115
+ * Determine if the path is a Windows prefix and, if so, returns
116
+ * its actual lentgh. If it is not a prefix, returns -1.
117
+ */
118
+ static int win32_prefix_length(const char *path, int len)
119
+ {
120
+ #ifndef GIT_WIN32
121
+ GIT_UNUSED(path);
122
+ GIT_UNUSED(len);
123
+ #else
124
+ /*
125
+ * Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
126
+ * 'C:/' here
127
+ */
128
+ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path))
129
+ return 2;
130
+
131
+ /*
132
+ * Similarly checks if we're dealing with a network computer name
133
+ * '//computername/.git' will return '//computername/'
134
+ */
135
+ if (looks_like_network_computer_name(path, len))
136
+ return len;
137
+ #endif
138
+
139
+ return -1;
140
+ }
141
+
111
142
  /*
112
143
  * Based on the Android implementation, BSD licensed.
113
144
  * Check http://android.git.kernel.org/
@@ -115,7 +146,7 @@ Exit:
115
146
  int git_path_dirname_r(git_buf *buffer, const char *path)
116
147
  {
117
148
  const char *endp;
118
- int result, len;
149
+ int is_prefix = 0, len;
119
150
 
120
151
  /* Empty or NULL string gets treated as "." */
121
152
  if (path == NULL || *path == '\0') {
@@ -129,6 +160,11 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
129
160
  while (endp > path && *endp == '/')
130
161
  endp--;
131
162
 
163
+ if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
164
+ is_prefix = 1;
165
+ goto Exit;
166
+ }
167
+
132
168
  /* Find the start of the dir */
133
169
  while (endp > path && *endp != '/')
134
170
  endp--;
@@ -144,35 +180,23 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
144
180
  endp--;
145
181
  } while (endp > path && *endp == '/');
146
182
 
147
- /* Cast is safe because max path < max int */
148
- len = (int)(endp - path + 1);
149
-
150
- #ifdef GIT_WIN32
151
- /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
152
- 'C:/' here */
153
-
154
- if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) {
155
- len = 3;
156
- goto Exit;
157
- }
158
-
159
- /* Similarly checks if we're dealing with a network computer name
160
- '//computername/.git' will return '//computername/' */
161
-
162
- if (looks_like_network_computer_name(path, len)) {
163
- len++;
183
+ if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
184
+ is_prefix = 1;
164
185
  goto Exit;
165
186
  }
166
187
 
167
- #endif
188
+ /* Cast is safe because max path < max int */
189
+ len = (int)(endp - path + 1);
168
190
 
169
191
  Exit:
170
- result = len;
171
-
172
- if (buffer != NULL && git_buf_set(buffer, path, len) < 0)
173
- return -1;
192
+ if (buffer) {
193
+ if (git_buf_set(buffer, path, len) < 0)
194
+ return -1;
195
+ if (is_prefix && git_buf_putc(buffer, '/') < 0)
196
+ return -1;
197
+ }
174
198
 
175
- return result;
199
+ return len;
176
200
  }
177
201
 
178
202
 
@@ -183,7 +207,7 @@ char *git_path_dirname(const char *path)
183
207
 
184
208
  git_path_dirname_r(&buf, path);
185
209
  dirname = git_buf_detach(&buf);
186
- git_buf_free(&buf); /* avoid memleak if error occurs */
210
+ git_buf_dispose(&buf); /* avoid memleak if error occurs */
187
211
 
188
212
  return dirname;
189
213
  }
@@ -195,7 +219,7 @@ char *git_path_basename(const char *path)
195
219
 
196
220
  git_path_basename_r(&buf, path);
197
221
  basename = git_buf_detach(&buf);
198
- git_buf_free(&buf); /* avoid memleak if error occurs */
222
+ git_buf_dispose(&buf); /* avoid memleak if error occurs */
199
223
 
200
224
  return basename;
201
225
  }
@@ -243,8 +267,8 @@ int git_path_root(const char *path)
243
267
 
244
268
  #ifdef GIT_WIN32
245
269
  /* Are we dealing with a windows network path? */
246
- else if ((path[0] == '/' && path[1] == '/') ||
247
- (path[0] == '\\' && path[1] == '\\'))
270
+ else if ((path[0] == '/' && path[1] == '/' && path[2] != '/') ||
271
+ (path[0] == '\\' && path[1] == '\\' && path[2] != '\\'))
248
272
  {
249
273
  offset += 2;
250
274
 
@@ -260,29 +284,67 @@ int git_path_root(const char *path)
260
284
  return -1; /* Not a real error - signals that path is not rooted */
261
285
  }
262
286
 
287
+ void git_path_trim_slashes(git_buf *path)
288
+ {
289
+ int ceiling = git_path_root(path->ptr) + 1;
290
+ assert(ceiling >= 0);
291
+
292
+ while (path->size > (size_t)ceiling) {
293
+ if (path->ptr[path->size-1] != '/')
294
+ break;
295
+
296
+ path->ptr[path->size-1] = '\0';
297
+ path->size--;
298
+ }
299
+ }
300
+
263
301
  int git_path_join_unrooted(
264
302
  git_buf *path_out, const char *path, const char *base, ssize_t *root_at)
265
303
  {
266
- int error, root;
304
+ ssize_t root;
267
305
 
268
306
  assert(path && path_out);
269
307
 
270
- root = git_path_root(path);
308
+ root = (ssize_t)git_path_root(path);
271
309
 
272
310
  if (base != NULL && root < 0) {
273
- error = git_buf_joinpath(path_out, base, path);
311
+ if (git_buf_joinpath(path_out, base, path) < 0)
312
+ return -1;
313
+
314
+ root = (ssize_t)strlen(base);
315
+ } else {
316
+ if (git_buf_sets(path_out, path) < 0)
317
+ return -1;
274
318
 
275
- if (root_at)
276
- *root_at = (ssize_t)strlen(base);
319
+ if (root < 0)
320
+ root = 0;
321
+ else if (base)
322
+ git_path_equal_or_prefixed(base, path, &root);
277
323
  }
278
- else {
279
- error = git_buf_sets(path_out, path);
280
324
 
281
- if (root_at)
282
- *root_at = (root < 0) ? 0 : (ssize_t)root;
325
+ if (root_at)
326
+ *root_at = root;
327
+
328
+ return 0;
329
+ }
330
+
331
+ void git_path_squash_slashes(git_buf *path)
332
+ {
333
+ char *p, *q;
334
+
335
+ if (path->size == 0)
336
+ return;
337
+
338
+ for (p = path->ptr, q = path->ptr; *q; p++, q++) {
339
+ *p = *q;
340
+
341
+ while (*q == '/' && *(q+1) == '/') {
342
+ path->size--;
343
+ q++;
344
+ }
283
345
  }
284
346
 
285
- return error;
347
+ *p = '\0';
286
348
  }
287
349
 
288
350
  int git_path_prettify(git_buf *path_out, const char *path, const char *base)
@@ -299,9 +361,9 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
299
361
  }
300
362
 
301
363
  if (p_realpath(path, buf) == NULL) {
302
- /* giterr_set resets the errno when dealing with a GITERR_OS kind of error */
364
+ /* git_error_set resets the errno when dealing with a GIT_ERROR_OS kind of error */
303
365
  int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1;
304
- giterr_set(GITERR_OS, "Failed to resolve path '%s'", path);
366
+ git_error_set(GIT_ERROR_OS, "failed to resolve path '%s'", path);
305
367
 
306
368
  git_buf_clear(path_out);
307
369
 
@@ -374,30 +436,37 @@ append:
374
436
 
375
437
  static int error_invalid_local_file_uri(const char *uri)
376
438
  {
377
- giterr_set(GITERR_CONFIG, "'%s' is not a valid local file URI", uri);
439
+ git_error_set(GIT_ERROR_CONFIG, "'%s' is not a valid local file URI", uri);
378
440
  return -1;
379
441
  }
380
442
 
381
- int git_path_fromurl(git_buf *local_path_out, const char *file_url)
443
+ static int local_file_url_prefixlen(const char *file_url)
382
444
  {
383
- int offset = 0, len;
445
+ int len = -1;
384
446
 
385
- assert(local_path_out && file_url);
447
+ if (git__prefixcmp(file_url, "file://") == 0) {
448
+ if (file_url[7] == '/')
449
+ len = 8;
450
+ else if (git__prefixcmp(file_url + 7, "localhost/") == 0)
451
+ len = 17;
452
+ }
386
453
 
387
- if (git__prefixcmp(file_url, "file://") != 0)
388
- return error_invalid_local_file_uri(file_url);
454
+ return len;
455
+ }
389
456
 
390
- offset += 7;
391
- len = (int)strlen(file_url);
457
+ bool git_path_is_local_file_url(const char *file_url)
458
+ {
459
+ return (local_file_url_prefixlen(file_url) > 0);
460
+ }
392
461
 
393
- if (offset < len && file_url[offset] == '/')
394
- offset++;
395
- else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0)
396
- offset += 10;
397
- else
398
- return error_invalid_local_file_uri(file_url);
462
+ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
463
+ {
464
+ int offset;
465
+
466
+ assert(local_path_out && file_url);
399
467
 
400
- if (offset >= len || file_url[offset] == '/')
468
+ if ((offset = local_file_url_prefixlen(file_url)) < 0 ||
469
+ file_url[offset] == '\0' || file_url[offset] == '/')
401
470
  return error_invalid_local_file_uri(file_url);
402
471
 
403
472
  #ifndef GIT_WIN32
@@ -405,14 +474,13 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
405
474
  #endif
406
475
 
407
476
  git_buf_clear(local_path_out);
408
-
409
477
  return git__percent_decode(local_path_out, file_url + offset);
410
478
  }
411
479
 
412
480
  int git_path_walk_up(
413
481
  git_buf *path,
414
482
  const char *ceiling,
415
- int (*cb)(void *data, git_buf *),
483
+ int (*cb)(void *data, const char *),
416
484
  void *data)
417
485
  {
418
486
  int error = 0;
@@ -430,15 +498,27 @@ int git_path_walk_up(
430
498
  }
431
499
  scan = git_buf_len(path);
432
500
 
501
+ /* empty path: yield only once */
502
+ if (!scan) {
503
+ error = cb(data, "");
504
+ if (error)
505
+ git_error_set_after_callback(error);
506
+ return error;
507
+ }
508
+
433
509
  iter.ptr = path->ptr;
434
510
  iter.size = git_buf_len(path);
435
511
  iter.asize = path->asize;
436
512
 
437
513
  while (scan >= stop) {
438
- error = cb(data, &iter);
514
+ error = cb(data, iter.ptr);
439
515
  iter.ptr[scan] = oldc;
440
- if (error < 0)
516
+
517
+ if (error) {
518
+ git_error_set_after_callback(error);
441
519
  break;
520
+ }
521
+
442
522
  scan = git_buf_rfind_next(&iter, '/');
443
523
  if (scan >= 0) {
444
524
  scan++;
@@ -451,6 +531,13 @@ int git_path_walk_up(
451
531
  if (scan >= 0)
452
532
  iter.ptr[scan] = oldc;
453
533
 
534
+ /* relative path: yield for the last component */
535
+ if (!error && stop == 0 && iter.ptr[0] != '/') {
536
+ error = cb(data, "");
537
+ if (error)
538
+ git_error_set_after_callback(error);
539
+ }
540
+
454
541
  return error;
455
542
  }
456
543
 
@@ -480,78 +567,121 @@ bool git_path_isfile(const char *path)
480
567
  return S_ISREG(st.st_mode) != 0;
481
568
  }
482
569
 
570
+ bool git_path_islink(const char *path)
571
+ {
572
+ struct stat st;
573
+
574
+ assert(path);
575
+ if (p_lstat(path, &st) < 0)
576
+ return false;
577
+
578
+ return S_ISLNK(st.st_mode) != 0;
579
+ }
580
+
483
581
  #ifdef GIT_WIN32
484
582
 
485
583
  bool git_path_is_empty_dir(const char *path)
486
584
  {
487
- git_buf pathbuf = GIT_BUF_INIT;
488
- HANDLE hFind = INVALID_HANDLE_VALUE;
489
- wchar_t wbuf[GIT_WIN_PATH];
490
- WIN32_FIND_DATAW ffd;
491
- bool retval = true;
492
-
493
- if (!git_path_isdir(path)) return false;
494
-
495
- git_buf_printf(&pathbuf, "%s\\*", path);
496
- git__utf8_to_16(wbuf, GIT_WIN_PATH, git_buf_cstr(&pathbuf));
585
+ git_win32_path filter_w;
586
+ bool empty = false;
587
+
588
+ if (git_win32__findfirstfile_filter(filter_w, path)) {
589
+ WIN32_FIND_DATAW findData;
590
+ HANDLE hFind = FindFirstFileW(filter_w, &findData);
591
+
592
+ /* FindFirstFile will fail if there are no children to the given
593
+ * path, which can happen if the given path is a file (and obviously
594
+ * has no children) or if the given path is an empty mount point.
595
+ * (Most directories have at least directory entries '.' and '..',
596
+ * but ridiculously another volume mounted in another drive letter's
597
+ * path space do not, and thus have nothing to enumerate.) If
598
+ * FindFirstFile fails, check if this is a directory-like thing
599
+ * (a mount point).
600
+ */
601
+ if (hFind == INVALID_HANDLE_VALUE)
602
+ return git_path_isdir(path);
603
+
604
+ /* If the find handle was created successfully, then it's a directory */
605
+ empty = true;
606
+
607
+ do {
608
+ /* Allow the enumeration to return . and .. and still be considered
609
+ * empty. In the special case of drive roots (i.e. C:\) where . and
610
+ * .. do not occur, we can still consider the path to be an empty
611
+ * directory if there's nothing there. */
612
+ if (!git_path_is_dot_or_dotdotW(findData.cFileName)) {
613
+ empty = false;
614
+ break;
615
+ }
616
+ } while (FindNextFileW(hFind, &findData));
497
617
 
498
- hFind = FindFirstFileW(wbuf, &ffd);
499
- if (INVALID_HANDLE_VALUE == hFind) {
500
- giterr_set(GITERR_OS, "Couldn't open '%s'", path);
501
- return false;
618
+ FindClose(hFind);
502
619
  }
503
620
 
504
- do {
505
- if (!git_path_is_dot_or_dotdotW(ffd.cFileName)) {
506
- retval = false;
507
- }
508
- } while (FindNextFileW(hFind, &ffd) != 0);
509
-
510
- FindClose(hFind);
511
- git_buf_free(&pathbuf);
512
- return retval;
621
+ return empty;
513
622
  }
514
623
 
515
624
  #else
516
625
 
517
- bool git_path_is_empty_dir(const char *path)
626
+ static int path_found_entry(void *payload, git_buf *path)
518
627
  {
519
- DIR *dir = NULL;
520
- struct dirent *e;
521
- bool retval = true;
628
+ GIT_UNUSED(payload);
629
+ return !git_path_is_dot_or_dotdot(path->ptr);
630
+ }
522
631
 
523
- if (!git_path_isdir(path)) return false;
632
+ bool git_path_is_empty_dir(const char *path)
633
+ {
634
+ int error;
635
+ git_buf dir = GIT_BUF_INIT;
524
636
 
525
- dir = opendir(path);
526
- if (!dir) {
527
- giterr_set(GITERR_OS, "Couldn't open '%s'", path);
637
+ if (!git_path_isdir(path))
528
638
  return false;
529
- }
530
639
 
531
- while ((e = readdir(dir)) != NULL) {
532
- if (!git_path_is_dot_or_dotdot(e->d_name)) {
533
- giterr_set(GITERR_INVALID,
534
- "'%s' exists and is not an empty directory", path);
535
- retval = false;
536
- break;
537
- }
538
- }
539
- closedir(dir);
640
+ if ((error = git_buf_sets(&dir, path)) != 0)
641
+ git_error_clear();
642
+ else
643
+ error = git_path_direach(&dir, 0, path_found_entry, NULL);
644
+
645
+ git_buf_dispose(&dir);
540
646
 
541
- return retval;
647
+ return !error;
542
648
  }
649
+
543
650
  #endif
544
651
 
545
- int git_path_lstat(const char *path, struct stat *st)
652
+ int git_path_set_error(int errno_value, const char *path, const char *action)
546
653
  {
547
- int err = 0;
548
-
549
- if (p_lstat(path, st) < 0) {
550
- err = (errno == ENOENT) ? GIT_ENOTFOUND : -1;
551
- giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
654
+ switch (errno_value) {
655
+ case ENOENT:
656
+ case ENOTDIR:
657
+ git_error_set(GIT_ERROR_OS, "could not find '%s' to %s", path, action);
658
+ return GIT_ENOTFOUND;
659
+
660
+ case EINVAL:
661
+ case ENAMETOOLONG:
662
+ git_error_set(GIT_ERROR_OS, "invalid path for filesystem '%s'", path);
663
+ return GIT_EINVALIDSPEC;
664
+
665
+ case EEXIST:
666
+ git_error_set(GIT_ERROR_OS, "failed %s - '%s' already exists", action, path);
667
+ return GIT_EEXISTS;
668
+
669
+ case EACCES:
670
+ git_error_set(GIT_ERROR_OS, "failed %s - '%s' is locked", action, path);
671
+ return GIT_ELOCKED;
672
+
673
+ default:
674
+ git_error_set(GIT_ERROR_OS, "could not %s '%s'", action, path);
675
+ return -1;
552
676
  }
677
+ }
678
+
679
+ int git_path_lstat(const char *path, struct stat *st)
680
+ {
681
+ if (p_lstat(path, st) == 0)
682
+ return 0;
553
683
 
554
- return err;
684
+ return git_path_set_error(errno, path, "stat");
555
685
  }
556
686
 
557
687
  static bool _check_dir_contents(
@@ -562,13 +692,17 @@ static bool _check_dir_contents(
562
692
  bool result;
563
693
  size_t dir_size = git_buf_len(dir);
564
694
  size_t sub_size = strlen(sub);
695
+ size_t alloc_size;
565
696
 
566
697
  /* leave base valid even if we could not make space for subdir */
567
- if (git_buf_try_grow(dir, dir_size + sub_size + 2, false) < 0)
698
+ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, dir_size, sub_size) ||
699
+ GIT_ADD_SIZET_OVERFLOW(&alloc_size, alloc_size, 2) ||
700
+ git_buf_try_grow(dir, alloc_size, false) < 0)
568
701
  return false;
569
702
 
570
703
  /* save excursion */
571
- git_buf_joinpath(dir, dir->ptr, sub);
704
+ if (git_buf_joinpath(dir, dir->ptr, sub) < 0)
705
+ return false;
572
706
 
573
707
  result = predicate(dir->ptr);
574
708
 
@@ -603,8 +737,8 @@ int git_path_find_dir(git_buf *dir, const char *path, const char *base)
603
737
  }
604
738
 
605
739
  /* call dirname if this is not a directory */
606
- if (!error && git_path_isdir(dir->ptr) == false)
607
- error = git_path_dirname_r(dir, dir->ptr);
740
+ if (!error) /* && git_path_isdir(dir->ptr) == false) */
741
+ error = (git_path_dirname_r(dir, dir->ptr) < 0) ? -1 : 0;
608
742
 
609
743
  if (!error)
610
744
  error = git_path_to_dir(dir);
@@ -617,8 +751,7 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
617
751
  char *base, *to, *from, *next;
618
752
  size_t len;
619
753
 
620
- if (!path || git_buf_oom(path))
621
- return -1;
754
+ GIT_ERROR_CHECK_ALLOC_BUF(path);
622
755
 
623
756
  if (ceiling > path->size)
624
757
  ceiling = path->size;
@@ -645,12 +778,33 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
645
778
  /* do nothing with singleton dot */;
646
779
 
647
780
  else if (len == 2 && from[0] == '.' && from[1] == '.') {
648
- while (to > base && to[-1] == '/') to--;
649
- while (to > base && to[-1] != '/') to--;
650
- }
781
+ /* error out if trying to up one from a hard base */
782
+ if (to == base && ceiling != 0) {
783
+ git_error_set(GIT_ERROR_INVALID,
784
+ "cannot strip root component off url");
785
+ return -1;
786
+ }
787
+
788
+ /* no more path segments to strip,
789
+ * use '../' as a new base path */
790
+ if (to == base) {
791
+ if (*next == '/')
792
+ len++;
651
793
 
652
- else {
653
- if (*next == '/')
794
+ if (to != from)
795
+ memmove(to, from, len);
796
+
797
+ to += len;
798
+ /* this is now the base, can't back up from a
799
+ * relative prefix */
800
+ base = to;
801
+ } else {
802
+ /* back up a path segment */
803
+ while (to > base && to[-1] == '/') to--;
804
+ while (to > base && to[-1] != '/') to--;
805
+ }
806
+ } else {
807
+ if (*next == '/' && *from != '/')
654
808
  len++;
655
809
 
656
810
  if (to != from)
@@ -673,8 +827,8 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling)
673
827
 
674
828
  int git_path_apply_relative(git_buf *target, const char *relpath)
675
829
  {
676
- git_buf_joinpath(target, git_buf_cstr(target), relpath);
677
- return git_path_resolve_relative(target, 0);
830
+ return git_buf_joinpath(target, git_buf_cstr(target), relpath) ||
831
+ git_path_resolve_relative(target, 0);
678
832
  }
679
833
 
680
834
  int git_path_cmp(
@@ -702,14 +856,246 @@ int git_path_cmp(
702
856
  return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
703
857
  }
704
858
 
859
+ size_t git_path_common_dirlen(const char *one, const char *two)
860
+ {
861
+ const char *p, *q, *dirsep = NULL;
862
+
863
+ for (p = one, q = two; *p && *q; p++, q++) {
864
+ if (*p == '/' && *q == '/')
865
+ dirsep = p;
866
+ else if (*p != *q)
867
+ break;
868
+ }
869
+
870
+ return dirsep ? (dirsep - one) + 1 : 0;
871
+ }
872
+
873
+ int git_path_make_relative(git_buf *path, const char *parent)
874
+ {
875
+ const char *p, *q, *p_dirsep, *q_dirsep;
876
+ size_t plen = path->size, newlen, alloclen, depth = 1, i, offset;
877
+
878
+ for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) {
879
+ if (*p == '/' && *q == '/') {
880
+ p_dirsep = p;
881
+ q_dirsep = q;
882
+ }
883
+ else if (*p != *q)
884
+ break;
885
+ }
886
+
887
+ /* need at least 1 common path segment */
888
+ if ((p_dirsep == path->ptr || q_dirsep == parent) &&
889
+ (*p_dirsep != '/' || *q_dirsep != '/')) {
890
+ git_error_set(GIT_ERROR_INVALID,
891
+ "%s is not a parent of %s", parent, path->ptr);
892
+ return GIT_ENOTFOUND;
893
+ }
894
+
895
+ if (*p == '/' && !*q)
896
+ p++;
897
+ else if (!*p && *q == '/')
898
+ q++;
899
+ else if (!*p && !*q)
900
+ return git_buf_clear(path), 0;
901
+ else {
902
+ p = p_dirsep + 1;
903
+ q = q_dirsep + 1;
904
+ }
905
+
906
+ plen -= (p - path->ptr);
907
+
908
+ if (!*q)
909
+ return git_buf_set(path, p, plen);
910
+
911
+ for (; (q = strchr(q, '/')) && *(q + 1); q++)
912
+ depth++;
913
+
914
+ GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newlen, depth, 3);
915
+ GIT_ERROR_CHECK_ALLOC_ADD(&newlen, newlen, plen);
916
+
917
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, newlen, 1);
918
+
919
+ /* save the offset as we might realllocate the pointer */
920
+ offset = p - path->ptr;
921
+ if (git_buf_try_grow(path, alloclen, 1) < 0)
922
+ return -1;
923
+ p = path->ptr + offset;
924
+
925
+ memmove(path->ptr + (depth * 3), p, plen + 1);
926
+
927
+ for (i = 0; i < depth; i++)
928
+ memcpy(path->ptr + (i * 3), "../", 3);
929
+
930
+ path->size = newlen;
931
+ return 0;
932
+ }
933
+
934
+ bool git_path_has_non_ascii(const char *path, size_t pathlen)
935
+ {
936
+ const uint8_t *scan = (const uint8_t *)path, *end;
937
+
938
+ for (end = scan + pathlen; scan < end; ++scan)
939
+ if (*scan & 0x80)
940
+ return true;
941
+
942
+ return false;
943
+ }
944
+
945
+ #ifdef GIT_USE_ICONV
946
+
947
+ int git_path_iconv_init_precompose(git_path_iconv_t *ic)
948
+ {
949
+ git_buf_init(&ic->buf, 0);
950
+ ic->map = iconv_open(GIT_PATH_REPO_ENCODING, GIT_PATH_NATIVE_ENCODING);
951
+ return 0;
952
+ }
953
+
954
+ void git_path_iconv_clear(git_path_iconv_t *ic)
955
+ {
956
+ if (ic) {
957
+ if (ic->map != (iconv_t)-1)
958
+ iconv_close(ic->map);
959
+ git_buf_dispose(&ic->buf);
960
+ }
961
+ }
962
+
963
+ int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen)
964
+ {
965
+ char *nfd = (char*)*in, *nfc;
966
+ size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, alloclen, rv;
967
+ int retry = 1;
968
+
969
+ if (!ic || ic->map == (iconv_t)-1 ||
970
+ !git_path_has_non_ascii(*in, *inlen))
971
+ return 0;
972
+
973
+ git_buf_clear(&ic->buf);
974
+
975
+ while (1) {
976
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, wantlen, 1);
977
+ if (git_buf_grow(&ic->buf, alloclen) < 0)
978
+ return -1;
979
+
980
+ nfc = ic->buf.ptr + ic->buf.size;
981
+ nfclen = ic->buf.asize - ic->buf.size;
982
+
983
+ rv = iconv(ic->map, &nfd, &nfdlen, &nfc, &nfclen);
984
+
985
+ ic->buf.size = (nfc - ic->buf.ptr);
986
+
987
+ if (rv != (size_t)-1)
988
+ break;
989
+
990
+ /* if we cannot convert the data (probably because iconv thinks
991
+ * it is not valid UTF-8 source data), then use original data
992
+ */
993
+ if (errno != E2BIG)
994
+ return 0;
995
+
996
+ /* make space for 2x the remaining data to be converted
997
+ * (with per retry overhead to avoid infinite loops)
998
+ */
999
+ wantlen = ic->buf.size + max(nfclen, nfdlen) * 2 + (size_t)(retry * 4);
1000
+
1001
+ if (retry++ > 4)
1002
+ goto fail;
1003
+ }
1004
+
1005
+ ic->buf.ptr[ic->buf.size] = '\0';
1006
+
1007
+ *in = ic->buf.ptr;
1008
+ *inlen = ic->buf.size;
1009
+
1010
+ return 0;
1011
+
1012
+ fail:
1013
+ git_error_set(GIT_ERROR_OS, "unable to convert unicode path data");
1014
+ return -1;
1015
+ }
1016
+
1017
+ static const char *nfc_file = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D.XXXXXX";
1018
+ static const char *nfd_file = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D.XXXXXX";
1019
+
1020
+ /* Check if the platform is decomposing unicode data for us. We will
1021
+ * emulate core Git and prefer to use precomposed unicode data internally
1022
+ * on these platforms, composing the decomposed unicode on the fly.
1023
+ *
1024
+ * This mainly happens on the Mac where HDFS stores filenames as
1025
+ * decomposed unicode. Even on VFAT and SAMBA file systems, the Mac will
1026
+ * return decomposed unicode from readdir() even when the actual
1027
+ * filesystem is storing precomposed unicode.
1028
+ */
1029
+ bool git_path_does_fs_decompose_unicode(const char *root)
1030
+ {
1031
+ git_buf path = GIT_BUF_INIT;
1032
+ int fd;
1033
+ bool found_decomposed = false;
1034
+ char tmp[6];
1035
+
1036
+ /* Create a file using a precomposed path and then try to find it
1037
+ * using the decomposed name. If the lookup fails, then we will mark
1038
+ * that we should precompose unicode for this repository.
1039
+ */
1040
+ if (git_buf_joinpath(&path, root, nfc_file) < 0 ||
1041
+ (fd = p_mkstemp(path.ptr)) < 0)
1042
+ goto done;
1043
+ p_close(fd);
1044
+
1045
+ /* record trailing digits generated by mkstemp */
1046
+ memcpy(tmp, path.ptr + path.size - sizeof(tmp), sizeof(tmp));
1047
+
1048
+ /* try to look up as NFD path */
1049
+ if (git_buf_joinpath(&path, root, nfd_file) < 0)
1050
+ goto done;
1051
+ memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
1052
+
1053
+ found_decomposed = git_path_exists(path.ptr);
1054
+
1055
+ /* remove temporary file (using original precomposed path) */
1056
+ if (git_buf_joinpath(&path, root, nfc_file) < 0)
1057
+ goto done;
1058
+ memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
1059
+
1060
+ (void)p_unlink(path.ptr);
1061
+
1062
+ done:
1063
+ git_buf_dispose(&path);
1064
+ return found_decomposed;
1065
+ }
1066
+
1067
+ #else
1068
+
1069
+ bool git_path_does_fs_decompose_unicode(const char *root)
1070
+ {
1071
+ GIT_UNUSED(root);
1072
+ return false;
1073
+ }
1074
+
1075
+ #endif
1076
+
1077
+ #if defined(__sun) || defined(__GNU__)
1078
+ typedef char path_dirent_data[sizeof(struct dirent) + FILENAME_MAX + 1];
1079
+ #else
1080
+ typedef struct dirent path_dirent_data;
1081
+ #endif
1082
+
705
1083
  int git_path_direach(
706
1084
  git_buf *path,
1085
+ uint32_t flags,
707
1086
  int (*fn)(void *, git_buf *),
708
1087
  void *arg)
709
1088
  {
1089
+ int error = 0;
710
1090
  ssize_t wd_len;
711
1091
  DIR *dir;
712
- struct dirent *de, *de_buf;
1092
+ struct dirent *de;
1093
+
1094
+ #ifdef GIT_USE_ICONV
1095
+ git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
1096
+ #endif
1097
+
1098
+ GIT_UNUSED(flags);
713
1099
 
714
1100
  if (git_path_to_dir(path) < 0)
715
1101
  return -1;
@@ -717,189 +1103,809 @@ int git_path_direach(
717
1103
  wd_len = git_buf_len(path);
718
1104
 
719
1105
  if ((dir = opendir(path->ptr)) == NULL) {
720
- giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr);
1106
+ git_error_set(GIT_ERROR_OS, "failed to open directory '%s'", path->ptr);
1107
+ if (errno == ENOENT)
1108
+ return GIT_ENOTFOUND;
1109
+
721
1110
  return -1;
722
1111
  }
723
1112
 
724
- #if defined(__sun) || defined(__GNU__)
725
- de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1);
726
- #else
727
- de_buf = git__malloc(sizeof(struct dirent));
1113
+ #ifdef GIT_USE_ICONV
1114
+ if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0)
1115
+ (void)git_path_iconv_init_precompose(&ic);
728
1116
  #endif
729
1117
 
730
- while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) {
731
- int result;
1118
+ while ((de = readdir(dir)) != NULL) {
1119
+ const char *de_path = de->d_name;
1120
+ size_t de_len = strlen(de_path);
732
1121
 
733
- if (git_path_is_dot_or_dotdot(de->d_name))
1122
+ if (git_path_is_dot_or_dotdot(de_path))
734
1123
  continue;
735
1124
 
736
- if (git_buf_puts(path, de->d_name) < 0) {
737
- closedir(dir);
738
- git__free(de_buf);
739
- return -1;
740
- }
1125
+ #ifdef GIT_USE_ICONV
1126
+ if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0)
1127
+ break;
1128
+ #endif
1129
+
1130
+ if ((error = git_buf_put(path, de_path, de_len)) < 0)
1131
+ break;
741
1132
 
742
- result = fn(arg, path);
1133
+ git_error_clear();
1134
+ error = fn(arg, path);
743
1135
 
744
1136
  git_buf_truncate(path, wd_len); /* restore path */
745
1137
 
746
- if (result < 0) {
747
- closedir(dir);
748
- git__free(de_buf);
749
- return -1;
1138
+ /* Only set our own error if the callback did not set one already */
1139
+ if (error != 0) {
1140
+ if (!git_error_last())
1141
+ git_error_set_after_callback(error);
1142
+
1143
+ break;
750
1144
  }
751
1145
  }
752
1146
 
753
1147
  closedir(dir);
754
- git__free(de_buf);
755
- return 0;
1148
+
1149
+ #ifdef GIT_USE_ICONV
1150
+ git_path_iconv_clear(&ic);
1151
+ #endif
1152
+
1153
+ return error;
756
1154
  }
757
1155
 
758
- int git_path_dirload(
1156
+ #if defined(GIT_WIN32) && !defined(__MINGW32__)
1157
+
1158
+ /* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7
1159
+ * and better.
1160
+ */
1161
+ #ifndef FIND_FIRST_EX_LARGE_FETCH
1162
+ # define FIND_FIRST_EX_LARGE_FETCH 2
1163
+ #endif
1164
+
1165
+ int git_path_diriter_init(
1166
+ git_path_diriter *diriter,
759
1167
  const char *path,
760
- size_t prefix_len,
761
- size_t alloc_extra,
762
- git_vector *contents)
1168
+ unsigned int flags)
763
1169
  {
764
- int error, need_slash;
765
- DIR *dir;
766
- struct dirent *de, *de_buf;
767
- size_t path_len;
1170
+ git_win32_path path_filter;
1171
+
1172
+ static int is_win7_or_later = -1;
1173
+ if (is_win7_or_later < 0)
1174
+ is_win7_or_later = git_has_win32_version(6, 1, 0);
1175
+
1176
+ assert(diriter && path);
1177
+
1178
+ memset(diriter, 0, sizeof(git_path_diriter));
1179
+ diriter->handle = INVALID_HANDLE_VALUE;
1180
+
1181
+ if (git_buf_puts(&diriter->path_utf8, path) < 0)
1182
+ return -1;
768
1183
 
769
- assert(path != NULL && contents != NULL);
770
- path_len = strlen(path);
771
- assert(path_len > 0 && path_len >= prefix_len);
1184
+ git_path_trim_slashes(&diriter->path_utf8);
772
1185
 
773
- if ((dir = opendir(path)) == NULL) {
774
- giterr_set(GITERR_OS, "Failed to open directory '%s'", path);
1186
+ if (diriter->path_utf8.size == 0) {
1187
+ git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
775
1188
  return -1;
776
1189
  }
777
1190
 
778
- #if defined(__sun) || defined(__GNU__)
779
- de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1);
1191
+ if ((diriter->parent_len = git_win32_path_from_utf8(diriter->path, diriter->path_utf8.ptr)) < 0 ||
1192
+ !git_win32__findfirstfile_filter(path_filter, diriter->path_utf8.ptr)) {
1193
+ git_error_set(GIT_ERROR_OS, "could not parse the directory path '%s'", path);
1194
+ return -1;
1195
+ }
1196
+
1197
+ diriter->handle = FindFirstFileExW(
1198
+ path_filter,
1199
+ is_win7_or_later ? FindExInfoBasic : FindExInfoStandard,
1200
+ &diriter->current,
1201
+ FindExSearchNameMatch,
1202
+ NULL,
1203
+ is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0);
1204
+
1205
+ if (diriter->handle == INVALID_HANDLE_VALUE) {
1206
+ git_error_set(GIT_ERROR_OS, "could not open directory '%s'", path);
1207
+ return -1;
1208
+ }
1209
+
1210
+ diriter->parent_utf8_len = diriter->path_utf8.size;
1211
+ diriter->flags = flags;
1212
+ return 0;
1213
+ }
1214
+
1215
+ static int diriter_update_paths(git_path_diriter *diriter)
1216
+ {
1217
+ size_t filename_len, path_len;
1218
+
1219
+ filename_len = wcslen(diriter->current.cFileName);
1220
+
1221
+ if (GIT_ADD_SIZET_OVERFLOW(&path_len, diriter->parent_len, filename_len) ||
1222
+ GIT_ADD_SIZET_OVERFLOW(&path_len, path_len, 2))
1223
+ return -1;
1224
+
1225
+ if (path_len > GIT_WIN_PATH_UTF16) {
1226
+ git_error_set(GIT_ERROR_FILESYSTEM,
1227
+ "invalid path '%.*ls\\%ls' (path too long)",
1228
+ diriter->parent_len, diriter->path, diriter->current.cFileName);
1229
+ return -1;
1230
+ }
1231
+
1232
+ diriter->path[diriter->parent_len] = L'\\';
1233
+ memcpy(&diriter->path[diriter->parent_len+1],
1234
+ diriter->current.cFileName, filename_len * sizeof(wchar_t));
1235
+ diriter->path[path_len-1] = L'\0';
1236
+
1237
+ git_buf_truncate(&diriter->path_utf8, diriter->parent_utf8_len);
1238
+
1239
+ if (diriter->parent_utf8_len > 0 &&
1240
+ diriter->path_utf8.ptr[diriter->parent_utf8_len-1] != '/')
1241
+ git_buf_putc(&diriter->path_utf8, '/');
1242
+
1243
+ git_buf_put_w(&diriter->path_utf8, diriter->current.cFileName, filename_len);
1244
+
1245
+ if (git_buf_oom(&diriter->path_utf8))
1246
+ return -1;
1247
+
1248
+ return 0;
1249
+ }
1250
+
1251
+ int git_path_diriter_next(git_path_diriter *diriter)
1252
+ {
1253
+ bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT);
1254
+
1255
+ do {
1256
+ /* Our first time through, we already have the data from
1257
+ * FindFirstFileW. Use it, otherwise get the next file.
1258
+ */
1259
+ if (!diriter->needs_next)
1260
+ diriter->needs_next = 1;
1261
+ else if (!FindNextFileW(diriter->handle, &diriter->current))
1262
+ return GIT_ITEROVER;
1263
+ } while (skip_dot && git_path_is_dot_or_dotdotW(diriter->current.cFileName));
1264
+
1265
+ if (diriter_update_paths(diriter) < 0)
1266
+ return -1;
1267
+
1268
+ return 0;
1269
+ }
1270
+
1271
+ int git_path_diriter_filename(
1272
+ const char **out,
1273
+ size_t *out_len,
1274
+ git_path_diriter *diriter)
1275
+ {
1276
+ assert(out && out_len && diriter);
1277
+
1278
+ assert(diriter->path_utf8.size > diriter->parent_utf8_len);
1279
+
1280
+ *out = &diriter->path_utf8.ptr[diriter->parent_utf8_len+1];
1281
+ *out_len = diriter->path_utf8.size - diriter->parent_utf8_len - 1;
1282
+ return 0;
1283
+ }
1284
+
1285
+ int git_path_diriter_fullpath(
1286
+ const char **out,
1287
+ size_t *out_len,
1288
+ git_path_diriter *diriter)
1289
+ {
1290
+ assert(out && out_len && diriter);
1291
+
1292
+ *out = diriter->path_utf8.ptr;
1293
+ *out_len = diriter->path_utf8.size;
1294
+ return 0;
1295
+ }
1296
+
1297
+ int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
1298
+ {
1299
+ assert(out && diriter);
1300
+
1301
+ return git_win32__file_attribute_to_stat(out,
1302
+ (WIN32_FILE_ATTRIBUTE_DATA *)&diriter->current,
1303
+ diriter->path);
1304
+ }
1305
+
1306
+ void git_path_diriter_free(git_path_diriter *diriter)
1307
+ {
1308
+ if (diriter == NULL)
1309
+ return;
1310
+
1311
+ git_buf_dispose(&diriter->path_utf8);
1312
+
1313
+ if (diriter->handle != INVALID_HANDLE_VALUE) {
1314
+ FindClose(diriter->handle);
1315
+ diriter->handle = INVALID_HANDLE_VALUE;
1316
+ }
1317
+ }
1318
+
780
1319
  #else
781
- de_buf = git__malloc(sizeof(struct dirent));
1320
+
1321
+ int git_path_diriter_init(
1322
+ git_path_diriter *diriter,
1323
+ const char *path,
1324
+ unsigned int flags)
1325
+ {
1326
+ assert(diriter && path);
1327
+
1328
+ memset(diriter, 0, sizeof(git_path_diriter));
1329
+
1330
+ if (git_buf_puts(&diriter->path, path) < 0)
1331
+ return -1;
1332
+
1333
+ git_path_trim_slashes(&diriter->path);
1334
+
1335
+ if (diriter->path.size == 0) {
1336
+ git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
1337
+ return -1;
1338
+ }
1339
+
1340
+ if ((diriter->dir = opendir(diriter->path.ptr)) == NULL) {
1341
+ git_buf_dispose(&diriter->path);
1342
+
1343
+ git_error_set(GIT_ERROR_OS, "failed to open directory '%s'", path);
1344
+ return -1;
1345
+ }
1346
+
1347
+ #ifdef GIT_USE_ICONV
1348
+ if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0)
1349
+ (void)git_path_iconv_init_precompose(&diriter->ic);
782
1350
  #endif
783
1351
 
784
- path += prefix_len;
785
- path_len -= prefix_len;
786
- need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
1352
+ diriter->parent_len = diriter->path.size;
1353
+ diriter->flags = flags;
787
1354
 
788
- while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) {
789
- char *entry_path;
790
- size_t entry_len;
1355
+ return 0;
1356
+ }
791
1357
 
792
- if (git_path_is_dot_or_dotdot(de->d_name))
793
- continue;
1358
+ int git_path_diriter_next(git_path_diriter *diriter)
1359
+ {
1360
+ struct dirent *de;
1361
+ const char *filename;
1362
+ size_t filename_len;
1363
+ bool skip_dot = !(diriter->flags & GIT_PATH_DIR_INCLUDE_DOT_AND_DOTDOT);
1364
+ int error = 0;
794
1365
 
795
- entry_len = strlen(de->d_name);
1366
+ assert(diriter);
796
1367
 
797
- entry_path = git__malloc(
798
- path_len + need_slash + entry_len + 1 + alloc_extra);
799
- GITERR_CHECK_ALLOC(entry_path);
1368
+ errno = 0;
800
1369
 
801
- if (path_len)
802
- memcpy(entry_path, path, path_len);
803
- if (need_slash)
804
- entry_path[path_len] = '/';
805
- memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len);
806
- entry_path[path_len + need_slash + entry_len] = '\0';
1370
+ do {
1371
+ if ((de = readdir(diriter->dir)) == NULL) {
1372
+ if (!errno)
1373
+ return GIT_ITEROVER;
807
1374
 
808
- if (git_vector_insert(contents, entry_path) < 0) {
809
- closedir(dir);
810
- git__free(de_buf);
1375
+ git_error_set(GIT_ERROR_OS,
1376
+ "could not read directory '%s'", diriter->path.ptr);
811
1377
  return -1;
812
1378
  }
813
- }
1379
+ } while (skip_dot && git_path_is_dot_or_dotdot(de->d_name));
814
1380
 
815
- closedir(dir);
816
- git__free(de_buf);
1381
+ filename = de->d_name;
1382
+ filename_len = strlen(filename);
817
1383
 
818
- if (error != 0)
819
- giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path);
1384
+ #ifdef GIT_USE_ICONV
1385
+ if ((diriter->flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0 &&
1386
+ (error = git_path_iconv(&diriter->ic, &filename, &filename_len)) < 0)
1387
+ return error;
1388
+ #endif
1389
+
1390
+ git_buf_truncate(&diriter->path, diriter->parent_len);
1391
+
1392
+ if (diriter->parent_len > 0 &&
1393
+ diriter->path.ptr[diriter->parent_len-1] != '/')
1394
+ git_buf_putc(&diriter->path, '/');
1395
+
1396
+ git_buf_put(&diriter->path, filename, filename_len);
1397
+
1398
+ if (git_buf_oom(&diriter->path))
1399
+ return -1;
820
1400
 
821
1401
  return error;
822
1402
  }
823
1403
 
824
- int git_path_with_stat_cmp(const void *a, const void *b)
1404
+ int git_path_diriter_filename(
1405
+ const char **out,
1406
+ size_t *out_len,
1407
+ git_path_diriter *diriter)
1408
+ {
1409
+ assert(out && out_len && diriter);
1410
+
1411
+ assert(diriter->path.size > diriter->parent_len);
1412
+
1413
+ *out = &diriter->path.ptr[diriter->parent_len+1];
1414
+ *out_len = diriter->path.size - diriter->parent_len - 1;
1415
+ return 0;
1416
+ }
1417
+
1418
+ int git_path_diriter_fullpath(
1419
+ const char **out,
1420
+ size_t *out_len,
1421
+ git_path_diriter *diriter)
1422
+ {
1423
+ assert(out && out_len && diriter);
1424
+
1425
+ *out = diriter->path.ptr;
1426
+ *out_len = diriter->path.size;
1427
+ return 0;
1428
+ }
1429
+
1430
+ int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter)
825
1431
  {
826
- const git_path_with_stat *psa = a, *psb = b;
827
- return strcmp(psa->path, psb->path);
1432
+ assert(out && diriter);
1433
+
1434
+ return git_path_lstat(diriter->path.ptr, out);
828
1435
  }
829
1436
 
830
- int git_path_with_stat_cmp_icase(const void *a, const void *b)
1437
+ void git_path_diriter_free(git_path_diriter *diriter)
831
1438
  {
832
- const git_path_with_stat *psa = a, *psb = b;
833
- return strcasecmp(psa->path, psb->path);
1439
+ if (diriter == NULL)
1440
+ return;
1441
+
1442
+ if (diriter->dir) {
1443
+ closedir(diriter->dir);
1444
+ diriter->dir = NULL;
1445
+ }
1446
+
1447
+ #ifdef GIT_USE_ICONV
1448
+ git_path_iconv_clear(&diriter->ic);
1449
+ #endif
1450
+
1451
+ git_buf_dispose(&diriter->path);
834
1452
  }
835
1453
 
836
- int git_path_dirload_with_stat(
1454
+ #endif
1455
+
1456
+ int git_path_dirload(
1457
+ git_vector *contents,
837
1458
  const char *path,
838
1459
  size_t prefix_len,
839
- bool ignore_case,
840
- const char *start_stat,
841
- const char *end_stat,
842
- git_vector *contents)
1460
+ uint32_t flags)
843
1461
  {
1462
+ git_path_diriter iter = GIT_PATH_DIRITER_INIT;
1463
+ const char *name;
1464
+ size_t name_len;
1465
+ char *dup;
844
1466
  int error;
845
- unsigned int i;
846
- git_path_with_stat *ps;
847
- git_buf full = GIT_BUF_INIT;
848
- int (*strncomp)(const char *a, const char *b, size_t sz);
849
- size_t start_len = start_stat ? strlen(start_stat) : 0;
850
- size_t end_len = end_stat ? strlen(end_stat) : 0, cmp_len;
851
-
852
- if (git_buf_set(&full, path, prefix_len) < 0)
853
- return -1;
854
1467
 
855
- error = git_path_dirload(
856
- path, prefix_len, sizeof(git_path_with_stat) + 1, contents);
857
- if (error < 0) {
858
- git_buf_free(&full);
1468
+ assert(contents && path);
1469
+
1470
+ if ((error = git_path_diriter_init(&iter, path, flags)) < 0)
859
1471
  return error;
860
- }
861
1472
 
862
- strncomp = ignore_case ? git__strncasecmp : git__strncmp;
1473
+ while ((error = git_path_diriter_next(&iter)) == 0) {
1474
+ if ((error = git_path_diriter_fullpath(&name, &name_len, &iter)) < 0)
1475
+ break;
1476
+
1477
+ assert(name_len > prefix_len);
863
1478
 
864
- /* stat struct at start of git_path_with_stat, so shift path text */
865
- git_vector_foreach(contents, i, ps) {
866
- size_t path_len = strlen((char *)ps);
867
- memmove(ps->path, ps, path_len + 1);
868
- ps->path_len = path_len;
1479
+ dup = git__strndup(name + prefix_len, name_len - prefix_len);
1480
+ GIT_ERROR_CHECK_ALLOC(dup);
1481
+
1482
+ if ((error = git_vector_insert(contents, dup)) < 0)
1483
+ break;
869
1484
  }
870
1485
 
871
- git_vector_foreach(contents, i, ps) {
872
- /* skip if before start_stat or after end_stat */
873
- cmp_len = min(start_len, ps->path_len);
874
- if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0)
875
- continue;
876
- cmp_len = min(end_len, ps->path_len);
877
- if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0)
1486
+ if (error == GIT_ITEROVER)
1487
+ error = 0;
1488
+
1489
+ git_path_diriter_free(&iter);
1490
+ return error;
1491
+ }
1492
+
1493
+ int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
1494
+ {
1495
+ if (git_path_is_local_file_url(url_or_path))
1496
+ return git_path_fromurl(local_path_out, url_or_path);
1497
+ else
1498
+ return git_buf_sets(local_path_out, url_or_path);
1499
+ }
1500
+
1501
+ /* Reject paths like AUX or COM1, or those versions that end in a dot or
1502
+ * colon. ("AUX." or "AUX:")
1503
+ */
1504
+ GIT_INLINE(bool) verify_dospath(
1505
+ const char *component,
1506
+ size_t len,
1507
+ const char dospath[3],
1508
+ bool trailing_num)
1509
+ {
1510
+ size_t last = trailing_num ? 4 : 3;
1511
+
1512
+ if (len < last || git__strncasecmp(component, dospath, 3) != 0)
1513
+ return true;
1514
+
1515
+ if (trailing_num && (component[3] < '1' || component[3] > '9'))
1516
+ return true;
1517
+
1518
+ return (len > last &&
1519
+ component[last] != '.' &&
1520
+ component[last] != ':');
1521
+ }
1522
+
1523
+ static int32_t next_hfs_char(const char **in, size_t *len)
1524
+ {
1525
+ while (*len) {
1526
+ int32_t codepoint;
1527
+ int cp_len = git__utf8_iterate((const uint8_t *)(*in), (int)(*len), &codepoint);
1528
+ if (cp_len < 0)
1529
+ return -1;
1530
+
1531
+ (*in) += cp_len;
1532
+ (*len) -= cp_len;
1533
+
1534
+ /* these code points are ignored completely */
1535
+ switch (codepoint) {
1536
+ case 0x200c: /* ZERO WIDTH NON-JOINER */
1537
+ case 0x200d: /* ZERO WIDTH JOINER */
1538
+ case 0x200e: /* LEFT-TO-RIGHT MARK */
1539
+ case 0x200f: /* RIGHT-TO-LEFT MARK */
1540
+ case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
1541
+ case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
1542
+ case 0x202c: /* POP DIRECTIONAL FORMATTING */
1543
+ case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
1544
+ case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
1545
+ case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
1546
+ case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
1547
+ case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
1548
+ case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
1549
+ case 0x206e: /* NATIONAL DIGIT SHAPES */
1550
+ case 0x206f: /* NOMINAL DIGIT SHAPES */
1551
+ case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
878
1552
  continue;
1553
+ }
1554
+
1555
+ /* fold into lowercase -- this will only fold characters in
1556
+ * the ASCII range, which is perfectly fine, because the
1557
+ * git folder name can only be composed of ascii characters
1558
+ */
1559
+ return git__tolower(codepoint);
1560
+ }
1561
+ return 0; /* NULL byte -- end of string */
1562
+ }
1563
+
1564
+ static bool verify_dotgit_hfs_generic(const char *path, size_t len, const char *needle, size_t needle_len)
1565
+ {
1566
+ size_t i;
1567
+ char c;
1568
+
1569
+ if (next_hfs_char(&path, &len) != '.')
1570
+ return true;
879
1571
 
880
- git_buf_truncate(&full, prefix_len);
1572
+ for (i = 0; i < needle_len; i++) {
1573
+ c = next_hfs_char(&path, &len);
1574
+ if (c != needle[i])
1575
+ return true;
1576
+ }
1577
+
1578
+ if (next_hfs_char(&path, &len) != '\0')
1579
+ return true;
1580
+
1581
+ return false;
1582
+ }
881
1583
 
882
- if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 ||
883
- (error = git_path_lstat(full.ptr, &ps->st)) < 0)
1584
+ static bool verify_dotgit_hfs(const char *path, size_t len)
1585
+ {
1586
+ return verify_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git"));
1587
+ }
1588
+
1589
+ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len)
1590
+ {
1591
+ git_buf *reserved = git_repository__reserved_names_win32;
1592
+ size_t reserved_len = git_repository__reserved_names_win32_len;
1593
+ size_t start = 0, i;
1594
+
1595
+ if (repo)
1596
+ git_repository__reserved_names(&reserved, &reserved_len, repo, true);
1597
+
1598
+ for (i = 0; i < reserved_len; i++) {
1599
+ git_buf *r = &reserved[i];
1600
+
1601
+ if (len >= r->size &&
1602
+ strncasecmp(path, r->ptr, r->size) == 0) {
1603
+ start = r->size;
884
1604
  break;
1605
+ }
1606
+ }
885
1607
 
886
- if (S_ISDIR(ps->st.st_mode)) {
887
- if ((error = git_buf_joinpath(&full, full.ptr, ".git")) < 0)
888
- break;
1608
+ if (!start)
1609
+ return true;
889
1610
 
890
- if (p_access(full.ptr, F_OK) == 0) {
891
- ps->st.st_mode = GIT_FILEMODE_COMMIT;
892
- } else {
893
- ps->path[ps->path_len++] = '/';
894
- ps->path[ps->path_len] = '\0';
895
- }
1611
+ /* Reject paths like ".git\" */
1612
+ if (path[start] == '\\')
1613
+ return false;
1614
+
1615
+ /* Reject paths like '.git ' or '.git.' */
1616
+ for (i = start; i < len; i++) {
1617
+ if (path[i] != ' ' && path[i] != '.')
1618
+ return true;
1619
+ }
1620
+
1621
+ return false;
1622
+ }
1623
+
1624
+ GIT_INLINE(bool) only_spaces_and_dots(const char *path)
1625
+ {
1626
+ const char *c = path;
1627
+
1628
+ for (;; c++) {
1629
+ if (*c == '\0')
1630
+ return true;
1631
+ if (*c != ' ' && *c != '.')
1632
+ return false;
1633
+ }
1634
+
1635
+ return true;
1636
+ }
1637
+
1638
+ GIT_INLINE(bool) verify_dotgit_ntfs_generic(const char *name, size_t len, const char *dotgit_name, size_t dotgit_len, const char *shortname_pfix)
1639
+ {
1640
+ int i, saw_tilde;
1641
+
1642
+ if (name[0] == '.' && len >= dotgit_len &&
1643
+ !strncasecmp(name + 1, dotgit_name, dotgit_len)) {
1644
+ return !only_spaces_and_dots(name + dotgit_len + 1);
1645
+ }
1646
+
1647
+ /* Detect the basic NTFS shortname with the first six chars */
1648
+ if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' &&
1649
+ name[7] >= '1' && name[7] <= '4')
1650
+ return !only_spaces_and_dots(name + 8);
1651
+
1652
+ /* Catch fallback names */
1653
+ for (i = 0, saw_tilde = 0; i < 8; i++) {
1654
+ if (name[i] == '\0') {
1655
+ return true;
1656
+ } else if (saw_tilde) {
1657
+ if (name[i] < '0' || name[i] > '9')
1658
+ return true;
1659
+ } else if (name[i] == '~') {
1660
+ if (name[i+1] < '1' || name[i+1] > '9')
1661
+ return true;
1662
+ saw_tilde = 1;
1663
+ } else if (i >= 6) {
1664
+ return true;
1665
+ } else if ((unsigned char)name[i] > 127) {
1666
+ return true;
1667
+ } else if (git__tolower(name[i]) != shortname_pfix[i]) {
1668
+ return true;
1669
+ }
1670
+ }
1671
+
1672
+ return !only_spaces_and_dots(name + i);
1673
+ }
1674
+
1675
+ GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
1676
+ {
1677
+ if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
1678
+ return false;
1679
+
1680
+ if ((flags & GIT_PATH_REJECT_SLASH) && c == '/')
1681
+ return false;
1682
+
1683
+ if (flags & GIT_PATH_REJECT_NT_CHARS) {
1684
+ if (c < 32)
1685
+ return false;
1686
+
1687
+ switch (c) {
1688
+ case '<':
1689
+ case '>':
1690
+ case ':':
1691
+ case '"':
1692
+ case '|':
1693
+ case '?':
1694
+ case '*':
1695
+ return false;
896
1696
  }
897
1697
  }
898
1698
 
899
- /* sort now that directory suffix is added */
900
- git_vector_sort(contents);
1699
+ return true;
1700
+ }
1701
+
1702
+ /*
1703
+ * Return the length of the common prefix between str and prefix, comparing them
1704
+ * case-insensitively (must be ASCII to match).
1705
+ */
1706
+ GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *prefix)
1707
+ {
1708
+ size_t count = 0;
1709
+
1710
+ while (len >0 && tolower(*str) == tolower(*prefix)) {
1711
+ count++;
1712
+ str++;
1713
+ prefix++;
1714
+ len--;
1715
+ }
1716
+
1717
+ return count;
1718
+ }
1719
+
1720
+ /*
1721
+ * We fundamentally don't like some paths when dealing with user-inputted
1722
+ * strings (in checkout or ref names): we don't want dot or dot-dot
1723
+ * anywhere, we want to avoid writing weird paths on Windows that can't
1724
+ * be handled by tools that use the non-\\?\ APIs, we don't want slashes
1725
+ * or double slashes at the end of paths that can make them ambiguous.
1726
+ *
1727
+ * For checkout, we don't want to recurse into ".git" either.
1728
+ */
1729
+ static bool verify_component(
1730
+ git_repository *repo,
1731
+ const char *component,
1732
+ size_t len,
1733
+ uint16_t mode,
1734
+ unsigned int flags)
1735
+ {
1736
+ if (len == 0)
1737
+ return false;
1738
+
1739
+ if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
1740
+ len == 1 && component[0] == '.')
1741
+ return false;
901
1742
 
902
- git_buf_free(&full);
1743
+ if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
1744
+ len == 2 && component[0] == '.' && component[1] == '.')
1745
+ return false;
903
1746
 
904
- return error;
1747
+ if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.')
1748
+ return false;
1749
+
1750
+ if ((flags & GIT_PATH_REJECT_TRAILING_SPACE) && component[len-1] == ' ')
1751
+ return false;
1752
+
1753
+ if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':')
1754
+ return false;
1755
+
1756
+ if (flags & GIT_PATH_REJECT_DOS_PATHS) {
1757
+ if (!verify_dospath(component, len, "CON", false) ||
1758
+ !verify_dospath(component, len, "PRN", false) ||
1759
+ !verify_dospath(component, len, "AUX", false) ||
1760
+ !verify_dospath(component, len, "NUL", false) ||
1761
+ !verify_dospath(component, len, "COM", true) ||
1762
+ !verify_dospath(component, len, "LPT", true))
1763
+ return false;
1764
+ }
1765
+
1766
+ if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) {
1767
+ if (!verify_dotgit_hfs(component, len))
1768
+ return false;
1769
+ if (S_ISLNK(mode) && git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_HFS))
1770
+ return false;
1771
+ }
1772
+
1773
+ if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
1774
+ if (!verify_dotgit_ntfs(repo, component, len))
1775
+ return false;
1776
+ if (S_ISLNK(mode) && git_path_is_gitfile(component, len, GIT_PATH_GITFILE_GITMODULES, GIT_PATH_FS_NTFS))
1777
+ return false;
1778
+ }
1779
+
1780
+ /* don't bother rerunning the `.git` test if we ran the HFS or NTFS
1781
+ * specific tests, they would have already rejected `.git`.
1782
+ */
1783
+ if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
1784
+ (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
1785
+ (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) {
1786
+ if (len >= 4 &&
1787
+ component[0] == '.' &&
1788
+ (component[1] == 'g' || component[1] == 'G') &&
1789
+ (component[2] == 'i' || component[2] == 'I') &&
1790
+ (component[3] == 't' || component[3] == 'T')) {
1791
+ if (len == 4)
1792
+ return false;
1793
+
1794
+ if (S_ISLNK(mode) && common_prefix_icase(component, len, ".gitmodules") == len)
1795
+ return false;
1796
+ }
1797
+ }
1798
+
1799
+ return true;
1800
+ }
1801
+
1802
+ GIT_INLINE(unsigned int) dotgit_flags(
1803
+ git_repository *repo,
1804
+ unsigned int flags)
1805
+ {
1806
+ int protectHFS = 0, protectNTFS = 0;
1807
+ int error = 0;
1808
+
1809
+ flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL;
1810
+
1811
+ #ifdef __APPLE__
1812
+ protectHFS = 1;
1813
+ #endif
1814
+
1815
+ #ifdef GIT_WIN32
1816
+ protectNTFS = 1;
1817
+ #endif
1818
+
1819
+ if (repo && !protectHFS)
1820
+ error = git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS);
1821
+ if (!error && protectHFS)
1822
+ flags |= GIT_PATH_REJECT_DOT_GIT_HFS;
1823
+
1824
+ if (repo && !protectNTFS)
1825
+ error = git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS);
1826
+ if (!error && protectNTFS)
1827
+ flags |= GIT_PATH_REJECT_DOT_GIT_NTFS;
1828
+
1829
+ return flags;
1830
+ }
1831
+
1832
+ bool git_path_isvalid(
1833
+ git_repository *repo,
1834
+ const char *path,
1835
+ uint16_t mode,
1836
+ unsigned int flags)
1837
+ {
1838
+ const char *start, *c;
1839
+
1840
+ /* Upgrade the ".git" checks based on platform */
1841
+ if ((flags & GIT_PATH_REJECT_DOT_GIT))
1842
+ flags = dotgit_flags(repo, flags);
1843
+
1844
+ for (start = c = path; *c; c++) {
1845
+ if (!verify_char(*c, flags))
1846
+ return false;
1847
+
1848
+ if (*c == '/') {
1849
+ if (!verify_component(repo, start, (c - start), mode, flags))
1850
+ return false;
1851
+
1852
+ start = c+1;
1853
+ }
1854
+ }
1855
+
1856
+ return verify_component(repo, start, (c - start), mode, flags);
1857
+ }
1858
+
1859
+ int git_path_normalize_slashes(git_buf *out, const char *path)
1860
+ {
1861
+ int error;
1862
+ char *p;
1863
+
1864
+ if ((error = git_buf_puts(out, path)) < 0)
1865
+ return error;
1866
+
1867
+ for (p = out->ptr; *p; p++) {
1868
+ if (*p == '\\')
1869
+ *p = '/';
1870
+ }
1871
+
1872
+ return 0;
1873
+ }
1874
+
1875
+ static const struct {
1876
+ const char *file;
1877
+ const char *hash;
1878
+ size_t filelen;
1879
+ } gitfiles[] = {
1880
+ { "gitignore", "gi250a", CONST_STRLEN("gitignore") },
1881
+ { "gitmodules", "gi7eba", CONST_STRLEN("gitmodules") },
1882
+ { "gitattributes", "gi7d29", CONST_STRLEN("gitattributes") }
1883
+ };
1884
+
1885
+ extern int git_path_is_gitfile(const char *path, size_t pathlen, git_path_gitfile gitfile, git_path_fs fs)
1886
+ {
1887
+ const char *file, *hash;
1888
+ size_t filelen;
1889
+
1890
+ if (!(gitfile >= GIT_PATH_GITFILE_GITIGNORE && gitfile < ARRAY_SIZE(gitfiles))) {
1891
+ git_error_set(GIT_ERROR_OS, "invalid gitfile for path validation");
1892
+ return -1;
1893
+ }
1894
+
1895
+ file = gitfiles[gitfile].file;
1896
+ filelen = gitfiles[gitfile].filelen;
1897
+ hash = gitfiles[gitfile].hash;
1898
+
1899
+ switch (fs) {
1900
+ case GIT_PATH_FS_GENERIC:
1901
+ return !verify_dotgit_ntfs_generic(path, pathlen, file, filelen, hash) ||
1902
+ !verify_dotgit_hfs_generic(path, pathlen, file, filelen);
1903
+ case GIT_PATH_FS_NTFS:
1904
+ return !verify_dotgit_ntfs_generic(path, pathlen, file, filelen, hash);
1905
+ case GIT_PATH_FS_HFS:
1906
+ return !verify_dotgit_hfs_generic(path, pathlen, file, filelen);
1907
+ default:
1908
+ git_error_set(GIT_ERROR_OS, "invalid filesystem for path validation");
1909
+ return -1;
1910
+ }
905
1911
  }